M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,297 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <arch/x86.h>
#include <platform/pc.h>
#include <platform/console.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
/* CGA values */
#define CURSOR_START 0x0A
#define CURSOR_END 0x0B
#define VIDEO_ADDRESS_MSB 0x0C
#define VIDEO_ADDRESS_LSB 0x0D
#define CURSOR_POS_MSB 0x0E
#define CURSOR_POS_LSB 0x0F
/* curr settings */
static unsigned char curr_x;
static unsigned char curr_y;
static unsigned char curr_start;
static unsigned char curr_end;
static unsigned char curr_attr;
/* video page buffer */
#define VPAGE_SIZE 2048
#define PAGE_MAX 8
static int active_page = 0;
static int visual_page = 0;
static int curs_x[PAGE_MAX];
static int curs_y[PAGE_MAX];
static struct {
int x1, y1, x2, y2;
} view_window = {
0, 0, 79, 24
};
void platform_init_console(void)
{
curr_save();
window(0, 0, 79, 24);
clear();
place(0, 0);
}
void set_visual_page(int page)
{
unsigned short page_offset = page*VPAGE_SIZE;
visual_page = page;
outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB);
outp(CGA_DATA_REG, page_offset & 0xFF);
outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB);
outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF);
}
void set_active_page(int page)
{
curs_x[active_page] = curr_x;
curs_y[active_page] = curr_y;
curr_x = curs_x[page];
curr_y = curs_y[page];
active_page = page;
}
int get_visual_page(void)
{
return visual_page;
}
int get_active_page(void)
{
return active_page;
}
void place(int x,int y)
{
unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE;
/*
* program CGA using index reg, then data reg
*/
outp(CGA_INDEX_REG, CURSOR_POS_LSB);
outp(CGA_DATA_REG, cursor_word & 0xFF);
outp(CGA_INDEX_REG, CURSOR_POS_MSB);
outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF);
curr_x = x;
curr_y = y;
}
void cursor(int start,int end)
{
outp(CGA_INDEX_REG, CURSOR_START);
outp(CGA_DATA_REG, start);
outp(CGA_INDEX_REG, CURSOR_END);
outp(CGA_DATA_REG, end);
}
void curr_save(void)
{
/* grab some info from the bios data area (these should be defined in memmap.h */
curr_attr = *((unsigned char *)0xB8000 + 159);
curr_x = *((unsigned char *)0x00450);
curr_y = *((unsigned char *)0x00451);
curr_end = *((unsigned char *)0x00460);
curr_start = *((unsigned char *)0x00461);
active_page = visual_page = 0;
}
void curr_restore(void)
{
*((unsigned char *)0x00450) = curr_x;
*((unsigned char *)0x00451) = curr_y;
place(curr_x, curr_y);
cursor(curr_start, curr_end);
}
void window(int x1, int y1, int x2, int y2) {
view_window.x1 = x1;
view_window.y1 = y1;
view_window.x2 = x2;
view_window.y2 = y2;
//place(x1, y1);
}
void _clear(char c,char attr,int x1,int y1,int x2,int y2)
{
register int i,j;
unsigned short w = attr;
w <<= 8; w |= c;
for (i = x1; i <= x2; i++) {
for (j = y1; j <= y2; j++) {
*((unsigned short *)(0xB8000 + 2*i+160*j + 2*active_page*VPAGE_SIZE)) = w;
}
}
place(x1,y1);
curr_y = y1;
curr_x = x1;
}
void clear()
{
_clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2,
view_window.y2);
}
void _scroll(char attr, int x1, int y1, int x2, int y2)
{
register int x,y;
unsigned short xattr = attr << 8,w;
unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE));
for (y = y1+1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
w = *((unsigned short *) (v + 2*(y*80+x)));
*((unsigned short *)(v + 2*((y-1)*80+x))) = w;
}
}
for (x = x1; x <= x2; x++) {
*((unsigned short *)(v + 2*((y-1)*80+x))) = xattr;
}
}
void scroll(void)
{
_scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2,
view_window.y2);
}
void cputc(char c)
{
static unsigned short scan_x, x, y;
unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE));
x = curr_x;
y = curr_y;
switch (c) {
case '\t':
x += 8;
if (x >= view_window.x2+1) {
x = view_window.x1;
if (y == view_window.y2) {
scroll();
} else {
y++;
}
} else {
scan_x = 0;
while ((scan_x+8) < x) {
scan_x += 8;
}
x = scan_x;
}
break;
case '\n':
x = view_window.x1;
if (y == view_window.y2) {
scroll();
} else {
y++;
}
break;
case '\b':
x--;
*(v + 2*(x + y*80)) = ' ';
break;
default:
*(v + 2*(x + y*80)) = c;
x++;
if (x >= view_window.x2+1) {
x = view_window.x1;
if (y == view_window.y2) {
scroll();
} else {
y++;
}
}
}
place(x, y);
}
void cputs(char *s)
{
char c;
while (*s != '\0') {
c = *s++;
cputc(c);
}
}
void puts_xy(int x,int y,char attr,char *s)
{
unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
while (*s != 0) {
*v = *s; s++; v++;
*v = attr; v++;
}
}
void putc_xy(int x, int y, char attr, char c)
{
unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
*v = c; v++;
*v = attr;
}
int printf_xy(int x, int y, char attr, char *fmt, ...)
{
char cbuf[200];
va_list parms;
int result;
va_start(parms, fmt);
result = vsprintf(cbuf, fmt, parms);
va_end(parms);
puts_xy(x, y, attr, cbuf);
return result;
}
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdarg.h>
#include <reg.h>
#include <printf.h>
#include <kernel/thread.h>
#include <arch/x86.h>
#include <platform/pc/memmap.h>
#include <platform/console.h>
#include <platform/keyboard.h>
#include <platform/debug.h>
void _dputc(char c)
{
cputc(c);
}
int dgetc(char *c, bool wait)
{
int ret = platform_read_key(c);
//if (ret < 0)
// arch_idle();
return ret;
}
void debug_dump_regs(void)
{
}
void platform_halt(void)
{
for(;;) {
x86_cli();
x86_hlt();
}
}
void debug_dump_memory_bytes(void *mem, int len)
{
}
void debug_dump_memory_halfwords(void *mem, int len)
{
}
void debug_dump_memory_words(void *mem, int len)
{
}
void debug_set_trace_level(int trace_type, int level)
{
}
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_CONSOLE_H
#define __PLATFORM_CONSOLE_H
#ifdef __cplusplus
extern "C" {
#endif
void platform_init_console(void);
void set_visual_page(int page);
void set_active_page(int page);
int get_visual_page(void);
int get_active_page(void);
void place(int x,int y);
void cursor(int start, int end);
void _clear(char c, char attr, int x1, int y1, int x2, int y2);
void clear(void);
void _scroll(char attr, int x1, int y1, int x2, int y2);
void scroll(void);
void curr_save(void);
void curr_restore(void);
void cputc(char c);
void cputs(char *s);
void window(int x1, int y1, int x2, int y2);
void putc_xy(int x, int y, char attr, char c);
void puts_xy(int x, int y, char attr, char *s);
int printf_xy(int x, int y, char attr, char *fmt, ...) __PRINTFLIKE(4, 5);
#define CURSOR_BLOCK() cursor(0, 15);
#define CURSOR_OFF() cursor(16, 16);
#define CURSOR_STD() cursor(14, 15);
/* text colors */
#define BLACK 0
#define BLUE 1
#define GREEN 2
#define CYAN 3
#define RED 4
#define MAGENTA 5
#define BROWN 6
#define LIGHTGRAY 7
#define DARKGRAY 8
#define LIGHTBLUE 9
#define LIGHTGREEN 10
#define LIGHTCYAN 11
#define LIGHTRED 12
#define LIGHTMAGENTA 13
#define YELLOW 14
#define WHITE 15
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_KEYBOARD_H
#define __PLATFORM_KEYBOARD_H
void platform_init_keyboard(void);
int platform_read_key(char *c);
#endif
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_MULTIBOOT_H
#define __PLATFORM_MULTIBOOT_H
#include <sys/types.h>
/* magic number for multiboot header */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* flags for multiboot header */
#ifdef __ELF__
#define MULTIBOOT_HEADER_FLAGS 0x00000003
#else
#define MULTIBOOT_HEADER_FLAGS 0x00010003
#endif
/* magic number passed by multiboot-compliant boot loaders */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
#ifndef ASSEMBLY
/* multiboot header */
typedef struct multiboot_header
{
uint32_t magic;
uint32_t flags;
uint32_t checksum;
uint32_t header_addr;
uint32_t load_addr;
uint32_t load_end_addr;
uint32_t bss_end_addr;
uint32_t entry_addr;
} multiboot_header_t;
/* symbol table for a.out */
typedef struct aout_symbol_table
{
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
} aout_symbol_table_t;
/* section header table for ELF */
typedef struct elf_section_header_table
{
uint32_t num;
uint32_t size;
uint32_t addr;
uint32_t shndx;
} elf_section_header_table_t;
/* multiboot info */
typedef struct multiboot_info
{
uint32_t flags;
uint32_t mem_lower;
uint32_t mem_upper;
uint32_t boot_device;
uint32_t cmdline;
uint32_t mods_count;
uint32_t mods_addr;
union
{
aout_symbol_table_t aout_sym;
elf_section_header_table_t elf_sec;
} u;
uint32_t mmap_length;
uint32_t mmap_addr;
} multiboot_info_t;
enum {
MB_INFO_MEM_SIZE = 0x001,
MB_INFO_BOOT_DEV = 0x002,
MB_INFO_CMD_LINE = 0x004,
MB_INFO_MODS = 0x008,
MB_INFO_SYMS = 0x010,
MB_INFO_MMAP = 0x020,
MB_INFO_DRIVES = 0x040,
MB_INFO_CONFIG = 0x080,
MB_INFO_BOOT_LOADER = 0x100,
MB_INFO_APM_TABLE = 0x200,
MB_INFO_VBE = 0x400,
};
/* module structure */
typedef struct module
{
uint32_t mod_start;
uint32_t mod_end;
uint32_t string;
uint32_t reserved;
} module_t;
/* memory map - be careful that the offset 0 is base_addr_low without size */
typedef struct memory_map
{
uint32_t size;
uint32_t base_addr_low;
uint32_t base_addr_high;
uint32_t length_low;
uint32_t length_high;
uint32_t type;
} memory_map_t;
/* memory map entry types */
enum {
MB_MMAP_TYPE_AVAILABLE = 0x01,
MB_MMAP_TYPE_RESERVED = 0x02,
MB_MMAP_TYPE_ACPI_RECLAIM = 0x03,
MB_MMAP_TYPE_ACPI_NVS = 0x04,
};
#endif
#endif
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_PC_H
#define __PLATFORM_PC_H
#include <platform/pc/memmap.h>
#include <platform/pc/iomap.h>
/* NOTE: keep arch/x86/crt0.S in sync with these definitions */
/* interrupts */
#define INT_VECTORS 0x31
/* defined interrupts */
#define INT_BASE 0x20
#define INT_PIT 0x20
#define INT_KEYBOARD 0x21
#define INT_PIC2 0x22
#define INT_BASE2 0x28
#define INT_CMOSRTC 0x28
#define INT_PS2MOUSE 0x2c
#define INT_IDE0 0x2e
#define INT_IDE1 0x2f
/* exceptions */
#define INT_DIVIDE_0 0x00
#define INT_DEBUG_EX 0x01
#define INT_INVALID_OP 0x06
#define INT_DEV_NA_EX 0x07
/* faults */
#define INT_STACK_FAULT 0x0c
#define INT_GP_FAULT 0x0d
#define INT_PAGE_FAULT 0x0e
/* APIC vectors */
#define INT_APIC_TIMER 0x22
#define INT_SYSCALL 0x30
/* PIC remap bases */
#define PIC1_BASE 0x20
#define PIC2_BASE 0x28
#endif
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __IOMAP_H
#define __IOMAP_H
/* i8253/i8254 programmable interval timer registers */
#define I8253_CONTROL_REG 0x43
#define I8253_DATA_REG 0x40
/* i8042 keyboard controller registers */
#define I8042_COMMAND_REG 0x64
#define I8042_STATUS_REG 0x64
#define I8042_DATA_REG 0x60
/* CGA registers */
#define CGA_INDEX_REG 0x3D4
#define CGA_DATA_REG 0x3D5
#endif
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __MEMMAP_H
#define __MEMMAP_H
/* some helpful macros */
#define REG(x) ((volatile unsigned int *)(x))
#define REG_H(x) ((volatile unsigned short *)(x))
#define REG_B(x) ((volatile unsigned char *)(x))
/* TODO: put fixed memory address definitions here */
#endif
@@ -0,0 +1,253 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <debug.h>
#include <err.h>
#include <reg.h>
#include <kernel/thread.h>
#include <platform/interrupts.h>
#include <arch/ops.h>
#include <arch/x86.h>
#include "platform_p.h"
#include <platform/pc.h>
void x86_gpf_handler(struct x86_iframe *frame);
void x86_invop_handler(struct x86_iframe *frame);
void x86_unhandled_exception(struct x86_iframe *frame);
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
struct int_handler_struct {
int_handler handler;
void *arg;
};
static struct int_handler_struct int_handler_table[INT_VECTORS];
/*
* Cached IRQ mask (enabled/disabled)
*/
static uint8_t irqMask[2];
/*
* init the PICs and remap them
*/
static void map(uint32_t pic1, uint32_t pic2)
{
/* send ICW1 */
outp(PIC1, ICW1);
outp(PIC2, ICW1);
/* send ICW2 */
outp(PIC1 + 1, pic1); /* remap */
outp(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
outp(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
outp(PIC2 + 1, 2);
/* send ICW4 */
outp(PIC1 + 1, 5);
outp(PIC2 + 1, 1);
/* disable all IRQs */
outp(PIC1 + 1, 0xff);
outp(PIC2 + 1, 0xff);
irqMask[0] = 0xff;
irqMask[1] = 0xff;
}
static void enable(unsigned int vector, bool enable)
{
if (vector >= PIC1_BASE && vector < PIC1_BASE + 8) {
vector -= PIC1_BASE;
uint8_t bit = 1 << vector;
if (enable && (irqMask[0] & bit)) {
irqMask[0] = inp(PIC1 + 1);
irqMask[0] &= ~bit;
outp(PIC1 + 1, irqMask[0]);
irqMask[0] = inp(PIC1 + 1);
} else if (!enable && !(irqMask[0] & bit)) {
irqMask[0] = inp(PIC1 + 1);
irqMask[0] |= bit;
outp(PIC1 + 1, irqMask[0]);
irqMask[0] = inp(PIC1 + 1);
}
} else if (vector >= PIC2_BASE && vector < PIC2_BASE + 8) {
vector -= PIC2_BASE;
uint8_t bit = 1 << vector;
if (enable && (irqMask[1] & bit)) {
irqMask[1] = inp(PIC2 + 1);
irqMask[1] &= ~bit;
outp(PIC2 + 1, irqMask[1]);
irqMask[1] = inp(PIC2 + 1);
} else if (!enable && !(irqMask[1] & bit)) {
irqMask[1] = inp(PIC2 + 1);
irqMask[1] |= bit;
outp(PIC2 + 1, irqMask[1]);
irqMask[1] = inp(PIC2 + 1);
}
bit = 1 << (INT_PIC2 - PIC1_BASE);
if (irqMask[1] != 0xff && (irqMask[0] & bit)) {
irqMask[0] = inp(PIC1 + 1);
irqMask[0] &= ~bit;
outp(PIC1 + 1, irqMask[0]);
irqMask[0] = inp(PIC1 + 1);
} else if (irqMask[1] == 0 && !(irqMask[0] & bit)) {
irqMask[0] = inp(PIC1 + 1);
irqMask[0] |= bit;
outp(PIC1 + 1, irqMask[0]);
irqMask[0] = inp(PIC1 + 1);
}
} else {
//dprintf(DEBUG, "Invalid PIC interrupt: %02x\n", vector);
}
}
void issueEOI(unsigned int vector)
{
if (vector >= PIC1_BASE && vector <= PIC1_BASE + 7) {
outp(PIC1, 0x20);
} else if (vector >= PIC2_BASE && vector <= PIC2_BASE + 7) {
outp(PIC2, 0x20);
outp(PIC1, 0x20); // must issue both for the second PIC
}
}
void platform_init_interrupts(void)
{
// rebase the PIC out of the way of processor exceptions
map(PIC1_BASE, PIC2_BASE);
}
status_t mask_interrupt(unsigned int vector)
{
if (vector >= INT_VECTORS)
return ERR_INVALID_ARGS;
// dprintf(DEBUG, "%s: vector %d\n", __PRETTY_FUNCTION__, vector);
enter_critical_section();
enable(vector, false);
exit_critical_section();
return NO_ERROR;
}
void platform_mask_irqs(void)
{
irqMask[0] = inp(PIC1 + 1);
irqMask[1] = inp(PIC2 + 1);
outp(PIC1 + 1, 0xff);
outp(PIC2 + 1, 0xff);
irqMask[0] = inp(PIC1 + 1);
irqMask[1] = inp(PIC2 + 1);
}
status_t unmask_interrupt(unsigned int vector)
{
if (vector >= INT_VECTORS)
return ERR_INVALID_ARGS;
// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
enter_critical_section();
enable(vector, true);
exit_critical_section();
return NO_ERROR;
}
enum handler_return platform_irq(struct x86_iframe *frame)
{
// get the current vector
unsigned int vector = frame->vector;
#if THREAD_STATS
thread_stats.interrupts++;
#endif
// deliver the interrupt
enum handler_return ret = INT_NO_RESCHEDULE;
switch (vector) {
case INT_GP_FAULT:
x86_gpf_handler(frame);
break;
case INT_INVALID_OP:
x86_invop_handler(frame);
break;
case INT_DIVIDE_0:
case INT_DEBUG_EX:
case INT_DEV_NA_EX:
case INT_PAGE_FAULT:
case INT_STACK_FAULT:
case 3:
x86_unhandled_exception(frame);
break;
default:
if (int_handler_table[vector].handler)
ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
}
// ack the interrupt
issueEOI(vector);
return ret;
}
void register_int_handler(unsigned int vector, int_handler handler, void *arg)
{
if (vector >= INT_VECTORS)
panic("register_int_handler: vector out of range %d\n", vector);
enter_critical_section();
int_handler_table[vector].arg = arg;
int_handler_table[vector].handler = handler;
exit_critical_section();
}
@@ -0,0 +1,341 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <err.h>
#include <reg.h>
#include <debug.h>
#include <kernel/thread.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/console.h>
#include <platform/timer.h>
#include <platform/pc.h>
#include "platform_p.h"
#include <arch/x86.h>
#include <lib/cbuf.h>
static inline int i8042_read_data(void)
{
return inp(I8042_DATA_REG);
}
static inline int i8042_read_status(void)
{
return inp(I8042_STATUS_REG);
}
static inline void i8042_write_data(int val)
{
outp(I8042_DATA_REG, val);
}
static inline void i8042_write_command(int val)
{
outp(I8042_COMMAND_REG, val);
}
/*
* timeout in milliseconds
*/
#define I8042_CTL_TIMEOUT 500
/*
* status register bits
*/
#define I8042_STR_PARITY 0x80
#define I8042_STR_TIMEOUT 0x40
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_MUXERR 0x04
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
/*
* control register bits
*/
#define I8042_CTR_KBDINT 0x01
#define I8042_CTR_AUXINT 0x02
#define I8042_CTR_IGNKEYLK 0x08
#define I8042_CTR_KBDDIS 0x10
#define I8042_CTR_AUXDIS 0x20
#define I8042_CTR_XLATE 0x40
/*
* commands
*/
#define I8042_CMD_CTL_RCTR 0x0120
#define I8042_CMD_CTL_WCTR 0x1060
#define I8042_CMD_CTL_TEST 0x01aa
#define I8042_CMD_KBD_DIS 0x00ad
#define I8042_CMD_KBD_EN 0x00ae
#define I8042_CMD_KBD_TEST 0x01ab
#define I8042_CMD_KBD_MODE 0x01f0
/*
* used for flushing buffers. the i8042 internal buffer shoudn't exceed this.
*/
#define I8042_BUFFER_LENGTH 32
static inline void delay(time_t delay) {
bigtime_t start = current_time();
while (start + delay > current_time());
}
/* scancodes we want to do something with that don't translate via table */
#define SCANCODE_LSHIFT 0x2a
#define SCANCODE_RSHIFT 0x36
/* scancode translation tables */
static const int KeyCodeSingleLower[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
-1, -1, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', // 0
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\n', -1, 'a', 's', // 1
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`', -1,'\\', 'z', 'x', 'c', 'v', // 2
'b', 'n', 'm', ',', '.', '/', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
};
static const int KeyCodeMultiLower[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
};
static const int KeyCodeSingleUpper[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
-1, -1, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', // 0
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\n', -1, 'A', 'S', // 1
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', -1, '|', 'Z', 'X', 'C', 'V', // 2
'B', 'N', 'M', '<', '>', '?', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
};
static const int KeyCodeMultiUpper[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
};
/*
* state key flags
*/
static bool key_lshift;
static bool key_rshift;
static cbuf_t key_buf;
static void i8042_process_scode(uint8_t scode, unsigned int flags)
{
static int lastCode = 0;
int keyCode;
uint8_t keyUpBit;
bool multi = lastCode == 0xe0;
// save the key up event bit
keyUpBit = scode & 0x80;
scode &= 0x7f;
if (scode == SCANCODE_LSHIFT) {
key_lshift = !keyUpBit;
}
if (scode == SCANCODE_RSHIFT) {
key_rshift = !keyUpBit;
}
if (key_lshift || key_rshift) {
keyCode = multi ? KeyCodeMultiUpper[scode] : KeyCodeSingleUpper[scode];
} else {
keyCode = multi ? KeyCodeMultiLower[scode] : KeyCodeSingleLower[scode];
}
/*printf_xy(71, 3, BLUE, "%02x%02x %c %c%c", multi ? lastCode : 0, scode,
keyCode != -1 ? (char) keyCode : ' ', key_lshift ? 'L' : ' ',
key_rshift ? 'R' : ' ');*/
if (keyCode != -1 && !keyUpBit) {
char c = (char) keyCode;
cbuf_write(&key_buf, &c, 1, false);
}
// update the last received code
lastCode = scode;
}
static int i8042_wait_read(void)
{
int i = 0;
while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
delay(1);
i++;
}
return -(i == I8042_CTL_TIMEOUT);
}
static int i8042_wait_write(void)
{
int i = 0;
while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
delay(1);
i++;
}
return -(i == I8042_CTL_TIMEOUT);
}
static int i8042_flush(void)
{
unsigned char data;
int i = 0;
//enter_critical_section();
while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_LENGTH)) {
delay(1);
data = i8042_read_data();
}
//exit_critical_section();
return i;
}
static int i8042_command(uint8_t *param, int command)
{
int retval = 0, i = 0;
//enter_critical_section();
retval = i8042_wait_write();
if (!retval) {
i8042_write_command(command & 0xff);
}
if (!retval) {
for (i = 0; i < ((command >> 12) & 0xf); i++) {
if ((retval = i8042_wait_write())) {
break;
}
i8042_write_data(param[i]);
}
}
if (!retval) {
for (i = 0; i < ((command & 0xf0) >> 8); i++) {
if ((retval = i8042_wait_read())) {
break;
}
if (i8042_read_status() & I8042_STR_AUXDATA) {
param[i] = ~i8042_read_data();
} else {
param[i] = i8042_read_data();
}
}
}
//exit_critical_section();
return retval;
}
static enum handler_return i8042_interrupt(void *arg)
{
uint8_t str, data = 0;
//enter_critical_section();
str = i8042_read_status();
if (str & I8042_STR_OBF) {
data = i8042_read_data();
}
//exit_critical_section();
if (str & I8042_STR_OBF) {
i8042_process_scode(data,
((str & I8042_STR_PARITY) ? I8042_STR_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? I8042_STR_TIMEOUT : 0));
}
return INT_NO_RESCHEDULE;
}
int platform_read_key(char *c)
{
ssize_t len;
len = cbuf_read(&key_buf, c, 1, true);
return len;
}
void platform_init_keyboard(void)
{
uint8_t ctr;
cbuf_initialize(&key_buf, 32);
i8042_flush();
if (i8042_command(&ctr, I8042_CMD_CTL_RCTR)) {
dprintf(DEBUG, "Failed to read CTR while initializing i8042\n");
return;
}
// turn on translation
ctr |= I8042_CTR_XLATE;
// enable keyboard and keyboard irq
ctr &= ~I8042_CTR_KBDDIS;
ctr |= I8042_CTR_KBDINT;
if (i8042_command(&ctr, I8042_CMD_CTL_WCTR)) {
dprintf(DEBUG, "Failed to write CTR while initializing i8042\n");
return;
}
register_int_handler(INT_KEYBOARD, &i8042_interrupt, NULL);
unmask_interrupt(INT_KEYBOARD);
i8042_interrupt(NULL);
}
+576
View File
@@ -0,0 +1,576 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <kernel/thread.h>
#include <arch/x86/descriptor.h>
#include <dev/pci.h>
static int last_bus = 0;
typedef struct {
uint16_t size;
void *offset;
uint16_t selector;
} __PACKED irq_routing_options_t;
static int pci_type1_detect(void);
static int pci_bios_detect(void);
int pci_get_last_bus(void)
{
return last_bus;
}
/*
* pointers to installed PCI routines
*/
int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index);
int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value);
int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value);
int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value);
int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value);
int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value);
int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value);
int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs);
int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
{
enter_critical_section();
int res = g_pci_find_pci_device(state, device_id, vendor_id, index);
exit_critical_section();
return res;
}
int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
{
enter_critical_section();
int res = g_pci_find_pci_class_code(state, class_code, index);
exit_critical_section();
return res;
}
int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
{
enter_critical_section();
int res = g_pci_read_config_byte(state, reg, value);
exit_critical_section();
return res;
}
int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
{
enter_critical_section();
int res = g_pci_read_config_half(state, reg, value);
exit_critical_section();
return res;
}
int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
{
enter_critical_section();
int res = g_pci_read_config_word(state, reg, value);
exit_critical_section();
return res;
}
int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
{
enter_critical_section();
int res = g_pci_write_config_byte(state, reg, value);
exit_critical_section();
return res;
}
int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
{
enter_critical_section();
int res = g_pci_write_config_half(state, reg, value);
exit_critical_section();
return res;
}
int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
{
enter_critical_section();
int res = g_pci_write_config_word(state, reg, value);
exit_critical_section();
return res;
}
int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs)
{
enter_critical_section();
irq_routing_options_t options;
options.size = sizeof(irq_routing_entry) * *count;
options.selector = DATA_SELECTOR;
options.offset = entries;
int res = g_pci_get_irq_routing_options(&options, pci_irqs);
*count = options.size / sizeof(irq_routing_entry);
exit_critical_section();
return res;
}
int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
{
enter_critical_section();
int res = g_pci_set_irq_hw_int(state, int_pin, irq);
exit_critical_section();
return res;
}
void pci_init(void)
{
if (!pci_bios_detect()) {
dprintf(INFO, "pci bios functions installed\n");
dprintf(INFO, "last pci bus is %d\n", last_bus);
}
}
#define PCIBIOS_PRESENT 0xB101
#define PCIBIOS_FIND_PCI_DEVICE 0xB102
#define PCIBIOS_FIND_PCI_CLASS_CODE 0xB103
#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xB106
#define PCIBIOS_READ_CONFIG_BYTE 0xB108
#define PCIBIOS_READ_CONFIG_WORD 0xB109
#define PCIBIOS_READ_CONFIG_DWORD 0xB10A
#define PCIBIOS_WRITE_CONFIG_BYTE 0xB10B
#define PCIBIOS_WRITE_CONFIG_WORD 0xB10C
#define PCIBIOS_WRITE_CONFIG_DWORD 0xB10D
#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E
#define PCIBIOS_PCI_SET_IRQ_HW_INT 0xB10F
#define PCIBIOS_SUCCESSFUL 0x00
#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
#define PCIBIOS_BAD_VENDOR_ID 0x83
#define PCIBIOS_DEVICE_NOT_FOUND 0x86
#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
#define PCIBIOS_SET_FAILED 0x88
#define PCIBIOS_BUFFER_TOO_SMALL 0x89
/*
* far call structure used by BIOS32 routines
*/
static struct {
uint32_t offset;
uint16_t selector;
} __PACKED bios32_entry;
/*
* BIOS32 entry header
*/
typedef struct {
uint8_t magic[4]; // "_32_"
void * entry; // entry point
uint8_t revision;
uint8_t length;
uint8_t checksum;
uint8_t reserved[5];
} __PACKED pci_bios_info;
/*
* scan for pci bios
*/
static const char * pci_bios_magic = "_32_";
static pci_bios_info *find_pci_bios_info(void) {
uint32_t *head = (uint32_t *) 0x000e0000;
int8_t sum, *b;
uint i;
while (head < (uint32_t *) 0x000ffff0) {
if (*head == *(uint32_t *) pci_bios_magic) {
// perform the checksum
sum = 0;
b = (int8_t *) head;
for (i=0; i < sizeof(pci_bios_info); i++) {
sum += b[i];
}
if (sum == 0) {
return (pci_bios_info *) head;
}
}
head += 4;
}
return NULL;
}
/*
* local BIOS32 PCI routines
*/
static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
{
uint32_t bx, ret;
__asm__(
"lcall *(%%edi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=b"(bx),
"=a"(ret)
: "1"(PCIBIOS_FIND_PCI_DEVICE),
"c"(device_id),
"d"(vendor_id),
"S"(index),
"D"(&bios32_entry));
state->bus = bx >> 8;
state->dev_fn = bx & 0xFF;
ret >>= 8;
return ret & 0xFF;
}
static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
{
uint32_t bx, ret;
__asm__(
"lcall *(%%edi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=b"(bx),
"=a"(ret)
: "1"(PCIBIOS_FIND_PCI_CLASS_CODE),
"c"(class_code),
"S"(index),
"D"(&bios32_entry));
state->bus = bx >> 8;
state->dev_fn = bx & 0xFF;
ret >>= 8;
return ret & 0xFF;
}
static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=c"(*value),
"=a"(ret)
: "1"(PCIBIOS_READ_CONFIG_BYTE),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=c"(*value),
"=a"(ret)
: "1"(PCIBIOS_READ_CONFIG_WORD),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=c"(*value),
"=a"(ret)
: "1"(PCIBIOS_READ_CONFIG_DWORD),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(ret)
: "0"(PCIBIOS_WRITE_CONFIG_BYTE),
"c"(value),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(ret)
: "0"(PCIBIOS_WRITE_CONFIG_WORD),
"c"(value),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
{
uint32_t bx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(ret)
: "0"(PCIBIOS_WRITE_CONFIG_DWORD),
"c"(value),
"b"(bx),
"D"(reg),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs)
{
uint32_t ret;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=b"(*pciIrqs),
"=a"(ret)
: "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS),
"b"(0),
"D"(route_buffer),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xff;
}
static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
{
uint32_t bx, cx, ret;
bx = state->bus;
bx <<= 8;
bx |= state->dev_fn;
cx = irq;
cx <<= 8;
cx |= int_pin;
__asm__(
"lcall *(%%esi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(ret)
: "0"(PCIBIOS_PCI_SET_IRQ_HW_INT),
"b"(bx),
"c"(cx),
"S"(&bios32_entry));
ret >>= 8;
return ret & 0xFF;
}
static const char *pci_signature = "PCI ";
static int pci_bios_detect(void) {
pci_bios_info * pci = find_pci_bios_info();
if (pci != NULL) {
/*printf("Found PCI structure at %08x\n", (uint32_t) pci);
printf("\nPCI header info:\n");
printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
pci->magic[3]);
printf("%08x\n", (uint32_t) pci->entry);
printf("%d\n", pci->length * 16);
printf("%d\n", pci->checksum);*/
uint32_t adr, temp, len;
uint8_t err;
bios32_entry.offset = (uint32_t) pci->entry;
bios32_entry.selector = CODE_SELECTOR;
__asm__(
"lcall *(%%edi)"
: "=a"(err), /* AL out=status */
"=b"(adr), /* EBX out=code segment base adr */
"=c"(len), /* ECX out=code segment size */
"=d"(temp) /* EDX out=entry pt offset in code */
: "0"(0x49435024),/* EAX in=service="$PCI" */
"1"(0), /* EBX in=0=get service entry pt */
"D"(&bios32_entry)
);
if (err == 0x80) {
dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
return -1;
}
if (err != 0) {
dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
return -1;
}
bios32_entry.offset = adr + temp;
// now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
uint16_t present, version, busses;
uint32_t signature;
__asm__(
"lcall *(%%edi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(present),
"=b"(version),
"=c"(busses),
"=d"(signature)
: "0"(PCIBIOS_PRESENT),
"D"(&bios32_entry)
);
if (present & 0xff00) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
return -1;
}
if (signature != *(uint32_t *)pci_signature) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
return -1;
}
//dprintf(DEBUG, "busses=%04x\n", busses);
last_bus = busses & 0xff;
g_pci_find_pci_device = bios_find_pci_device;
g_pci_find_pci_class_code = bios_find_pci_class_code;
g_pci_read_config_word = bios_read_config_word;
g_pci_read_config_half = bios_read_config_half;
g_pci_read_config_byte = bios_read_config_byte;
g_pci_write_config_word = bios_write_config_word;
g_pci_write_config_half = bios_write_config_half;
g_pci_write_config_byte = bios_write_config_byte;
g_pci_get_irq_routing_options = bios_get_irq_routing_options;
g_pci_set_irq_hw_int = bios_set_irq_hw_int;
return 0;
}
return -1;
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <err.h>
#include <debug.h>
#include <arch/x86/mmu.h>
#include <platform.h>
#include "platform_p.h"
#include <platform/pc.h>
#include <platform/multiboot.h>
#include <platform/console.h>
#include <platform/keyboard.h>
#include <dev/pci.h>
extern multiboot_info_t *_multiboot_info;
extern unsigned int _heap_end;
void platform_init_mmu_mappings(void)
{
/* do some memory map initialization */
}
void platform_init_multiboot_info(void)
{
unsigned int i;
if (_multiboot_info) {
if (_multiboot_info->flags & MB_INFO_MEM_SIZE) {
_heap_end = _multiboot_info->mem_upper * 1024;
}
if (_multiboot_info->flags & MB_INFO_MMAP) {
memory_map_t *mmap = (memory_map_t *) (_multiboot_info->mmap_addr - 4);
dprintf(DEBUG, "mmap length: %u\n", _multiboot_info->mmap_length);
for (i=0; i < _multiboot_info->mmap_length / sizeof(memory_map_t); i++) {
dprintf(DEBUG, "base=%08x, length=%08x, type=%02x\n",
mmap[i].base_addr_low, mmap[i].length_low, mmap[i].type);
if (mmap[i].type == MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
_heap_end = mmap[i].base_addr_low + mmap[i].length_low;
} else if (mmap[i].type != MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
/*
* break on first memory hole above default heap end for now.
* later we can add facilities for adding free chunks to the
* heap for each segregated memory region.
*/
break;
}
}
}
}
}
void platform_early_init(void)
{
/* update the heap end so we can take advantage of more ram */
platform_init_multiboot_info();
/* get the text console working */
platform_init_console();
/* initialize the interrupt controller */
platform_init_interrupts();
/* initialize the timer */
platform_init_timer();
}
void platform_init(void)
{
platform_init_keyboard();
pci_init();
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_P_H
#define __PLATFORM_P_H
void platform_init_interrupts(void);
void platform_init_timer(void);
#endif
@@ -0,0 +1,23 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
ARCH := x86
CPU := generic
MODULES += \
lib/cbuf
INCLUDES += \
-I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/interrupts.o \
$(LOCAL_DIR)/platform.o \
$(LOCAL_DIR)/timer.o \
$(LOCAL_DIR)/debug.o \
$(LOCAL_DIR)/console.o \
$(LOCAL_DIR)/keyboard.o \
$(LOCAL_DIR)/pci.o
LINKER_SCRIPT += \
$(BUILDDIR)/kernel.ld
+166
View File
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <err.h>
#include <reg.h>
#include <debug.h>
#include <kernel/thread.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/console.h>
#include <platform/timer.h>
#include <platform/pc.h>
#include "platform_p.h"
#include <arch/x86.h>
static platform_timer_callback t_callback;
static void *callback_arg;
static uint64_t next_trigger_time;
static uint64_t next_trigger_delta;
static uint64_t timer_delta_time;
static uint64_t timer_current_time;
static uint16_t divisor;
#define INTERNAL_FREQ 1193182ULL
#define INTERNAL_FREQ_3X 3579546ULL
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, time_t interval)
{
enter_critical_section();
t_callback = callback;
callback_arg = arg;
next_trigger_delta = (uint64_t) interval << 32;
next_trigger_time = timer_current_time + next_trigger_delta;
exit_critical_section();
return NO_ERROR;
}
time_t current_time(void)
{
time_t time;
enter_critical_section();
time = (time_t) (timer_current_time >> 32);
exit_critical_section();
return time;
}
bigtime_t current_time_hires(void)
{
bigtime_t time;
enter_critical_section();
time = (bigtime_t) ((timer_current_time >> 22) * 1000) >> 10;
exit_critical_section();
return time;
}
static enum handler_return os_timer_tick(void *arg)
{
uint64_t delta;
timer_current_time += timer_delta_time;
time_t time = current_time();
//bigtime_t btime = current_time_hires();
//printf_xy(71, 0, WHITE, "%08u", (uint32_t) time);
//printf_xy(63, 1, WHITE, "%016llu", (uint64_t) btime);
if (t_callback && timer_current_time >= next_trigger_time) {
delta = timer_current_time - next_trigger_time;
next_trigger_time = timer_current_time + next_trigger_delta - delta;
return t_callback(callback_arg, time);
} else {
return INT_NO_RESCHEDULE;
}
}
static void set_pit_frequency(uint32_t frequency)
{
uint32_t count, remainder;
/* figure out the correct divisor for the desired frequency */
if (frequency <= 18) {
count = 0xffff;
} else if (frequency >= INTERNAL_FREQ) {
count = 1;
} else {
count = INTERNAL_FREQ_3X / frequency;
remainder = INTERNAL_FREQ_3X % frequency;
if (remainder >= INTERNAL_FREQ_3X / 2) {
count += 1;
}
count /= 3;
remainder = count % 3;
if (remainder >= 1) {
count += 1;
}
}
divisor = count & 0xffff;
/*
* funky math that i don't feel like explaining. essentially 32.32 fixed
* point representation of the configured timer delta.
*/
timer_delta_time = (3685982306ULL * count) >> 10;
//dprintf(DEBUG, "set_pit_frequency: dt=%016llx\n", timer_delta_time);
//dprintf(DEBUG, "set_pit_frequency: divisor=%04x\n", divisor);
/*
* setup the Programmable Interval Timer
* timer 0, mode 2, binary counter, LSB followed by MSB
*/
outp(I8253_CONTROL_REG, 0x34);
outp(I8253_DATA_REG, divisor & 0xff); // LSB
outp(I8253_DATA_REG, divisor >> 8); // MSB
}
void platform_init_timer(void)
{
timer_current_time = 0;
set_pit_frequency(1000); // ~1ms granularity
register_int_handler(INT_PIT, &os_timer_tick, NULL);
unmask_interrupt(INT_PIT);
}
void platform_halt_timers(void)
{
mask_interrupt(INT_PIT);
}