summaryrefslogtreecommitdiff
path: root/kernel/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/arch')
-rw-r--r--kernel/src/arch/i686/acpi.c106
-rw-r--r--kernel/src/arch/i686/asm.c51
-rw-r--r--kernel/src/arch/i686/drivers/ps2ctrl.c91
-rw-r--r--kernel/src/arch/i686/drivers/ps2kb.c124
-rw-r--r--kernel/src/arch/i686/drivers/ps2mouse.c81
-rw-r--r--kernel/src/arch/i686/drivers/rtc.c152
-rw-r--r--kernel/src/arch/i686/drivers/vga.c50
-rw-r--r--kernel/src/arch/i686/gdt.asm42
-rw-r--r--kernel/src/arch/i686/idt.asm99
-rw-r--r--kernel/src/arch/i686/idt.c140
-rw-r--r--kernel/src/arch/i686/mboot.c73
-rw-r--r--kernel/src/arch/i686/memory.c197
-rw-r--r--kernel/src/arch/i686/paging.asm62
-rw-r--r--kernel/src/arch/i686/pic.c80
-rw-r--r--kernel/src/arch/i686/start.asm82
-rw-r--r--kernel/src/arch/i686/sys.c51
-rw-r--r--kernel/src/arch/i686/time.c17
17 files changed, 1498 insertions, 0 deletions
diff --git a/kernel/src/arch/i686/acpi.c b/kernel/src/arch/i686/acpi.c
new file mode 100644
index 0000000..7807558
--- /dev/null
+++ b/kernel/src/arch/i686/acpi.c
@@ -0,0 +1,106 @@
+#include <panic.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <arch/i686/acpi.h>
+#include <arch/i686/asm.h>
+
+extern uintptr_t KERNEL_MAPPING;
+
+static struct RootSystemDescriptionTable *rsdt;
+static struct FixedACPIDescriptionTable *fadt;
+
+static uint16_t SLP_TYPa;
+static uint16_t SLP_TYPb;
+static uint16_t SLP_EN;
+static uint16_t SCI_EN;
+
+static bool checksum(uint8_t *data, size_t len) {
+ unsigned char sum = 0;
+ for (size_t i = 0; i < len; i++)
+ sum += data[i];
+ return sum == 0;
+}
+
+static void *find_fadt(void) {
+ int entries = (rsdt->header.length - sizeof(rsdt->header)) / 4;
+
+ for (int i = 0; i < entries; i++) {
+ uintptr_t sdt_ptr = rsdt->sdt_table[i];
+ struct SystemDescriptionTableHeader *h = (void*) sdt_ptr;
+ if (!strncmp(h->signature, "FACP", 4))
+ return (void *) h;
+ }
+
+ return NULL;
+}
+
+static void read_s5_addr(void) {
+ uintptr_t ptr = fadt->dsdt;
+ char *s5_addr = (void*) (ptr + 36);
+
+ int dsdt_len = *((int*) (ptr+1)) - 36;
+ while (0 < dsdt_len--) {
+ if ( memcmp(s5_addr, "_S5_", 4) == 0)
+ break;
+ s5_addr++;
+ }
+
+ if (dsdt_len > 0) {
+ // check for valid AML structure
+ if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) {
+ s5_addr += 5;
+ s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size
+
+ if (*s5_addr == 0x0A)
+ s5_addr++; // skip byteprefix
+ SLP_TYPa = *(s5_addr)<<10;
+ s5_addr++;
+
+ if (*s5_addr == 0x0A)
+ s5_addr++; // skip byteprefix
+ SLP_TYPb = *(s5_addr)<<10;
+
+ SLP_EN = 1<<13;
+ SCI_EN = 1;
+
+ } else {
+ panic("\\_S5 parse error.");
+ }
+ } else {
+ panic("\\_S5 not present.");
+ }
+}
+
+void acpi_init(void *ptr) {
+
+ struct RootSystemDescriptionPointer *rsdp = ptr;
+ if (!checksum((uint8_t*) rsdp, sizeof(struct RootSystemDescriptionPointer))) {
+ panic("RSDP checksum failed to validate");
+ }
+
+ uintptr_t rsdt_ptr = rsdp->rsdt_address;
+ rsdt = (void *) rsdt_ptr;
+ if (!checksum((uint8_t*) &rsdt->header, rsdt->header.length)) {
+ panic("RSDT checksum failed to validate");
+ }
+
+ fadt = find_fadt();
+ if (fadt == NULL) {
+ panic("Could not find FADT");
+ }
+
+ if (!checksum((uint8_t*) &fadt->header, fadt->header.length)) {
+ panic("FADT checksum failed to validate");
+ }
+
+ read_s5_addr();
+
+ outb(fadt->smi_command_port,fadt->acpi_enable);
+}
+
+void acpi_poweroff(void) {
+ outw((unsigned int) fadt->pm1_a_control_block, SLP_TYPb | SLP_EN);
+ panic("failed to shutdown");
+}
diff --git a/kernel/src/arch/i686/asm.c b/kernel/src/arch/i686/asm.c
new file mode 100644
index 0000000..8ed00d0
--- /dev/null
+++ b/kernel/src/arch/i686/asm.c
@@ -0,0 +1,51 @@
+#include <arch/i686/asm.h>
+
+uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+void outb(uint16_t port, uint8_t val) {
+ __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
+}
+
+uint16_t inw(uint16_t port) {
+ uint16_t ret;
+ __asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+void outw(uint16_t port, uint16_t val) {
+ __asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
+}
+
+uint32_t inl(uint16_t port) {
+ uint32_t ret;
+ __asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+void outl(uint16_t port, uint32_t val) {
+ __asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
+}
+
+void io_wait(void) {
+ outb(0x80, 0);
+}
+
+void int_enable(void) {
+ __asm__ volatile ("sti");
+}
+
+void int_disable(void) {
+ __asm__ volatile ("cli");
+}
+
+void int_wait(void) {
+ __asm__ volatile ("sti; hlt");
+}
+
+void halt(void) {
+ __asm__ volatile ("cli; hlt");
+}
diff --git a/kernel/src/arch/i686/drivers/ps2ctrl.c b/kernel/src/arch/i686/drivers/ps2ctrl.c
new file mode 100644
index 0000000..794aabd
--- /dev/null
+++ b/kernel/src/arch/i686/drivers/ps2ctrl.c
@@ -0,0 +1,91 @@
+#include <panic.h>
+#include <arch/i686/drivers/ps2ctrl.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/asm.h>
+
+#define STATUS_OUT_BUF ((uint8_t)0x01)
+#define STATUS_IN_BUF ((uint8_t)0x02)
+
+#define CONFIG_INT_0 ((uint8_t)0x01)
+#define CONFIG_INT_1 ((uint8_t)0x02)
+#define CONFIG_SYS ((uint8_t)0x04)
+#define CONFIG_CLOCK_0 ((uint8_t)0x10)
+#define CONFIG_CLOCK_1 ((uint8_t)0x20)
+#define CONFIG_TRANS ((uint8_t)0x40)
+
+static bool is_init = false;
+
+uint8_t ps2ctrl_in(void) {
+ while((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
+ io_wait();
+ }
+ return inb(0x60);
+}
+
+uint8_t ps2ctrl_in_status(void) {
+ return inb(0x64);
+}
+
+void ps2ctrl_out_cmd(uint8_t cmd) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x64, cmd);
+}
+
+void ps2ctrl_out_data(uint8_t data) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x60, data);
+}
+
+void ps2ctrl_set_port2(void) {
+ outb(0x64, 0xD4);
+}
+
+void ps2ctrl_init(void) {
+
+ is_init = false;
+
+ pic_mask(1); // keyboard
+ pic_mask(12); // mouse
+
+ inb(0x60);
+
+ // self-test
+ ps2ctrl_out_cmd(0xAA);
+ uint8_t response = ps2ctrl_in();
+ if(response != 0x55) {
+ panic("PS/2 controller failed to initialize");
+ }
+
+ // set config
+ ps2ctrl_out_cmd(0x20);
+ uint8_t config = ps2ctrl_in();
+ config = (config | CONFIG_INT_0 | CONFIG_INT_1) & ~CONFIG_TRANS;
+ // config = 0xFF;
+ ps2ctrl_out_cmd(0x60);
+ ps2ctrl_out_data(config);
+
+ // enable port 0
+ ps2ctrl_out_cmd(0xAE);
+
+ // enable port 2
+ ps2ctrl_out_cmd(0xA9);
+ response = ps2ctrl_in();
+ if (response == 0x01) {
+ panic("PS/2 port 2 not supported");
+ }
+
+ ps2ctrl_out_cmd(0xA8);
+
+ is_init = true;
+
+ pic_unmask(1);
+ pic_unmask(12);
+}
+
+bool ps2ctrl_is_init(void) {
+ return is_init;
+}
diff --git a/kernel/src/arch/i686/drivers/ps2kb.c b/kernel/src/arch/i686/drivers/ps2kb.c
new file mode 100644
index 0000000..50bdfb6
--- /dev/null
+++ b/kernel/src/arch/i686/drivers/ps2kb.c
@@ -0,0 +1,124 @@
+#include <panic.h>
+#include <arch/i686/drivers/ps2ctrl.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/asm.h>
+#include <drivers/ps2kb.h>
+
+#define BUFFER_LEN 16
+
+#define KEYCODE_ARRAY_LEN 0x84
+
+static uint8_t scancodes[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12,
+/*08*/ KEY_NONE, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, KEY_NONE,
+/*10*/ KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE,
+/*18*/ KEY_NONE, KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_NONE,
+/*20*/ KEY_NONE, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
+/*28*/ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_NONE,
+/*30*/ KEY_NONE, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_NONE,
+/*38*/ KEY_NONE, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_NONE,
+/*40*/ KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_NONE,
+/*48*/ KEY_NONE, KEY_PERIOD, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
+/*50*/ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, KEY_EQUAL, KEY_NONE, KEY_NONE,
+/*58*/ KEY_CAPS_LOCK, KEY_R_SHIFT, KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
+/*78*/ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_F7,
+};
+static uint8_t scancodes_ext[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*08*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*10*/ KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*18*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_L_META,
+/*20*/ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
+/*28*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_MENU,
+/*30*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*38*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*40*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*48*/ KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*50*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*58*/ KEY_NONE, KEY_NONE, KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
+/*78*/ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, KEY_PAGE_UP, KEY_NONE, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+};
+
+static struct Keycode last_keycode;
+
+static bool is_init = false;
+static bool state_keyup = false;
+static bool state_ext = false;
+
+void ps2kb_init(void) {
+
+ is_init = false;
+ pic_mask(1);
+
+ uint8_t result;
+
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ panic("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if(result != 0xAA) {
+ panic("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
+ return;
+ }
+
+ ps2ctrl_out_data(0xF4);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ panic("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+
+ pic_unmask(1);
+ is_init = true;
+}
+
+void ps2kb_recv(void) {
+ if(!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+ uint8_t code = ps2ctrl_in();
+ if (code == 0x00 || code == 0x0F) {
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = KC_FLAG_ERROR;
+ } else if(code == 0xF0) {
+ state_keyup = true;
+ } else if(code == 0xE0) {
+ state_ext = true;
+ } else if(code <= KEYCODE_ARRAY_LEN) {
+ uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
+ uint8_t keycode = scancode_table[code];
+ if(keycode != KEY_NONE) {
+ last_keycode.key = keycode;
+ last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
+ }
+ state_keyup = false;
+ state_ext = false;
+ }
+}
+
+struct Keycode ps2kb_get(void) {
+ struct Keycode code;
+ if(is_init) {
+ code = last_keycode;
+ } else {
+ code.key = KEY_NONE;
+ code.flags = KC_FLAG_ERROR;
+ }
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = 0;
+ return code;
+}
diff --git a/kernel/src/arch/i686/drivers/ps2mouse.c b/kernel/src/arch/i686/drivers/ps2mouse.c
new file mode 100644
index 0000000..d1082a1
--- /dev/null
+++ b/kernel/src/arch/i686/drivers/ps2mouse.c
@@ -0,0 +1,81 @@
+#include <panic.h>
+#include <arch/i686/drivers/ps2ctrl.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/asm.h>
+#include <drivers/ps2mouse.h>
+
+static bool is_init = false;
+
+static struct MouseEvent last_event;
+static uint8_t first_b, second_b, third_b;
+
+void ps2mouse_init(void) {
+
+ is_init = false;
+ pic_mask(12);
+
+ uint8_t result;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if (result != 0xFA) {
+ panic("Failed to reset PS/2 mouse: expected 0xFA, got 0x%X", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if (result != 0xAA) {
+ panic("Failed to reset PS/2 mouse: expected 0xAA, got 0x%X", result);
+ return;
+ }
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xF4);
+
+ pic_unmask(12);
+ is_init = true;
+}
+
+static uint8_t packet_num = 0;
+void ps2mouse_recv(void) {
+ if (!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+
+ uint8_t packet = ps2ctrl_in();
+ switch (packet_num) {
+ case 0:
+ first_b = packet;
+ break;
+ case 1:
+ second_b = packet;
+ break;
+ case 2: {
+ third_b = packet;
+
+ int state, d;
+ state = first_b;
+ d = second_b;
+ last_event.relx = d - ((state << 4) & 0x100);
+ d = third_b;
+ last_event.rely = d - ((state << 3) & 0x100);
+
+ last_event.lmb = first_b & 0x01;
+ last_event.rmb = first_b & 0x02;
+ last_event.mmb = first_b & 0x04;
+ last_event.updated = true;
+ break;
+ }
+ }
+
+ packet_num += 1;
+ packet_num %= 3;
+
+}
+
+struct MouseEvent ps2mouse_get(void) {
+ struct MouseEvent event = last_event;
+ last_event.updated = false;
+ return event;
+}
diff --git a/kernel/src/arch/i686/drivers/rtc.c b/kernel/src/arch/i686/drivers/rtc.c
new file mode 100644
index 0000000..ba69d15
--- /dev/null
+++ b/kernel/src/arch/i686/drivers/rtc.c
@@ -0,0 +1,152 @@
+#include "time.h"
+#include <stdint.h>
+#include <sys.h>
+#include <arch/i686/drivers/rtc.h>
+#include <arch/i686/asm.h>
+
+#define CMOS_WRITE_PORT 0x70
+#define CMOS_READ_PORT 0x71
+
+#define CMOS_REG_SEC 0x00
+#define CMOS_REG_MIN 0x02
+#define CMOS_REG_HOUR 0x04
+#define CMOS_REG_WDAY 0x06
+#define CMOS_REG_MDAY 0x07
+#define CMOS_REG_MON 0x08
+#define CMOS_REG_YEAR 0x09
+#define CMOS_REG_CEN 0x32
+
+// Live buffers to work on data
+static struct Time time;
+static struct Time localtime;
+
+// Front buffers so interupts dont request data that is half done
+static struct Time cur_time;
+static struct Time cur_localtime;
+
+// Current set Time Zone
+static enum Timezone last_timezone = UTC;
+
+static uint8_t cmos_read(uint8_t reg) {
+ uint8_t hex, ret;
+
+ outb(CMOS_WRITE_PORT, reg);
+ hex = inb(CMOS_READ_PORT);
+
+ ret = hex & 0x0F;
+ ret += (hex & 0xF0) / 16 * 10;
+
+ return ret;
+}
+
+static int mday_offset[12] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static void update_localtime(void) {
+
+ int change, max;
+
+ // set localtime
+ localtime = time;
+
+ // if tz is UTC, we dont need to do anythin
+ if (last_timezone == UTC) {
+ cur_localtime = localtime;
+ return;
+ }
+
+ // check if day rolled over
+ change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
+ if (!change) return;
+
+ // roll over day
+ localtime.hour = (localtime.hour + 24) % 24;
+ localtime.wday = (localtime.wday + change + 7) % 7;
+ localtime.mday += change;
+ localtime.yday += change;
+
+ // check if month rolled over
+ max = month_days[localtime.mon];
+ if (localtime.leap && localtime.mon == 1) max++;
+ change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
+ if (!change) return;
+
+ // roll over month
+ localtime.mon = (localtime.mon + change + 12) % 12;
+
+ // check if year rolled over
+ max = localtime.leap ? 366 : 365;
+ change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
+ if (!change) return;
+
+ // roll over year
+ localtime.yn += change;
+
+ // check if cen rolled over
+ change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
+ if (!change) goto year;
+
+ // roll over cen
+ localtime.cen += change;
+
+
+year:
+
+ localtime.year = localtime.yn + localtime.cen * 100;
+ localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
+
+ if (localtime.leap && localtime.yday == -1)
+ localtime.yday = 365;
+ else if (localtime.yday == -1)
+ localtime.yday = 364;
+ else
+ localtime.yday = 0;
+
+ localtime.year -= 1900;
+
+ cur_localtime = localtime;
+
+}
+
+void rtc_update(void) {
+ time.sec = cmos_read(CMOS_REG_SEC);
+ time.min = cmos_read(CMOS_REG_MIN);
+ time.hour = cmos_read(CMOS_REG_HOUR);
+ time.wday = cmos_read(CMOS_REG_WDAY) - 1;
+ time.mday = cmos_read(CMOS_REG_MDAY);
+ time.mon = cmos_read(CMOS_REG_MON) - 1;
+ time.yn = cmos_read(CMOS_REG_YEAR);
+ time.cen = 20;
+
+ time.year = time.yn + time.cen * 100;
+
+ time.leap = time.year % 4 == 0 && time.year % 100 != 0;
+
+ time.yday = mday_offset[time.mon] + time.mday;
+
+ if (time.leap && time.mon > 2)
+ time.yday++;
+
+ time.year -= 1900;
+
+ update_localtime();
+
+ cur_time = time;
+}
+
+struct Time rtc_utctime(void) {
+ return cur_time;
+}
+
+struct Time rtc_localtime(enum Timezone tz) {
+ if (tz != last_timezone) {
+ last_timezone = tz;
+ update_localtime();
+ }
+ return cur_localtime;
+}
diff --git a/kernel/src/arch/i686/drivers/vga.c b/kernel/src/arch/i686/drivers/vga.c
new file mode 100644
index 0000000..a41ce54
--- /dev/null
+++ b/kernel/src/arch/i686/drivers/vga.c
@@ -0,0 +1,50 @@
+#include <arch/i686/asm.h>
+#include <drivers/vga.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+static uint16_t *buffer = (uint16_t*) 0xC03FF000;
+static uint8_t start, end;
+
+void vgatext_write(char c, enum vga_color color, uint8_t x, uint8_t y) {
+ const size_t index = y * VGA_TEXT_W + x;
+ buffer[index] = c | (uint16_t) color << 8;
+}
+
+void vgatext_write_data(uint16_t data, uint16_t index) {
+ buffer[index] = data;
+}
+
+void vgatext_write_buf(const uint16_t *src) {
+ memcpy(buffer, src, VGA_TEXT_W * VGA_TEXT_H * sizeof(uint16_t));
+}
+
+void vgatext_cur_mov(uint8_t x, uint8_t y) {
+; const uint16_t pos = y * VGA_TEXT_W + x;
+
+ outb(0x3D4, 0x0F);
+ outb(0x3D5, (uint8_t) (pos & 0xFF));
+ outb(0x3D4, 0x0E);
+ outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
+}
+
+void vgatext_cur_resize(uint8_t s, uint8_t e) {
+ start = s;
+ end = e;
+
+ outb(0x3D4, 0x0A);
+ outb(0x3D5, (inb(0x3D5) & 0xC0) | start);
+
+ outb(0x3D4, 0x0B);
+ outb(0x3D5, (inb(0x3D5) & 0xE0) | end);
+}
+
+void vgatext_cur_visible(bool visible) {
+ if (visible) {
+ vgatext_cur_resize(start, end);
+ } else {
+ outb(0x3D4, 0x0A);
+ outb(0x3D5, 0x20);
+ }
+}
diff --git a/kernel/src/arch/i686/gdt.asm b/kernel/src/arch/i686/gdt.asm
new file mode 100644
index 0000000..ea8a86b
--- /dev/null
+++ b/kernel/src/arch/i686/gdt.asm
@@ -0,0 +1,42 @@
+global load_gdt
+
+%macro gdt_entry 4
+ db %2 & 0xff
+ db (%2 >> 8) & 0xff
+ db %1 & 0xff
+ db (%1 >> 8) & 0xff
+ db (%1 >> 16) & 0xff
+ db %3
+ db ((%2 >> 16) & 0x0f) | (%4 << 4)
+ db (%1 >> 24) & 0xff
+%endmacro
+
+section .rodata
+align 16
+gdt_start:
+gdt_entry 0, 0, 0, 0
+gdt_entry 0, 0xFFFFF, 0x9A, 0xC
+gdt_entry 0, 0xFFFFF, 0x92, 0xC
+gdt_end:
+gdt_descriptor:
+ dw gdt_end - gdt_start - 1
+ dd gdt_start
+
+
+section .text
+align 8
+load_gdt:
+ cli
+ lgdt [gdt_descriptor]
+ mov eax, cr0
+ or al, 1
+ mov cr0, eax
+ mov ax, 0x10
+ mov ds, ax
+ mov ss, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ jmp 0x08:after_gdt
+after_gdt:
+ ret
diff --git a/kernel/src/arch/i686/idt.asm b/kernel/src/arch/i686/idt.asm
new file mode 100644
index 0000000..6cccdc6
--- /dev/null
+++ b/kernel/src/arch/i686/idt.asm
@@ -0,0 +1,99 @@
+extern idt_exception_handler
+extern idt_pic_timer
+extern idt_pic_keyboard
+extern idt_pic_mouse
+extern idt_pic_eoi
+global isr_stub_table
+
+%macro ISRErrorStub 1
+isr_stub_%+%1:
+ push dword %1
+ call idt_exception_handler
+ pop eax
+ iret
+%endmacro
+
+%macro PICGeneric 1
+isr_stub_%+%1:
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICTimer 1
+isr_stub_%+%1:
+ call idt_pic_timer
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICKeyboard 1
+isr_stub_%+%1:
+ call idt_pic_keyboard
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro PICMouse 1
+isr_stub_%+%1:
+ call idt_pic_mouse
+ push dword %1
+ call idt_pic_eoi
+ pop eax
+ iret
+%endmacro
+
+%macro ISRSyscall 1
+isr_stub_%+%1:
+ push eax
+ push ebx
+ push ecx
+ push edx
+ call idt_syscall
+ add esp, 16
+ pop eax
+ iret
+%endmacro
+
+section .text
+align 8
+%assign i 0
+%rep 32
+ ISRErrorStub i
+%assign i i+1
+%endrep
+PICTimer 32 ; 0
+PICKeyboard 33 ; 1
+PICGeneric 34 ; 2
+PICGeneric 35 ; 3
+PICGeneric 36 ; 4
+PICGeneric 37 ; 5
+PICGeneric 38 ; 6
+PICGeneric 39 ; 7
+PICGeneric 40 ; 8
+PICGeneric 41 ; 9
+PICGeneric 42 ; 10
+PICGeneric 43 ; 11
+PICMouse 44 ; 12
+PICGeneric 45 ; 13
+PICGeneric 46 ; 14
+PICGeneric 47 ; 15
+%assign i 48
+%rep 256 - 48
+ ISRErrorStub i
+%assign i i+1
+%endrep
+
+section .rodata
+align 8
+isr_stub_table:
+%assign i 0x00
+%rep 256
+ dd isr_stub_%+i
+%assign i i+0x01
+%endrep
diff --git a/kernel/src/arch/i686/idt.c b/kernel/src/arch/i686/idt.c
new file mode 100644
index 0000000..04fd5f8
--- /dev/null
+++ b/kernel/src/arch/i686/idt.c
@@ -0,0 +1,140 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys.h>
+#include <print.h>
+#include <panic.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/idt.h>
+#include <time.h>
+#include <drivers/ps2kb.h>
+#include <drivers/ps2mouse.h>
+
+#include "tty/term.h"
+
+struct IdtEntry {
+ uint16_t isr_low;
+ uint16_t kernel_cs;
+ uint8_t _reserved;
+ uint8_t attributes;
+ uint16_t isr_high;
+} __attribute__((packed));
+
+struct Idtr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+enum IDTFlags {
+ IDT_FLAG_GATE_TASK = 0x5,
+ IDT_FLAG_GATE_16BIT_INT = 0x6,
+ IDT_FLAG_GATE_16BIT_TRAP = 0x7,
+ IDT_FLAG_GATE_32BIT_INT = 0xE,
+ IDT_FLAG_GATE_32BIT_TRAP = 0xF,
+
+ IDT_FLAG_RING0 = (0 << 5),
+ IDT_FLAG_RING1 = (1 << 5),
+ IDT_FLAG_RING2 = (2 << 5),
+ IDT_FLAG_RING3 = (3 << 5),
+
+ IDT_FLAG_PRESENT = 0x80,
+};
+
+#define WIDTH 30
+static char buf[WIDTH];
+static int timer = -1;
+
+void idt_pic_eoi(uint8_t exception) {
+ pic_eoi(exception - PIC_REMAP_OFFSET);
+}
+
+void idt_pic_timer(void) {
+
+ timer += 1;
+ if (timer % 20 != 0) return;
+
+ uint32_t state = term_save();
+
+ term_setfg(VGA_LIGHT_GREEN);
+ term_setpos(TERM_W - WIDTH - 1, 0);
+ for (size_t i = 0; i < WIDTH; i++) putchar(' ');
+ term_setpos(TERM_W - WIDTH - 1, 0);
+
+ struct Time t = get_localtime();
+ timetostr(&t, "%a %b %d %Y %H:%M:%S", buf, WIDTH);
+ printk("%s", buf);
+
+ term_load(state);
+}
+
+void idt_pic_keyboard(void) {
+ ps2kb_recv();
+}
+
+void idt_pic_mouse(void) {
+ ps2mouse_recv();
+}
+
+void idt_exception_handler(uint8_t exception) {
+ char* msg;
+ switch(exception) {
+ case 0x00:
+ msg = "Division by zero";
+ break;
+ case 0x02:
+ msg = "NMI";
+ break;
+ case 0x04:
+ msg = "Overflow";
+ break;
+ case 0x06:
+ msg = "invalid opcode";
+ break;
+ case 0x08:
+ msg = "double fault";
+ break;
+ case 0x0A:
+ msg = "invalid task state segment";
+ break;
+ case 0x0C:
+ msg = "stack segment fault";
+ break;
+ case 0x0D:
+ msg = "general protection fault";
+ break;
+ case 0x0E:
+ msg = "page fault";
+ break;
+ default:
+ msg = "unknown exception";
+ break;
+ }
+ panic("E%u: %s", exception, msg);
+}
+
+__attribute__((aligned(0x10)))
+static struct IdtEntry idt[256];
+static struct Idtr idtr;
+extern void* isr_stub_table[];
+
+static void set_descriptor(uint8_t vector, void* isr, uint8_t flags) {
+ struct IdtEntry* entry = &idt[vector];
+ entry->isr_low = (size_t)isr & 0xffff;
+ entry->kernel_cs = 0x08;
+ entry->attributes = flags;
+ entry->isr_high = (size_t)isr >> 16;
+ entry->_reserved = 0;
+}
+
+void idt_init(void) {
+ idtr.base = (uintptr_t)&idt[0];
+ idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
+
+ for(int i = 0; i < IDT_INTERRUPTS; i++) {
+ set_descriptor(i, isr_stub_table[i], 0x8e);
+ }
+
+ __asm__ volatile ("lidt %0" : : "m"(idtr));
+}
+
diff --git a/kernel/src/arch/i686/mboot.c b/kernel/src/arch/i686/mboot.c
new file mode 100644
index 0000000..108812f
--- /dev/null
+++ b/kernel/src/arch/i686/mboot.c
@@ -0,0 +1,73 @@
+#include <panic.h>
+#include <string.h>
+#include <arch/i686/mboot.h>
+#include <arch/i686/memory.h>
+#include <arch/i686/acpi.h>
+
+static struct BootInfo info;
+
+static void read_cmdline(struct BootTag *tag, char *data, uint8_t len) {
+ if (len >= CMDLINE_MAX)
+ panic("multiboot2 cmd line to long\nmax is %d but was provided %d\n",
+ CMDLINE_MAX, len);
+ memcpy(tag->data.cmdline, data, len);
+ info.tags[ID_CMDLINE] = *tag;
+}
+
+static void read_memorymap(struct BootTag *tag, uint32_t *data) {
+ tag->data.memory_map = (struct MemoryMap *) data;
+ info.tags[iD_MEMORYMAP] = *tag;
+}
+
+static void read_rsdp(struct BootTag *tag, char *data) {
+ tag->data.rsdp = (struct RootSystemDescriptionPointer *) data;
+ info.tags[ID_RSDP] = *tag;
+}
+
+static uint32_t *read_tag(uint32_t *data) {
+ struct BootTag tag;
+ tag.type = ((uint16_t*)data)[0];
+ tag.size = data[1];
+ tag.valid = 1;
+
+ uint8_t data_len = tag.size - 2 * sizeof(uint32_t);
+
+ switch (tag.type) {
+ case ID_CMDLINE:
+ read_cmdline(&tag, (char *)(data + 2), data_len);
+ break;
+ case iD_MEMORYMAP:
+ read_memorymap(&tag, data + 2);
+ break;
+ case ID_RSDP:
+ read_rsdp(&tag, (char *) (data + 2));
+ break;
+ default:
+ break;
+ }
+
+ if(tag.size % 8 != 0) {
+ tag.size += 8 - (tag.size % 8);
+ }
+
+ return data + tag.size / sizeof(uint32_t);
+}
+
+void load_boot_info(void* boot_info) {
+
+ memset(&info, 0, sizeof(boot_info));
+
+ uint32_t* data = (uint32_t*) boot_info;
+ info.total_size = *data++;
+ info.reserved = *data++;
+
+ while((uint8_t*) data < (uint8_t*) boot_info + info.total_size) {
+ data = read_tag(data);
+ }
+
+}
+
+bool get_boot_tag(enum BootTagID id, struct BootTag **tag) {
+ *tag = &info.tags[id];
+ return (*tag)->valid;
+}
diff --git a/kernel/src/arch/i686/memory.c b/kernel/src/arch/i686/memory.c
new file mode 100644
index 0000000..29f1f56
--- /dev/null
+++ b/kernel/src/arch/i686/memory.c
@@ -0,0 +1,197 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys.h>
+#include <panic.h>
+#include <arch/i686/memory.h>
+#include <arch/i686/mboot.h>
+
+struct MemoryArea {
+ uint32_t len;
+ struct MemoryArea *prev;
+ struct MemoryArea *next;
+};
+
+typedef unsigned char page[4096];
+
+extern unsigned char kernel_start, kernel_end;
+static uintptr_t kernel_start_addr, kernel_end_addr;
+static uint32_t *bitmap;
+static uint32_t total_memory;
+static uint32_t free_memory;
+static uint32_t page_count;
+static uint32_t page_free_start;
+static struct MemoryArea *page_start;
+
+int memory_lock(void) {
+ // int_disable();
+ return 0;
+}
+
+int memory_unlock(void) {
+ // int_enable();
+ return 0;
+}
+
+static int n_pages(const struct MemoryArea *m) {
+ return (m->len - sizeof(*m)) / sizeof(page);
+}
+
+static void *page_at(int i) {
+ int cur_page = 0;
+ for (struct MemoryArea *m = page_start; m != NULL; m = m->next) {
+ int pages = n_pages(m);
+ if (i - cur_page < pages) {
+ page *page_array = (page *) (m + 1);
+ return page_array[i - cur_page];
+ }
+ cur_page += pages;
+ }
+ return NULL;
+}
+
+static int page_idx(page p) {
+ uintptr_t addr = (uintptr_t) p;
+ int cur_page = 0;
+ for (struct MemoryArea *m = page_start; m != NULL; m = m->next) {
+ if ((uintptr_t) m + m->len > addr) {
+ return cur_page + (addr - (uintptr_t) m) / sizeof(page);
+ }
+ cur_page += n_pages(m);
+ }
+ return -1;
+}
+
+static inline bool bitmap_get(int i) {
+ return (bitmap[i / 32] >> i % 32) & 1;
+}
+
+static inline void bitmap_set(int i, bool v) {
+ int idx = i / 32;
+ bitmap[idx] &= ~(1 << i % 32);
+ bitmap[idx] |= (v << i % 32);
+}
+
+void *memory_alloc_page(int pages) {
+ if (pages < 1) return NULL;
+
+ int n_contiguous = 0;
+ int free_region_start = 0;
+ bool first = true;
+ for (uint32_t i = page_free_start; i < page_count; i++) {
+ bool free = !bitmap_get(i);
+
+ if (first) {
+ first = false;
+ page_free_start = i;
+ }
+
+ if (free) {
+ if (n_contiguous == 0) free_region_start = i;
+ n_contiguous++;
+ if (n_contiguous == pages) {
+ for (int j = 0; j < pages; j++)
+ bitmap_set(free_region_start + j, true);
+ return page_at(free_region_start);
+ }
+ } else n_contiguous = 0;
+ }
+
+ return NULL;
+}
+
+int memory_free_page(void *ptr, int pages) {
+ int idx = page_idx(ptr);
+ if (idx == -1) return 1;
+
+ if ((unsigned) idx < page_free_start) page_free_start = idx;
+
+ for (int i = 0; i < pages; i++)
+ bitmap_set(idx + pages, false);
+ return 0;
+}
+
+void memory_init(void) {
+
+ memory_lock();
+
+ bitmap = NULL;
+ total_memory = 0;
+ free_memory = 0;
+ page_count = 0;
+ page_free_start = 0;
+ page_start = NULL;
+
+ kernel_start_addr = (uintptr_t) &kernel_start;
+ kernel_end_addr = (uintptr_t) &kernel_end;
+
+ struct BootTag *tag;
+ if (!get_boot_tag(iD_MEMORYMAP, &tag)) {
+ panic("No multiboot memory map found");
+ }
+
+ uintptr_t end = (uintptr_t) tag->data.memory_map;
+ end += tag->size;
+
+ struct MemoryArea *prev = NULL;
+ struct MemorySegment *segment = &tag->data.memory_map->entries[0];
+ for(; (uintptr_t) segment < end; segment++) {
+
+ if (segment->type != 1) continue;
+ if (segment->addr >= UINT32_MAX) continue;
+ if (segment->addr < kernel_start_addr) continue;
+
+ uint32_t length;
+ if (segment->addr + segment->len > UINT32_MAX) {
+ length = UINT32_MAX - segment->addr;
+ } else {
+ length = segment->len;
+ }
+
+ uintptr_t addr;
+ if (segment->addr < kernel_end_addr) {
+ addr = kernel_end_addr;
+ length -= addr - segment->addr;
+ } else {
+ addr = segment->addr;
+ }
+
+ struct MemoryArea *current = (struct MemoryArea *) addr;
+ current->prev = prev;
+ current->next = NULL;
+ current->len = length;
+
+ if (prev != NULL) {
+ prev->next = current;
+ } else {
+ page_start = current;
+ }
+
+ page_count += n_pages(current);
+ total_memory += length;
+
+ prev = current;
+
+ }
+
+ int bitmap_pages = page_count / 32 / sizeof(page) + 1;
+ bitmap = (uint32_t *) page_at(page_count - bitmap_pages);
+ page_count -= bitmap_pages;
+ memset(bitmap, 0, bitmap_pages * sizeof(page));
+ free_memory = page_count * sizeof(page);
+
+ memory_unlock();
+
+}
+
+uint32_t memory_total(void) {
+ return total_memory;
+}
+
+uint32_t memory_free(void) {
+ return free_memory;
+}
+
+uint32_t memory_used(void) {
+ return total_memory - free_memory;
+}
diff --git a/kernel/src/arch/i686/paging.asm b/kernel/src/arch/i686/paging.asm
new file mode 100644
index 0000000..f74cc55
--- /dev/null
+++ b/kernel/src/arch/i686/paging.asm
@@ -0,0 +1,62 @@
+global page_directory
+global paging_init
+global paging_finish
+global KERNEL_MAPPING
+
+KERNEL_MAPPING equ 0xC0000000
+VGABUF equ 0x000B8000
+
+section .bss
+align 4096
+page_directory:
+resb 4096
+page_table1:
+resb 4096
+
+section .bootstrap.text
+align 8
+paging_init:
+ extern kernel_start
+ extern kernel_end
+
+paging_load:
+ mov edi, page_table1 - KERNEL_MAPPING
+ mov esi, 0
+ mov ecx, 1023
+
+paging_cmp:
+ cmp esi, kernel_start
+ jl paging_add
+ cmp esi, kernel_end - KERNEL_MAPPING
+ jge paging_map
+
+ mov edx, esi
+ or edx, 0x003
+ mov [edi], edx
+
+paging_add:
+ add esi, 4096
+ add edi, 4
+ loop paging_cmp
+
+paging_map:
+ mov dword [page_table1 - KERNEL_MAPPING + 1023 * 4], VGABUF | 0x003
+ mov dword [page_directory - KERNEL_MAPPING + 0], page_table1 - KERNEL_MAPPING + 0x003
+ mov dword [page_directory - KERNEL_MAPPING + 768 * 4], page_table1 - KERNEL_MAPPING + 0x003
+
+ mov ecx, page_directory - KERNEL_MAPPING
+ mov cr3, ecx
+
+ mov ecx, cr0
+ or ecx, 0x80010000
+ mov cr0, ecx
+
+ ret
+
+section .text
+align 8
+paging_finish:
+ mov dword [page_directory], 0
+ mov ecx, cr3
+ mov cr3, ecx
+ ret
diff --git a/kernel/src/arch/i686/pic.c b/kernel/src/arch/i686/pic.c
new file mode 100644
index 0000000..f5d0f94
--- /dev/null
+++ b/kernel/src/arch/i686/pic.c
@@ -0,0 +1,80 @@
+#include <sys.h>
+#include <print.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/asm.h>
+
+#define PIC1_COMMAND_PORT 0x20
+#define PIC1_DATA_PORT 0x21
+#define PIC2_COMMAND_PORT 0xA0
+#define PIC2_DATA_PORT 0xA1
+
+void pic_remap(void) {
+ char a1 = inb(PIC1_DATA_PORT);
+ char a2 = inb(PIC2_DATA_PORT);
+ // control word 1
+ // 0x11: initialize, enable ICW4
+ outb(PIC1_COMMAND_PORT, 0x11);
+ io_wait();
+ outb(PIC2_COMMAND_PORT, 0x11);
+ io_wait();
+ // control word 2
+ // interrupt offset
+ outb(PIC1_DATA_PORT, PIC_REMAP_OFFSET);
+ io_wait();
+ outb(PIC2_DATA_PORT, PIC_REMAP_OFFSET + 8);
+ io_wait();
+ // control word 3
+ // primary pic: set which pin secondary is connected to
+ // (pin 2)
+ outb(PIC1_DATA_PORT, 0x04);
+ io_wait();
+ outb(PIC2_DATA_PORT, 2);
+ io_wait();
+ // control word 3
+ // 0x01: enable 8086 mode
+ outb(PIC1_DATA_PORT, 0x01);
+ io_wait();
+ outb(PIC2_DATA_PORT, 0x01);
+ io_wait();
+ // clear data registers
+ outb(PIC1_DATA_PORT, a1);
+ outb(PIC2_DATA_PORT, a2);
+}
+
+void pic_mask(int irq) {
+ uint8_t port;
+ if(irq < 8) {
+ port = PIC1_DATA_PORT;
+ } else {
+ irq -= 8;
+ port = PIC2_DATA_PORT;
+ }
+ uint8_t mask = inb(port);
+ outb(port, mask | (1 << irq));
+}
+
+void pic_unmask(int irq) {
+ uint8_t port;
+ if(irq < 8) {
+ port = PIC1_DATA_PORT;
+ } else {
+ irq -= 8;
+ port = PIC2_DATA_PORT;
+ }
+ uint8_t mask = inb(port);
+ outb(port, mask & ~(1 << irq));
+}
+
+void pic_disable(void) {
+ outb(PIC1_DATA_PORT, 0xff);
+ io_wait();
+ outb(PIC2_DATA_PORT, 0xff);
+ io_wait();
+}
+
+void pic_eoi(int irq) {
+ if(irq >= 8) {
+ outb(PIC2_COMMAND_PORT, 0x20);
+ }
+ outb(PIC1_COMMAND_PORT, 0x20);
+}
diff --git a/kernel/src/arch/i686/start.asm b/kernel/src/arch/i686/start.asm
new file mode 100644
index 0000000..2151b51
--- /dev/null
+++ b/kernel/src/arch/i686/start.asm
@@ -0,0 +1,82 @@
+global start
+bits 32
+
+
+; create the multiboot header
+section .bootstrap.data
+align 8
+mb_start:
+dd 0xe85250d6
+dd 0
+dd mb_end - mb_start
+dd -(0xe85250d6 + (mb_end - mb_start))
+dw 0
+dw 0
+dd 8
+mb_end:
+
+
+; create the stack for bootstrapping
+section .bootstrap.stack
+align 16
+bootstrap_stack_start:
+resb 1024 ; 1 KiB
+bootstrap_stack_end:
+
+
+; create the stack for the kernel
+section .stack
+align 16
+stack_start:
+resb 16384 ; 16 KiB
+stack_end:
+
+
+; load the kernel into the higher half
+section .bootstrap.text
+align 8
+start:
+ ; init bootstrap stack
+ mov esp, bootstrap_stack_end
+ mov ebp, bootstrap_stack_end
+
+ ; load kernel into higher half and init paging
+ extern paging_init
+ call paging_init
+
+ jmp near load_kernel
+
+; initalize kernel after it has been loaded in higher half
+section .text
+align 8
+load_kernel:
+ ; init stack
+ mov esp, stack_end
+ mov ebp, stack_end
+
+ ; load global descripter table
+ extern load_gdt
+ call load_gdt
+
+ ; unmap kernel at page 0
+ extern paging_finish
+ call paging_finish
+
+ ; initalize the FPU
+ finit
+
+ ; push multiboot header
+ extern KERNEL_MAPPING
+ add ebx, KERNEL_MAPPING
+ push ebx
+
+ ; start kernel
+ sti
+ call kernel_main
+ extern kernel_main
+
+ ; hlt forever if kernel quits (it should never)
+ cli
+halt:
+ hlt
+ jmp halt
diff --git a/kernel/src/arch/i686/sys.c b/kernel/src/arch/i686/sys.c
new file mode 100644
index 0000000..209fea4
--- /dev/null
+++ b/kernel/src/arch/i686/sys.c
@@ -0,0 +1,51 @@
+#include <sys.h>
+#include <arch/i686/asm.h>
+#include <arch/i686/acpi.h>
+#include <arch/i686/drivers/rtc.h>
+#include <arch/i686/idt.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/mboot.h>
+#include <arch/i686/drivers/ps2ctrl.h>
+
+void arch_init(void *boot_info) {
+ rtc_update();
+
+ idt_init();
+ pic_remap();
+
+ load_boot_info(boot_info);
+
+ /* havent refactored to work with paging yet */
+ // acpi_init();
+ // memory_init();
+
+ ps2ctrl_init();
+}
+
+extern void arch_update(void) {
+ rtc_update();
+}
+
+void arch_halt(void) {
+ halt();
+}
+
+void arch_wait_io(void) {
+ io_wait();
+}
+
+void arch_disable_int(void) {
+ int_disable();
+}
+
+void arch_enable_int(void) {
+ int_enable();
+}
+
+extern void arch_wait_int(void) {
+ int_wait();
+}
+
+void arch_poweroff(void) {
+ acpi_poweroff();
+}
diff --git a/kernel/src/arch/i686/time.c b/kernel/src/arch/i686/time.c
new file mode 100644
index 0000000..66fabc1
--- /dev/null
+++ b/kernel/src/arch/i686/time.c
@@ -0,0 +1,17 @@
+#include <time.h>
+#include <arch/i686/drivers/rtc.h>
+
+static enum Timezone cur_tz = UTC;
+
+struct Time get_utctime(void) {
+ return rtc_utctime();
+}
+
+struct Time get_localtime(void) {
+ return rtc_localtime(cur_tz);
+}
+
+void set_timezone(enum Timezone tz) {
+ cur_tz = tz;
+}
+