diff options
| author | Franklin Wei <frankhwei536@gmail.com> | 2015-03-01 14:20:47 -0500 |
|---|---|---|
| committer | Franklin Wei <frankhwei536@gmail.com> | 2015-03-01 14:20:47 -0500 |
| commit | c7252588ebb95f97631e9470778c69afa00c35b5 (patch) | |
| tree | 06d760878e18f6cddbe4305cddd4d5dfa74529f8 /arch | |
| parent | b8f54e63d2b8f8007c580adf2a6034c98a0f2eaa (diff) | |
| download | kappa-c7252588ebb95f97631e9470778c69afa00c35b5.zip kappa-c7252588ebb95f97631e9470778c69afa00c35b5.tar.gz kappa-c7252588ebb95f97631e9470778c69afa00c35b5.tar.bz2 kappa-c7252588ebb95f97631e9470778c69afa00c35b5.tar.xz | |
Huge restructure
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/i686/boot/head.S | 41 | ||||
| -rw-r--r-- | arch/i686/drivers/gfx-as.S | 101 | ||||
| -rw-r--r-- | arch/i686/drivers/gfx.c | 540 | ||||
| -rw-r--r-- | arch/i686/drivers/pcspkr.c | 19 | ||||
| -rw-r--r-- | arch/i686/drivers/ps2kbd.c | 212 | ||||
| -rw-r--r-- | arch/i686/drivers/vgatext.c | 124 | ||||
| -rw-r--r-- | arch/i686/fpu.c | 25 | ||||
| -rw-r--r-- | arch/i686/gdt-as.S | 14 | ||||
| -rw-r--r-- | arch/i686/gdt.c | 34 | ||||
| -rw-r--r-- | arch/i686/idt-as.S | 6 | ||||
| -rw-r--r-- | arch/i686/idt.c | 24 | ||||
| -rw-r--r-- | arch/i686/irq-as.S | 146 | ||||
| -rw-r--r-- | arch/i686/irq.c | 73 | ||||
| -rw-r--r-- | arch/i686/isr-as.S | 214 | ||||
| -rw-r--r-- | arch/i686/isr.c | 60 | ||||
| -rw-r--r-- | arch/i686/linker.ld | 45 | ||||
| -rw-r--r-- | arch/i686/paging-as.S | 9 | ||||
| -rw-r--r-- | arch/i686/paging.c | 64 |
18 files changed, 1751 insertions, 0 deletions
diff --git a/arch/i686/boot/head.S b/arch/i686/boot/head.S new file mode 100644 index 0000000..9118c20 --- /dev/null +++ b/arch/i686/boot/head.S @@ -0,0 +1,41 @@ + .set ALIGN, 1<<0 + .set MEMINFO, 1<<1 + .set GFXMODE, 1<<2 # this flag enables the graphics fields + .set FLAGS, ALIGN | MEMINFO | GFXMODE + .set MAGIC, 0x1BADB002 # multiboot magic + .set CHECKSUM, -(MAGIC + FLAGS) + +.section .multiboot + .align 4 +multiboot_header: + .long MAGIC + .long FLAGS + .long CHECKSUM + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 # 1=text mode, 0=graphics mode + .long 0 # screen width (don't care) + .long 0 # screen height (don't care) + .long 32 # screen BPP: MUST be 32 + +.section .stack +stack_bottom: # Stack grows up in addresses, so bottom is + # lower in memory than the top + .skip 32768 # 32KB stack +stack_top: + +.section .text + .global _start +_start: + cli + movl $stack_top, %esp + push %eax # multiboot magic + push %ebx # multiboot header + call main +.Lhang: # Idle + cli + hlt + jmp .Lhang diff --git a/arch/i686/drivers/gfx-as.S b/arch/i686/drivers/gfx-as.S new file mode 100644 index 0000000..a58fa12 --- /dev/null +++ b/arch/i686/drivers/gfx-as.S @@ -0,0 +1,101 @@ + .extern fb_width + .extern fb_height + .extern fb_stride + .extern fb_bpp + .extern _gfx_fgcol + .extern _gfx_bgcol + .extern framebuffer + + .global gfx_clear_packed +gfx_clear_packed: + movl framebuffer, %eax + movzwl fb_stride, %ecx + movzwl fb_height, %edx + imull %ecx, %edx + addl %eax, %edx + pushl %ebx + movzwl fb_bpp, %ebx + movl _gfx_bgcol, %ecx +.L1: + movl %ecx, (%eax) + addl %ebx, %eax + cmpl %eax, %edx + ja .L1 +.L2: + popl %ebx + ret + + .global gfx_hline_fast + +gfx_hline_fast: + int $0x80 + pushl %ebx + movl 8(%esp), %eax + movl 12(%esp), %ecx + cmpl %eax, %ecx + jge .L3 + xchgl %eax, %ecx +.L3: + movzwl fb_stride, %edx + movzbl fb_bpp, %ebx + imull 16(%esp), %edx + addl framebuffer, %edx + imull %ebx, %ecx + imull %ebx, %eax + addl %edx, %eax + addl %ecx, %edx + movl _gfx_fgcol, %ecx + cmpl %edx, %eax + jnb .L5 +.L4: + movl %ecx, (%eax) + addl %ebx, %eax + cmpl %eax, %edx + ja .L4 +.L5: + popl %ebx + ret + + .global gfx_vline_fast + +gfx_vline_fast: + pushl %esi + pushl %ebx + movl 12(%esp), %eax + movl 16(%esp), %edx + cmpl %eax, %edx + jge .L6 + xchgl %eax, %edx +.L6: + movzwl fb_stride, %ebx + movzbl fb_bpp, %ecx + imull 20(%esp), %ecx + movl framebuffer, %esi + imull %ebx, %edx + imull %ebx, %eax + addl %ecx, %eax + addl %edx, %ecx + leal (%esi,%ecx), %edx + addl %esi, %eax + movl _gfx_fgcol, %ecx + cmpl %edx, %eax + jnb .L8 +.L7: + movl %ecx, (%eax) + addl %ebx, %eax + cmpl %eax, %edx + ja .L7 +.L8: + popl %ebx + popl %esi + ret + + .global gfx_drawpixel_32bpp +gfx_drawpixel_32bpp: + movzwl fb_stride32, %eax + movl framebuffer, %edx + imull 8(%esp), %eax + movl _gfx_fgcol, %ecx + addl 4(%esp), %eax + movl %ecx, (%edx,%eax,4) + ret diff --git a/arch/i686/drivers/gfx.c b/arch/i686/drivers/gfx.c new file mode 100644 index 0000000..2f4864b --- /dev/null +++ b/arch/i686/drivers/gfx.c @@ -0,0 +1,540 @@ +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gfx_font.h" +#include "log.h" +#include "multiboot.h" +#include "paging.h" +#include "panic.h" +#include "gfx.h" + +uint8_t *real_framebuffer = NULL; +uint8_t *temp_framebuffer = NULL; +uint8_t *framebuffer = NULL; +bool double_buffer = false; +uint16_t fb_width; +uint16_t fb_height; + +/* this is BYTES per pixel */ +uint8_t fb_bpp; +uint16_t fb_stride; +/* fb_stride / 4 */ +uint16_t fb_stride32; +const uint8_t *gfx_bpp = &fb_bpp; + +const uint16_t *gfx_width = &fb_width; +const uint16_t *gfx_height = &fb_height; + +static int cursor_x, cursor_y; +uint32_t _gfx_fgcol, _gfx_bgcol; + +void (*gfx_clear)(void); +void (*gfx_drawpixel)(int x, int y); +void (*gfx_hline)(int x1, int x2, int y); +void (*gfx_vline)(int y1, int y2, int x); + +void gfx_set_background(uint32_t col) +{ + _gfx_bgcol = col; +} + +uint32_t gfx_get_background(void) +{ + return _gfx_bgcol; +} + +void gfx_set_foreground(uint32_t col) +{ + _gfx_fgcol = col; +} + +uint32_t gfx_get_foreground(void) +{ + return _gfx_fgcol; +} + +/* assembly */ +void gfx_drawpixel_32bpp_checked(int x, int y) +{ + if(0 <= x && x < fb_width && + 0 <= y && y < fb_height) + ((uint32_t*)framebuffer)[y * fb_stride32 + x] = _gfx_fgcol; + else + panic("pixel OOB!\n"); +} + +/* implemented in assembly now */ +/* +void gfx_clear(uint32_t col) +{ + uint8_t *p = framebuffer; + uint8_t *stop = framebuffer + fb_width * fb_height * fb_bpp; + while(p < stop) + { + *(uint32_t*)p = col; + p += fb_bpp; + } +} +*/ + +void gfx_clear_unpacked(void) +{ + uint8_t *fb = framebuffer; + const uint32_t bg = _gfx_bgcol; + + const uint16_t padding = fb_stride - (fb_bpp * fb_width); + + for(int y = 0; y < fb_height; ++y) + { + for(int x = 0; x < fb_width; ++x) + { + *(uint32_t*)fb++ = bg; + } + fb += padding; + } +} + +void gfx_reset(void) +{ + _gfx_fgcol = VGA_RGBPACK(0xff, 0xff, 0xff); + _gfx_bgcol = VGA_RGBPACK(0, 0, 0); + gfx_clear(); + cursor_y = 0; + cursor_x = 0; +} + +void gfx_drawchar(int x, int y, int c) +{ + uint8_t *line_addr = framebuffer + (x * fb_bpp) + (y * fb_stride); + const uint32_t fg = _gfx_fgcol; + const uint16_t stride = fb_stride; + const uint8_t stop_y = MIN(FONT_HEIGHT, fb_height - y); + const uint8_t stop_x = MIN(FONT_WIDTH, fb_width - x); + if(c < 0 || c > 132) + return; + for(int i = 0; i < stop_y; ++i) + { + uint8_t mask_table[8] = {128, 64, 32, 16, 8, 4, 2, 1}; + for(int j = 0; j < stop_x; ++j) + { + if(gfx_font[c][i] & mask_table[j]) + ((uint32_t*)line_addr)[j] = fg; + } + line_addr += stride; + } +} + +void gfx_drawchar_bg(int x, int y, int c) +{ + uint8_t *line_addr = framebuffer + (x * fb_bpp) + (y * fb_stride); + const uint32_t fg = _gfx_fgcol; + const uint16_t stride = fb_stride; + const uint8_t stop_y = MIN(FONT_HEIGHT, fb_height - y); + const uint8_t stop_x = MIN(FONT_WIDTH, fb_width - x); + if(c < 0 || c > 132) + return; + for(int i = 0; i < stop_y; ++i) + { + uint8_t mask_table[8] = {128, 64, 32, 16, 8, 4, 2, 1}; + for(int j = 0; j < stop_x; ++j) + { + if(gfx_font[c][i] & mask_table[j]) + ((uint32_t*)line_addr)[j] = fg; + else + ((uint32_t*)line_addr)[j] = _gfx_bgcol; + } + line_addr += stride; + } +} + +void gfx_putchar(int ch) +{ + if(ch != '\n' && ch != '\b') + { + gfx_drawchar(cursor_x, cursor_y, ch); + cursor_x += FONT_WIDTH; + if(cursor_x >= fb_width) + { + cursor_x = 0; + cursor_y += FONT_HEIGHT; + if(cursor_y >= fb_height) + { + gfx_clear(); + cursor_y = 0; + } + } + } + else if(ch == '\n') + { + cursor_x = 0; + cursor_y += FONT_HEIGHT; + if(cursor_y >= fb_height) + { + gfx_clear(); + cursor_y = 0; + } + } + else if(ch == '\b') + { + int temp_x = cursor_x - FONT_WIDTH; + if(temp_x >= 0) + cursor_x = temp_x; + gfx_drawchar_bg(cursor_x, cursor_y, ' '); + } +} + +void gfx_puts(const char* str) +{ + while(*str) + { + gfx_putchar(*str++); + } +} + +/* implemented in assembly now */ +void gfx_hline_checked(int x1, int x2, int y) +{ + /* make sure x1 is to the left of x2 */ + if(x2 < x1) + { + int temp = x1; + x1 = x2; + x2 = temp; + } + + x1 = MAX(0, x1); + x2 = MIN(x2, fb_width); + + if(0 <= y && y < fb_height) + { + + uint8_t *base = framebuffer + y * fb_stride; + + uint8_t *dest = base + x1 * fb_bpp; + uint8_t *stop = base + x2 * fb_bpp; + const uint32_t col = _gfx_fgcol; + while(dest < stop) + { + *(uint32_t*)dest = col; + dest += fb_bpp; + } + } +} + +void gfx_vline_checked(int y1, int y2, int x) +{ + /* make sure y1 is above y2 */ + if(y2 < y1) + { + int temp = y1; + y1 = y2; + y2 = temp; + } + + y1 = MAX(0, y1); + y2 = MIN(y2, fb_height); + + if(0 <= x && x < fb_width) + { + uint8_t *dest = framebuffer + y1 * fb_stride + x * fb_bpp; + uint8_t *stop = framebuffer + y2 * fb_stride + x * fb_bpp; + const uint32_t col = _gfx_fgcol; + const uint16_t stride = fb_stride; + while(dest < stop) + { + *(uint32_t*)dest = col; + dest += stride; + } + } +} + +void gfx_fillrect(int x, int y, int w, int h) +{ + for(int i = 0; i < h; ++i) + { + gfx_hline(x, x + w, y + i); + } +} + +void gfx_drawline(int x1, int y1, int x2, int y2) +{ + int dx = abs(x2 - x1); + int sx = x1 < x2 ? 1 : -1; + int dy = -abs(y2 - y1); + int sy = y1 < y2 ? 1 : -1; + int err = dx + dy; + int e2; /* error value e_xy */ + + while(1) + { + gfx_drawpixel(x1, y1); + if (x1 == x2 && y1 == y2) + break; + e2 = err << 1; + if (e2 >= dy) + { + err += dy; + x1 += sx; + } + if (e2 <= dx) + { + err += dx; + y1 += sy; + } + } +} + +void gfx_drawcircle(int cx, int cy, int r) +{ + int d = 3 - (r * 2); + int x = 0; + int y = r; + while(x <= y) + { + gfx_drawpixel(cx + x, cy + y); + gfx_drawpixel(cx - x, cy + y); + gfx_drawpixel(cx + x, cy - y); + gfx_drawpixel(cx - x, cy - y); + gfx_drawpixel(cx + y, cy + x); + gfx_drawpixel(cx - y, cy + x); + gfx_drawpixel(cx + y, cy - x); + gfx_drawpixel(cx - y, cy - x); + if(d < 0) + { + d += (x * 4) + 6; + } + else + { + d += ((x - y) * 4) + 10; + --y; + } + ++x; + } +} + +void gfx_fillcircle(int cx, int cy, int r) +{ + int d = 3 - (r * 2); + int x = 0; + int y = r; + while(x <= y) + { + gfx_hline(cx - x, cx + x, cy + y); + gfx_hline(cx - x, cx + x, cy - y); + gfx_hline(cx - y, cx + y, cy + x); + gfx_hline(cx - y, cx + y, cy - x); + if(d < 0) + { + d += (x * 4) + 6; + } + else + { + d += ((x - y) * 4) + 10; + --y; + } + ++x; + } +} + +/* these next two functions were taken directly from the Rockbox project's XLCD + * library. + * Copyright (C) 2005 Jens Arnold */ + +/* sort the given coordinates by increasing x value */ +static void sort_points_by_increasing_y(int* y1, int* x1, + int* y2, int* x2, + int* y3, int* x3) +{ + int x, y; + if (*x1 > *x3) + { + if (*x2 < *x3) /* x2 < x3 < x1 */ + { + x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x; + y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y; + } + else if (*x2 > *x1) /* x3 < x1 < x2 */ + { + x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x; + y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y; + } + else /* x3 <= x2 <= x1 */ + { + x = *x1; *x1 = *x3; *x3 = x; + y = *y1; *y1 = *y3; *y3 = y; + } + } + else + { + if (*x2 < *x1) /* x2 < x1 <= x3 */ + { + x = *x1; *x1 = *x2; *x2 = x; + y = *y1; *y1 = *y2; *y2 = y; + } + else if (*x2 > *x3) /* x1 <= x3 < x2 */ + { + x = *x2; *x2 = *x3; *x3 = x; + y = *y2; *y2 = *y3; *y3 = y; + } + /* else already sorted */ + } +} + +/* draw a filled triangle, using horizontal lines for speed */ +void gfx_filltriangle(int x1, int y1, + int x2, int y2, + int x3, int y3) +{ + long fp_x1, fp_x2, fp_dx1, fp_dx2; + int y; + sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3); + + if (y1 < y3) /* draw */ + { + fp_dx1 = ((x3 - x1) << 16) / (y3 - y1); + fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1); + + if (y1 < y2) /* first part */ + { + fp_dx2 = ((x2 - x1) << 16) / (y2 - y1); + fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1); + for (y = y1; y < y2; y++) + { + gfx_hline(fp_x1 >> 16, fp_x2 >> 16, y); + fp_x1 += fp_dx1; + fp_x2 += fp_dx2; + } + } + if (y2 < y3) /* second part */ + { + fp_dx2 = ((x3 - x2) << 16) / (y3 - y2); + fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1); + for (y = y2; y < y3; y++) + { + gfx_hline(fp_x1 >> 16, fp_x2 >> 16, y); + fp_x1 += fp_dx1; + fp_x2 += fp_dx2; + } + } + } +} + +static void gfx_bitmap32(int x, int y, const struct bitmap_t *bmp) +{ + /* SLOOW */ + uint8_t *data = bmp->data; + for(unsigned int i = y; i < y + bmp->h && i < fb_height; ++i) + { + for(unsigned int j = x; j < x + bmp->w && j < fb_width; ++j) + { + uint8_t r = *data++; + uint8_t g = *data++; + uint8_t b = *data++; + gfx_set_foreground(VGA_RGBPACK(r, g, b)); + gfx_drawpixel(j, i); + } + } +} + +void gfx_bitmap(int x, int y, const struct bitmap_t *bmp) +{ + gfx_bitmap32(x, y, bmp); +} + +void gfx_drawrect(int x, int y, int w, int h) +{ + gfx_hline(MAX(0, x), MIN(x + w, fb_width), MAX(0, y)); + gfx_hline(MAX(0, x), MIN(x + w, fb_width), MIN(y + h, fb_height)); + gfx_vline(MAX(0, y), MIN(y + h, fb_height),MAX(0, x)); + gfx_vline(MAX(0, y), MIN(y + h, fb_height),MIN(x + w, fb_width)); +} + +void gfx_update(void) +{ + memcpy(real_framebuffer, framebuffer, fb_height * fb_stride); +} + +void gfx_set_doublebuffer(bool yesno) +{ + if(yesno) + framebuffer = temp_framebuffer; + else + framebuffer = real_framebuffer; +} + +bool gfx_get_doublebuffer(void) +{ + if(framebuffer == temp_framebuffer) + return true; + else + return false; +} + +void gfx_putsxy(int x, int y, const char* str) +{ + while(*str) + { + gfx_drawchar(x, y, *str); + x += FONT_WIDTH; + str++; + } +} + +void gfx_putsxy_bg(int x, int y, const char* str) +{ + while(*str) + { + gfx_drawchar_bg(x, y, *str); + x += FONT_WIDTH; + str++; + } +} + +bool gfx_init(struct vbe_info_t *vbe_mode_info) +{ + real_framebuffer = (uint8_t*)vbe_mode_info->physbase; + gfx_set_doublebuffer(false); + fb_width = vbe_mode_info->Xres; + fb_height = vbe_mode_info->Yres; + fb_bpp = vbe_mode_info->bpp / 8; + fb_stride = vbe_mode_info->pitch; + fb_stride32 = fb_stride / sizeof(uint32_t); + gfx_hline = gfx_hline_checked; + gfx_vline = gfx_vline_checked; + temp_framebuffer = malloc(fb_height * fb_stride); + if(fb_bpp != 4) + { + printf("WARNING: BPP != 32, falling back to text mode...\n"); + return false; + } + else + { + extern void gfx_drawpixel_32bpp(int, int); + gfx_drawpixel = &gfx_drawpixel_32bpp; + } + + set_putchar(gfx_putchar); + set_puts(gfx_puts); + + /* A bit of fragile code here... don't call gfx_reset() before setting gfx_clear! */ + + if(fb_stride != fb_bpp * fb_width) + { + gfx_clear = &gfx_clear_unpacked; + gfx_reset(); + printf("WARNING: Internal framebuffer padding detected, support is experimental.\n"); + } + else + { + /* assembly */ + extern void gfx_clear_packed(void); + gfx_clear = &gfx_clear_packed; + gfx_reset(); + } + + printf("Real FB addr: 0x%x\n", (uint32_t)real_framebuffer); + + return true; +} diff --git a/arch/i686/drivers/pcspkr.c b/arch/i686/drivers/pcspkr.c new file mode 100644 index 0000000..33c0540 --- /dev/null +++ b/arch/i686/drivers/pcspkr.c @@ -0,0 +1,19 @@ +#include <stdint.h> +#include "io.h" +#include "pcspkr.h" + +void pcspkr_play(uint32_t freq) +{ + uint32_t div; + uint8_t tmp; + + div = 1193180 / freq; + outb(0x43, 0xb6); + outb(0x42, (uint8_t)(div)); + outb(0x42, (uint8_t)(div >> 8)); + + tmp = inb(0x61); + if (tmp != (tmp | 3)) { + outb(0x61, tmp | 3); + } +} diff --git a/arch/i686/drivers/ps2kbd.c b/arch/i686/drivers/ps2kbd.c new file mode 100644 index 0000000..29d02dc --- /dev/null +++ b/arch/i686/drivers/ps2kbd.c @@ -0,0 +1,212 @@ +/* this is a PS/2 keyboard driver */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include "io.h" +#include "isr.h" +#include "ps2kbd.h" +#include "ps2_keymaps.h" + +static void ps2_wait(void) +{ + /* wait for the keyboard */ + while(1) + if ((inb(0x64) & 2) == 0) break; +} + +void ps2kbd_set_leds(uint8_t status) +{ + ps2_wait(); + outb(0x60, 0xED); + outb(0x60, status); +} + +#define IDX_UP 0 +#define IDX_LEFT 1 +#define IDX_DOWN 2 +#define IDX_RIGHT 3 + +static uint8_t ps2_arrowkeys[4]; + +uint8_t ps2kbd_button_get(void) +{ + uint8_t ret = 0; + if(ps2_arrowkeys[IDX_UP]) + ret |= BUTTON_UP; + if(ps2_arrowkeys[IDX_LEFT]) + ret |= BUTTON_LEFT; + if(ps2_arrowkeys[IDX_DOWN]) + ret |= BUTTON_DOWN; + if(ps2_arrowkeys[IDX_RIGHT]) + ret |= BUTTON_RIGHT; + return ret; +} + +static uint8_t ps2_ctrl; +static uint8_t ps2_shift; +static uint8_t ps2_alt; + +uint8_t ps2kbd_modifier_get(void) +{ + uint8_t ret = 0; + if(ps2_ctrl) + ret |= MODIFIER_CTRL; + if(ps2_shift) + ret |= MODIFIER_SHIFT; + if(ps2_alt) + ret |= MODIFIER_ALT; + return ret; +} + +static struct ps2_specialkeys_t special_keys; + +static void handle_special_key(uint8_t scancode, int release) +{ + int press = ~release; + switch(ps2_set1_special[scancode]) + { + case SPECIAL_SHIFT: + special_keys.shift = press; + break; + case SPECIAL_CTRL: + special_keys.ctrl = press; + break; + case SPECIAL_BKSP: + special_keys.bksp = press; + break; + case SPECIAL_ALT: + special_keys.alt = press; + break; + case SPECIAL_NUMLOCK: + special_keys.numlock = ~special_keys.numlock; + ps2kbd_set_leds((special_keys.capslock << 2) | (special_keys.numlock << 1) | special_keys.scrllock); + break; + case SPECIAL_CAPLOCK: + special_keys.capslock = ~special_keys.capslock; + ps2kbd_set_leds((special_keys.capslock << 2) | (special_keys.numlock << 1) | special_keys.scrllock); + break; + case SPECIAL_SCRLLOCK: + special_keys.scrllock = ~special_keys.scrllock; + ps2kbd_set_leds((special_keys.capslock << 2) | (special_keys.numlock << 1) | special_keys.scrllock); + break; + case SPECIAL_ESC: + special_keys.esc = press; + break; + case SPECIAL_F1: + special_keys.f1 = press; + break; + case SPECIAL_F2: + special_keys.f2 = press; + break; + case SPECIAL_F3: + special_keys.f3 = press; + break; + case SPECIAL_F4: + special_keys.f4 = press; + break; + case SPECIAL_F5: + special_keys.f5 = press; + break; + case SPECIAL_F6: + special_keys.f6 = press; + break; + case SPECIAL_F7: + special_keys.f7 = press; + break; + case SPECIAL_F8: + special_keys.f8 = press; + break; + case SPECIAL_F9: + special_keys.f9 = press; + break; + case SPECIAL_F10: + special_keys.f10 = press; + break; + case SPECIAL_F11: + special_keys.f11 = press; + break; + case SPECIAL_F12: + special_keys.f12 = press; + break; + } +} + +static void handle_extended_scancode(void) +{ + uint8_t temp = inb(0x60); + (void) temp; + //printf("Extended scancode: 0x%x\n", temp); +} + +void (*keyevent_handler)(const struct ps2_keyevent*); + +static void key_handler(struct regs_t *regs) +{ + (void) regs; + uint8_t scancode = inb(0x60); + //printf("INTR SCAN: 0x%x\n", scancode); + if(scancode == EXTENDED_SCANCODE) + { + handle_extended_scancode(); + return; + } + + /* AND by 0x7F to get in the range of [0,128) */ + + int type = ps2_set1_scancodes[scancode & 0x7F]; + int release = (scancode & (1<<7)) >> 7; + char ascii = '\0'; + switch(type) + { + case PRINTING_KEY: + { + if(!release) + { + int capitals = special_keys.capslock; + if(special_keys.shift) + capitals = ~capitals; + if(capitals) + ascii = ps2_set1_shift[scancode]; + else + ascii = ps2_set1_ascii[scancode]; + } + break; + } + case SPECIAL_KEY: + handle_special_key(scancode & 0x7F, release); + break; + } + if(special_keys.bksp) + ascii = '\b'; + if(keyevent_handler) + { + struct ps2_keyevent ev; + ev.special_keys = &special_keys; + ev.ascii = ascii; + keyevent_handler(&ev); + } +} + +static void ps2_set_scancode_set(uint8_t set) +{ + ps2_wait(); + outb(0x60, 0xF0); + outb(0x60, set); +} + +static void keyboard_init(void) +{ + set_interrupt_handler(IRQ(1), key_handler); + ps2_set_scancode_set(1); + memset(&special_keys, 0, sizeof(special_keys)); +} + +void ps2kbd_set_handler(void (*handler)(const struct ps2_keyevent*)) +{ + keyevent_handler = handler; +} + +void ps2kbd_init(void) +{ + keyboard_init(); +} diff --git a/arch/i686/drivers/vgatext.c b/arch/i686/drivers/vgatext.c new file mode 100644 index 0000000..d0633af --- /dev/null +++ b/arch/i686/drivers/vgatext.c @@ -0,0 +1,124 @@ +#include <stdint.h> +#include <stdio.h> +#include "gfx.h" +#include "io.h" +#include "panic.h" +#include "vgatext.h" + +static int term_x, term_y; +static uint8_t term_col; +/* VGA buffer starts at 0xB8000 on color or 0xB0000 on monochrome */ +static uint16_t *term_buf; + +static uint16_t video_detect_hardware(void) +{ + const uint16_t *ptr = (const uint16_t*)0x410; + return *ptr; +} + +void vgatext_init(void) +{ + uint16_t vid_type = video_detect_hardware() & 0x30; + if(vid_type == 0x20) + { + /* color */ + term_buf = (uint16_t*)0xB8000; + } + else if(vid_type == 0x30) + { + term_buf = (uint16_t*)0xB0000; + } + else + { + /* none */ + panic("VGATEXT init failed!"); + } + vgatext_set_color(VGA_MAKE_COLOR(VGA_LIGHT_GRAY, VGA_BLACK)); + vgatext_clear(); + set_putchar(vgatext_putchar); + set_puts(vgatext_puts); +} + +static void move_cursor(uint16_t cursor_idx) +{ + outb(0x3D4, 14); + outb(0x3D5, cursor_idx >> 8); // high byte + outb(0x3D4, 15); + outb(0x3D5, cursor_idx); // low byte +} + +static void update_cursor(void) +{ + move_cursor(term_y * VGA_WIDTH + term_x); +} + +void vgatext_clear(void) +{ + term_x = 0; + term_y = 0; + for(int y = 0; y < VGA_HEIGHT; ++y) + { + for(int x = 0; x < VGA_WIDTH; ++x) + { + term_buf[y * VGA_WIDTH + x] = VGA_MAKE_ENTRY(' ', term_col); + } + } +} + +void vgatext_set_color(uint8_t color) +{ + term_col = color; +} + +uint8_t vgatext_get_color(void) +{ + return term_col; +} + +void vgatext_putchar_at(int ch, uint8_t col, int x, int y) +{ + term_buf[y * VGA_WIDTH + x] = VGA_MAKE_ENTRY((char)ch, col); +} + +void vgatext_putchar(int ch) +{ + if(ch != '\n' && ch != '\b') + { + vgatext_putchar_at(ch, term_col, term_x, term_y); + if(++term_x == VGA_WIDTH) + { + term_x = 0; + if(++term_y == VGA_HEIGHT) + { + vgatext_clear(); + term_y = 0; + } + } + } + else if(ch == '\n') + { + term_x = 0; + if(++term_y == VGA_HEIGHT) + { + vgatext_clear(); + term_y = 0; + } + } + else if(ch == '\b') + { + int temp_x = term_x - 1; + if(temp_x >= 0) + term_x = temp_x; + vgatext_putchar_at(' ', term_col, term_x, term_y); + } + + update_cursor(); +} + +void vgatext_puts(const char *str) +{ + while(*str) + { + vgatext_putchar(*str++); + } +} diff --git a/arch/i686/fpu.c b/arch/i686/fpu.c new file mode 100644 index 0000000..f5512d6 --- /dev/null +++ b/arch/i686/fpu.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2011-2013 Kevin Lange */ +/* this code from toaruos */ +#include <stddef.h> +#include "fpu.h" + +/** + * Enable the FPU and SSE + */ +void fpu_enable(void) { + asm volatile ("clts"); + size_t t; + asm volatile ("mov %%cr4, %0" : "=r"(t)); + t |= 3 << 9; + asm volatile ("mov %0, %%cr4" :: "r"(t)); +} + +/** + * Disable FPU and SSE so it traps to the kernel + */ +void fpu_disable(void) { + size_t t; + asm volatile ("mov %%cr0, %0" : "=r"(t)); + t |= 1 << 3; + asm volatile ("mov %0, %%cr0" :: "r"(t)); +} diff --git a/arch/i686/gdt-as.S b/arch/i686/gdt-as.S new file mode 100644 index 0000000..5a481e3 --- /dev/null +++ b/arch/i686/gdt-as.S @@ -0,0 +1,14 @@ + .global gdt_flush +gdt_flush: # prototype: void gdt_flush(uint32) + movl 4(%esp), %eax + lgdt (%eax) + # 0x8 is the code segment selector + jmp $0x8, $.flush +.flush: + mov $0x10, %ax # 0x10 is the data segment selector + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + ret diff --git a/arch/i686/gdt.c b/arch/i686/gdt.c new file mode 100644 index 0000000..36a0cda --- /dev/null +++ b/arch/i686/gdt.c @@ -0,0 +1,34 @@ +#include "gdt.h" + +static void gdt_set_gate(int idx, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) +{ + /* Setup the descriptor base address */ + gdt[idx].base_low = (base & 0xFFFF); + gdt[idx].base_middle = (base >> 16) & 0xFF; + gdt[idx].base_high = (base >> 24) & 0xFF; + + /* Setup the descriptor limits */ + gdt[idx].limit_low = (limit & 0xFFFF); + gdt[idx].granularity = ((limit >> 16) & 0x0F); + + /* Finally, set up the granularity and access flags */ + gdt[idx].granularity |= (gran & 0xF0); + gdt[idx].access = access; +} + +void gdt_init(void) +{ + gp.limit = sizeof(gdt) - 1; + gp.base = (uint32_t)&gdt; + + /* null segment */ + gdt_set_gate(0, 0, 0, 0, 0); + + /* code segment */ + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); + + /* data segment */ + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + + gdt_flush((uint32_t)&gp); +} diff --git a/arch/i686/idt-as.S b/arch/i686/idt-as.S new file mode 100644 index 0000000..d1ab7e2 --- /dev/null +++ b/arch/i686/idt-as.S @@ -0,0 +1,6 @@ + .global idt_flush + .type idt_flush, @function +idt_flush: # prototype: void idt_flush(uint32) + movl 4(%esp), %eax + lidt (%eax) + ret diff --git a/arch/i686/idt.c b/arch/i686/idt.c new file mode 100644 index 0000000..0108991 --- /dev/null +++ b/arch/i686/idt.c @@ -0,0 +1,24 @@ +#include <stdint.h> +#include <string.h> +#include "idt.h" +#include "isr.h" +#include "irq.h" + +void idt_set_gate(uint8_t idx, uint32_t base, uint16_t sel, uint8_t flags) +{ + idt[idx].base_lo = base & 0xFFFF; + idt[idx].base_hi = base >> 16; + idt[idx].sel = sel; + idt[idx].zero = 0; + idt[idx].flags = flags; +} + +void idt_init(void) +{ + idt_pt.limit = sizeof(idt) - 1; + idt_pt.base = (uint32_t)&idt; + + memset(&idt, 0, sizeof(idt)); + + idt_flush((uint32_t)&idt_pt); +} diff --git a/arch/i686/irq-as.S b/arch/i686/irq-as.S new file mode 100644 index 0000000..1d16392 --- /dev/null +++ b/arch/i686/irq-as.S @@ -0,0 +1,146 @@ + .extern irq_handler + +irq_stub: + + pusha + push %ds + push %es + push %fs + push %gs + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %esp, %eax # push the stack + push %eax + mov $irq_handler, %eax + call *%eax + pop %eax + pop %gs + pop %fs + pop %es + pop %ds + popa + addl $8, %esp + iret + + .global _irq0 + .global _irq1 + .global _irq2 + .global _irq3 + .global _irq4 + .global _irq5 + .global _irq6 + .global _irq7 + .global _irq8 + .global _irq9 + .global _irq10 + .global _irq11 + .global _irq12 + .global _irq13 + .global _irq14 + .global _irq15 + .global _int0x80 + +_irq0: + cli + pushl $0 + pushl $32 + jmp irq_stub + +_irq1: + cli + pushl $0 + pushl $33 + jmp irq_stub + +_irq2: + cli + pushl $0 + pushl $34 + jmp irq_stub + +_irq3: + cli + pushl $0 + pushl $35 + jmp irq_stub + +_irq4: + cli + pushl $0 + pushl $36 + jmp irq_stub + +_irq5: + cli + pushl $0 + pushl $37 + jmp irq_stub + +_irq6: + cli + pushl $0 + pushl $38 + jmp irq_stub + +_irq7: + cli + pushl $0 + pushl $39 + jmp irq_stub + +_irq8: + cli + pushl $0 + pushl $40 + jmp irq_stub + +_irq9: + cli + pushl $0 + pushl $41 + jmp irq_stub + +_irq10: + cli + pushl $0 + pushl $42 + jmp irq_stub + +_irq11: + cli + pushl $0 + pushl $43 + jmp irq_stub + +_irq12: + cli + pushl $0 + pushl $44 + jmp irq_stub + +_irq13: + cli + pushl $0 + pushl $45 + jmp irq_stub + +_irq14: + cli + pushl $0 + pushl $46 + jmp irq_stub + +_irq15: + cli + pushl $0 + pushl $47 + jmp irq_stub + +_int0x80: + cli + pushl $0 + pushl $0x80 + jmp irq_stub diff --git a/arch/i686/irq.c b/arch/i686/irq.c new file mode 100644 index 0000000..c6dbf4c --- /dev/null +++ b/arch/i686/irq.c @@ -0,0 +1,73 @@ +#include <stdint.h> +#include <stddef.h> +#include <stdio.h> +#include "idt.h" +#include "io.h" +#include "irq.h" +#include "isr.h" +#include "panic.h" + +/* in isr.c */ +extern void *int_callbacks[256]; + +void irq_remap(void) +{ + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x0); + outb(0xA1, 0x0); +} + +void irq_init(void) +{ + irq_remap(); + idt_set_gate(32, (uint32_t)_irq0, 0x08, 0x8E); + idt_set_gate(33, (uint32_t)_irq1, 0x08, 0x8E); + idt_set_gate(34, (uint32_t)_irq2, 0x08, 0x8E); + idt_set_gate(35, (uint32_t)_irq3, 0x08, 0x8E); + idt_set_gate(36, (uint32_t)_irq4, 0x08, 0x8E); + idt_set_gate(37, (uint32_t)_irq5, 0x08, 0x8E); + idt_set_gate(38, (uint32_t)_irq6, 0x08, 0x8E); + idt_set_gate(39, (uint32_t)_irq7, 0x08, 0x8E); + idt_set_gate(40, (uint32_t)_irq8, 0x08, 0x8E); + idt_set_gate(41, (uint32_t)_irq9, 0x08, 0x8E); + idt_set_gate(42, (uint32_t)_irq10, 0x08, 0x8E); + idt_set_gate(43, (uint32_t)_irq11, 0x08, 0x8E); + idt_set_gate(44, (uint32_t)_irq12, 0x08, 0x8E); + idt_set_gate(45, (uint32_t)_irq13, 0x08, 0x8E); + idt_set_gate(46, (uint32_t)_irq14, 0x08, 0x8E); + idt_set_gate(47, (uint32_t)_irq15, 0x08, 0x8E); + idt_set_gate(128,(uint32_t)_int0x80, 0x08, 0x8E); +} + +void irq_handler(struct regs_t *regs) +{ + void (*handler)(struct regs_t *r); + + handler = int_callbacks[regs->int_no]; + + if(handler) + { + handler(regs); + } + else + { + } + + /* If the IDT entry that was invoked was greater than 40 + * (meaning IRQ8 - 15), then we need to send an EOI to + * the slave controller */ + if (regs->int_no >= 40) + { + outb(0xA0, 0x20); + } + + /* send an EOI to the master controller */ + outb(0x20, 0x20); +} diff --git a/arch/i686/isr-as.S b/arch/i686/isr-as.S new file mode 100644 index 0000000..858ce47 --- /dev/null +++ b/arch/i686/isr-as.S @@ -0,0 +1,214 @@ + .extern isr_handler +isr_stub: + pusha + push %ds + push %es + push %fs + push %gs + mov $0x10, %ax # Load the Kernel Data Segment descriptor! + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %esp, %eax # Push us the stack + push %eax + call isr_handler + pop %eax + pop %gs + pop %fs + pop %es + pop %ds + popa + add $8, %esp + iret + + # stub ISR's: + .global _isr0 + .global _isr1 + .global _isr2 + .global _isr3 + .global _isr4 + .global _isr5 + .global _isr6 + .global _isr7 + .global _isr8 + .global _isr9 + .global _isr10 + .global _isr11 + .global _isr12 + .global _isr13 + .global _isr14 + .global _isr15 + .global _isr16 + .global _isr17 + .global _isr18 + .global _isr19 + .global _isr20 + .global _isr21 + .global _isr22 + .global _isr23 + .global _isr24 + .global _isr25 + .global _isr26 + .global _isr27 + .global _isr28 + .global _isr29 + .global _isr30 + .global _isr31 + + # Interrupts 8, 10, 11, 12, 13, and 14 push error codes onto the stack + +_isr0: + cli + pushl $0 + pushl $0 + jmp isr_stub +_isr1: + cli + pushl $0 + pushl $1 + jmp isr_stub +_isr2: + cli + pushl $0 + pushl $2 + jmp isr_stub +_isr3: + cli + pushl $0 + pushl $3 + jmp isr_stub +_isr4: + cli + pushl $0 + pushl $4 + jmp isr_stub +_isr5: + cli + pushl $0 + pushl $5 + jmp isr_stub +_isr6: + cli + pushl $0 + pushl $6 + jmp isr_stub +_isr7: + cli + pushl $0 + pushl $7 + jmp isr_stub +_isr8: + cli + pushl $8 + jmp isr_stub +_isr9: + cli + pushl $0 + pushl $9 + jmp isr_stub +_isr10: + cli + pushl $10 + jmp isr_stub +_isr11: + cli + pushl $11 + jmp isr_stub +_isr12: + cli + pushl $12 + jmp isr_stub +_isr13: + cli + pushl $13 + jmp isr_stub +_isr14: + cli + pushl $14 + jmp isr_stub +_isr15: + cli + pushl $0 + pushl $15 + jmp isr_stub +_isr16: + cli + pushl $0 + pushl $16 + jmp isr_stub +_isr17: + cli + pushl $0 + pushl $17 + jmp isr_stub +_isr18: + cli + pushl $0 + pushl $18 + jmp isr_stub +_isr19: + cli + pushl $0 + pushl $19 + jmp isr_stub +_isr20: + cli + pushl $0 + pushl $20 + jmp isr_stub +_isr21: + cli + pushl $0 + pushl $21 + jmp isr_stub +_isr22: + cli + pushl $0 + pushl $22 + jmp isr_stub +_isr23: + cli + pushl $0 + pushl $23 + jmp isr_stub +_isr24: + cli + pushl $0 + pushl $24 + jmp isr_stub +_isr25: + cli + pushl $0 + pushl $25 + jmp isr_stub +_isr26: + cli + pushl $0 + pushl $26 + jmp isr_stub +_isr27: + cli + pushl $0 + pushl $27 + jmp isr_stub +_isr28: + cli + pushl $0 + pushl $28 + jmp isr_stub +_isr29: + cli + pushl $0 + pushl $29 + jmp isr_stub +_isr30: + cli + pushl $0 + pushl $30 + jmp isr_stub +_isr31: + cli + pushl $0 + pushl $31 + jmp isr_stub diff --git a/arch/i686/isr.c b/arch/i686/isr.c new file mode 100644 index 0000000..e6887c6 --- /dev/null +++ b/arch/i686/isr.c @@ -0,0 +1,60 @@ +#include <stddef.h> +#include <stdio.h> +#include "isr.h" +#include "idt.h" +#include "panic.h" + +void (*int_callbacks[256])(struct regs_t*) = { NULL }; + +void set_interrupt_handler(uint8_t n, void (*callback)(struct regs_t*)) +{ + int_callbacks[n] = callback; +} + +void isr_handler(struct regs_t *regs) +{ + if(int_callbacks[regs->int_no]) + { + int_callbacks[regs->int_no](regs); + } + else + { + printf("WARNING: unhandled ISR 0x%x!\n", regs->int_no); + } +} + +void isr_init(void) +{ + idt_set_gate(0, (uint32_t)_isr0, 0x08, 0x8E); + idt_set_gate(1, (uint32_t)_isr1, 0x08, 0x8E); + idt_set_gate(2, (uint32_t)_isr2, 0x08, 0x8E); + idt_set_gate(3, (uint32_t)_isr3, 0x08, 0x8E); + idt_set_gate(4, (uint32_t)_isr4, 0x08, 0x8E); + idt_set_gate(5, (uint32_t)_isr5, 0x08, 0x8E); + idt_set_gate(6, (uint32_t)_isr6, 0x08, 0x8E); + idt_set_gate(7, (uint32_t)_isr7, 0x08, 0x8E); + idt_set_gate(8, (uint32_t)_isr8, 0x08, 0x8E); + idt_set_gate(9, (uint32_t)_isr9, 0x08, 0x8E); + idt_set_gate(10, (uint32_t)_isr10, 0x08, 0x8E); + idt_set_gate(11, (uint32_t)_isr11, 0x08, 0x8E); + idt_set_gate(12, (uint32_t)_isr12, 0x08, 0x8E); + idt_set_gate(13, (uint32_t)_isr13, 0x08, 0x8E); + idt_set_gate(14, (uint32_t)_isr14, 0x08, 0x8E); + idt_set_gate(15, (uint32_t)_isr15, 0x08, 0x8E); + idt_set_gate(16, (uint32_t)_isr16, 0x08, 0x8E); + idt_set_gate(17, (uint32_t)_isr17, 0x08, 0x8E); + idt_set_gate(18, (uint32_t)_isr18, 0x08, 0x8E); + idt_set_gate(19, (uint32_t)_isr19, 0x08, 0x8E); + idt_set_gate(20, (uint32_t)_isr20, 0x08, 0x8E); + idt_set_gate(21, (uint32_t)_isr21, 0x08, 0x8E); + idt_set_gate(22, (uint32_t)_isr22, 0x08, 0x8E); + idt_set_gate(23, (uint32_t)_isr23, 0x08, 0x8E); + idt_set_gate(24, (uint32_t)_isr24, 0x08, 0x8E); + idt_set_gate(25, (uint32_t)_isr25, 0x08, 0x8E); + idt_set_gate(26, (uint32_t)_isr26, 0x08, 0x8E); + idt_set_gate(27, (uint32_t)_isr27, 0x08, 0x8E); + idt_set_gate(28, (uint32_t)_isr28, 0x08, 0x8E); + idt_set_gate(29, (uint32_t)_isr29, 0x08, 0x8E); + idt_set_gate(30, (uint32_t)_isr30, 0x08, 0x8E); + idt_set_gate(31, (uint32_t)_isr31, 0x08, 0x8E); +} diff --git a/arch/i686/linker.ld b/arch/i686/linker.ld new file mode 100644 index 0000000..c032991 --- /dev/null +++ b/arch/i686/linker.ld @@ -0,0 +1,45 @@ +/* The bootloader will look at this image and start execution at the symbol + designated as the entry point. */ +ENTRY(_start) + +/* Tell where the various sections of the object files will be put in the final + kernel image. */ +SECTIONS +{ + /* Begin putting sections at 1 MiB, a conventional place for kernels to be + loaded at by the bootloader. */ + . = 1M; + + /* First put the multiboot header, as it is required to be put very early + early in the image or the bootloader won't recognize the file format. + Next we'll put the .text section. */ + .text BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + *(.text) + } + + /* Read-only data. */ + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + *(.bootstrap_stack) + } + + /* The compiler may produce other sections, by default it will put them in + a segment with the same name. Simply add stuff here as needed. */ + link_mem_end = .; +} diff --git a/arch/i686/paging-as.S b/arch/i686/paging-as.S new file mode 100644 index 0000000..cafaab4 --- /dev/null +++ b/arch/i686/paging-as.S @@ -0,0 +1,9 @@ + .global do_paging_enable +do_paging_enable: + movl 4(%esp), %eax # loads page directory address + mov %eax, %cr3 + mov %cr0, %eax + orl $0x80000000, %eax # set PG bit + sti + mov %eax, %cr0 + ret diff --git a/arch/i686/paging.c b/arch/i686/paging.c new file mode 100644 index 0000000..9d748ab --- /dev/null +++ b/arch/i686/paging.c @@ -0,0 +1,64 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include "heap.h" +#include "isr.h" +#include "paging.h" +#include "panic.h" + +uint32_t *current_directory; + +static void page_fault(struct regs_t *regs) +{ + volatile uint32_t fault_addr; + asm("mov %%cr2, %0" : "=r"(fault_addr)); + printf("=== Page Fault ===\n"); + printf("Faulting address: 0x%x\n", fault_addr); + /* dump the regs */ + printf("EAX: 0x%x EBX: 0x%x\n", regs->eax, regs->ebx); + printf("ECX: 0x%x EDX: 0x%x\n", regs->ecx, regs->edx); + printf("ESP: 0x%x EBP: 0x%x\n", regs->esp, regs->ebp); + printf("ESI: 0x%x EDI: 0x%x\n", regs->esi, regs->edi); + printf("EIP: 0x%x\n", regs->eip); + panic("Page fault!\n"); +} + + void paging_switch_directory(uint32_t *dir) +{ + current_directory = dir; + extern void do_paging_enable(uint32_t); + do_paging_enable((uint32_t)current_directory); +} + +static uint32_t *identity_map_table(uint32_t start, int flags) +{ + /* make a page table */ + uint32_t *table = kmalloc_a(0x1000); + /* identity map 4MB */ + for(uint32_t i = start; i < start + 1024; ++i) + { + table[i - start] = (i * PAGE_SIZE) | flags; + } + return table; +} + +void paging_init(void) +{ + uint32_t *kernel_directory = kmalloc_a(0x1000); + memset(kernel_directory, 0, 0x1000); + /* blank the kernel directory */ + for(int i = 0; i < 1024; ++i) + { + kernel_directory[i] = PAGE_RW; + } + + /* identity map all 4GB (and allocate all page tables) */ + for(int i = 0; i < 1024; ++i) + kernel_directory[i] = (uint32_t)identity_map_table(i * 1024, PAGE_PRESENT | PAGE_RW) | + PAGE_PRESENT | PAGE_RW; + + set_interrupt_handler(14, page_fault); + + paging_switch_directory(kernel_directory); +} |