aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorFranklin Wei <frankhwei536@gmail.com>2015-03-01 14:20:47 -0500
committerFranklin Wei <frankhwei536@gmail.com>2015-03-01 14:20:47 -0500
commitc7252588ebb95f97631e9470778c69afa00c35b5 (patch)
tree06d760878e18f6cddbe4305cddd4d5dfa74529f8 /arch
parentb8f54e63d2b8f8007c580adf2a6034c98a0f2eaa (diff)
downloadkappa-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.S41
-rw-r--r--arch/i686/drivers/gfx-as.S101
-rw-r--r--arch/i686/drivers/gfx.c540
-rw-r--r--arch/i686/drivers/pcspkr.c19
-rw-r--r--arch/i686/drivers/ps2kbd.c212
-rw-r--r--arch/i686/drivers/vgatext.c124
-rw-r--r--arch/i686/fpu.c25
-rw-r--r--arch/i686/gdt-as.S14
-rw-r--r--arch/i686/gdt.c34
-rw-r--r--arch/i686/idt-as.S6
-rw-r--r--arch/i686/idt.c24
-rw-r--r--arch/i686/irq-as.S146
-rw-r--r--arch/i686/irq.c73
-rw-r--r--arch/i686/isr-as.S214
-rw-r--r--arch/i686/isr.c60
-rw-r--r--arch/i686/linker.ld45
-rw-r--r--arch/i686/paging-as.S9
-rw-r--r--arch/i686/paging.c64
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);
+}