Move to kernel/
diff --git a/src/kernel/.gdbinit b/src/kernel/.gdbinit
new file mode 100644
index 0000000..24efe1e
--- /dev/null
+++ b/src/kernel/.gdbinit
@@ -0,0 +1 @@
+target remote localhost:1234
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
new file mode 100644
index 0000000..f369294
--- /dev/null
+++ b/src/kernel/Makefile
@@ -0,0 +1,51 @@
+SOURCES = boot.o \
+ main.o \
+ descriptor_tables.o \
+ io.o \
+ vga.o \
+ gdt_flush.o \
+ idt.o \
+ log.o \
+ irq.o \
+ pic.o \
+ timer.o \
+ paging.o \
+ switch_table.o \
+ scan_codes.o
+CFLAGS = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 -O2 -g
+LDFLAGS = -Tlink.ld -melf_i386
+ASMFLAGS = -felf
+QEMUFLAGS = -d cpu_reset
+
+JAYROOT = ../../
+
+kernel.elf: $(SOURCES)
+ ld $(LDFLAGS) -o $@ $^
+
+clean:
+ rm -f *.o *.bin *.elf $(JAYROOT)/bin/*.iso
+
+debug: kernel.elf
+ qemu-system-i386 -s -S -kernel kernel.elf &
+ @echo run "target remote localhost:1234" to connect to qemu
+ gdb
+ @pkill qemu-system-i38
+
+qemu: kernel.elf
+ qemu-system-i386 $(QEMUFLAGS) -monitor stdio -kernel kernel.elf -no-reboot
+
+qemu-iso: install
+ qemu-system-i386 $(QEMUFLAGS) -monitor stdio $(JAYROOT)/bin/bluejay.iso
+
+scan_codes.c: gen_scan_codes.py scan_codes.tsv
+ python3 $< > $@
+
+.s.o:
+ nasm $(ASMFLAGS) $<
+
+install: kernel.elf
+ cp kernel.elf ../boot/
+ rm -f $(JAYROOT)/bin/bluejay.iso
+ grub-mkrescue -o $(JAYROOT)/bin/bluejay.iso ..
+
+.PHONY: install qemu clean qemu-iso debug
diff --git a/src/kernel/boot.s b/src/kernel/boot.s
new file mode 100644
index 0000000..c71ef40
--- /dev/null
+++ b/src/kernel/boot.s
@@ -0,0 +1,37 @@
+;;; GRUB Multiboot header, calls main() in main.c
+
+MBOOT_PAGE_ALIGN equ 1<<0
+MBOOT_MEM_INFO equ 1<<1
+MBOOT_HEADER_MAGIC equ 0x1BADB002
+
+MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
+MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
+
+
+ [bits 32]
+
+ [global mboot]
+ [extern code]
+ [extern bss]
+ [extern end]
+
+mboot:
+ dd MBOOT_HEADER_MAGIC ; This tells GRUB to start executing here:
+ dd MBOOT_HEADER_FLAGS
+ dd MBOOT_CHECKSUM
+
+ dd mboot ; Current location
+ dd code ; .text section
+ dd bss ; End of .data
+ dd end ; End of kernel
+ dd start
+
+ [global start]
+ [extern kmain] ; C code
+
+start:
+ push ebx ; Holds multiboot header location
+
+ cli
+ call kmain
+ jmp $
diff --git a/src/kernel/descriptor_tables.c b/src/kernel/descriptor_tables.c
new file mode 100644
index 0000000..916a1ae
--- /dev/null
+++ b/src/kernel/descriptor_tables.c
@@ -0,0 +1,111 @@
+#include "descriptor_tables.h"
+#include "io.h"
+#include "log.h"
+#include "pic.h"
+#include "vga.h"
+
+extern void gdt_flush(uint gdt);
+extern void idt_flush(uint idt);
+
+static void gdt_set_gate(uint i, uint base, uint limit, uchar access,
+ uchar gran);
+static void idt_set_gate(uchar num, uint base, ushort selector, uchar flags);
+
+struct gdt_entry gdt_entries[5];
+struct gdt_pointer gdt_pointer;
+
+struct idt_entry idt_entries[256];
+struct idt_pointer idt_pointer;
+
+static void (*isrs[32])() = {
+ isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8, isr9, isr10,
+ isr11, isr12, isr13, isr14, isr15, isr16, isr17, isr18, isr19, isr20, isr21,
+ isr22, isr23, isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31};
+
+static void (*irqs[16])() = {irq0, irq1, irq2, irq3, irq4, irq5,
+ irq6, irq7, irq8, irq9, irq10, irq11,
+ irq12, irq13, irq14, irq15};
+
+extern void (*interrupt_handlers[256])(struct registers);
+
+void init_gdt()
+{
+ vga_write("Initializing GDT...\n");
+ gdt_pointer.limit = sizeof(struct gdt_entry) * 5 - 1;
+ gdt_pointer.base = (uint)&gdt_entries;
+
+ gdt_set_gate(0, 0, 0, 0, 0); // Null segment
+ gdt_set_gate(1, 0, ~0, 0x9a, 0xcf); // Code segment
+ gdt_set_gate(2, 0, ~0, 0x92, 0xcf); // Data segment
+ gdt_set_gate(3, 0, ~0, 0xfa, 0xcf); // User mode code segment
+ gdt_set_gate(4, 0, ~0, 0xf2, 0xcf); // User mode data segment
+
+ for (volatile uint i = 0; i < 0x1000; i++)
+ {
+ } // waste some time, for some reason this helps
+
+ gdt_flush((uint)&gdt_pointer);
+
+ vga_write("GDT Initialized\n");
+}
+
+static void gdt_set_gate(uint i, uint base, uint limit, uchar access,
+ uchar gran)
+{
+ struct gdt_entry *e = &gdt_entries[i];
+
+ e->base_low = base & 0xffff;
+ e->base_middle = (base >> 16) & 0xff;
+ e->base_high = (base >> 24) & 0xff;
+
+ e->limit_low = limit & 0xffff;
+ e->granularity = ((limit >> 16) & 0x0f) | (gran & 0xf0);
+
+ e->access = access;
+}
+
+void init_idt()
+{
+ idt_pointer.limit = sizeof(struct idt_entry) * 256 - 1;
+ idt_pointer.base = (uint)&idt_entries;
+
+ memset(&idt_entries, 0, sizeof(idt_entries));
+
+ // Remap PIC
+ pic_remap();
+
+ vga_set_color(CYAN, BLACK);
+ for (int i = 0; i < 16; i++)
+ {
+ idt_set_gate(IRQ_TO_INT(i), (uint)irqs[i], 0x08, 0x8e);
+ }
+ vga_set_color(WHITE, BLACK);
+
+ for (int i = 0; i < 32; i++)
+ {
+ idt_set_gate(i, (uint)isrs[i], 0x08, 0x8e);
+ }
+
+ idt_flush((uint)&idt_pointer);
+
+ vga_write("IDT Initialized!\n");
+}
+
+static void idt_set_gate(uchar num, uint base, ushort selector, uchar flags)
+{
+ struct idt_entry *e = &idt_entries[num];
+
+ e->base_low = base & 0xffff;
+ e->base_high = (base >> 16) & 0xffff;
+
+ e->selector = selector;
+ e->zero = 0;
+ e->flags = flags /* | 0x60 */;
+}
+
+void init_descriptor_tables()
+{
+ init_gdt();
+ init_idt();
+ memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
+}
diff --git a/src/kernel/descriptor_tables.h b/src/kernel/descriptor_tables.h
new file mode 100644
index 0000000..b35f670
--- /dev/null
+++ b/src/kernel/descriptor_tables.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#include "kint.h"
+
+struct gdt_entry
+{
+ ushort limit_low;
+ ushort base_low;
+ uchar base_middle;
+
+ union {
+ struct
+ {
+ uint a_p : 1;
+ uint a_dpl : 2;
+ uint a_dt : 1;
+ uint a_type : 4;
+ } __attribute__((packed));
+
+ uchar access;
+ };
+
+ union {
+ struct
+ {
+ uint g_g : 1;
+ uint g_d : 1;
+ uint g_zero : 2; /* includes A */
+ uint g_len : 4;
+ } __attribute__((packed));
+
+ uchar granularity;
+ };
+
+ uchar base_high;
+} __attribute__((packed));
+
+struct gdt_pointer
+{
+ /* Upper 16 bits of selector limits */
+ ushort limit;
+ /* first struct gdt_entry */
+ uint base;
+} __attribute__((packed));
+
+struct idt_entry
+{
+ ushort base_low;
+ ushort selector;
+ uchar zero;
+
+ union {
+ struct
+ {
+ uchar f_p : 1;
+ uchar f_dpl : 2;
+ uchar f_const : 5;
+ } __attribute__((packed));
+
+ uchar flags;
+ };
+
+ ushort base_high;
+} __attribute__((packed));
+
+#define IDT_F_CONST 0b00110
+
+struct idt_pointer
+{
+ ushort limit;
+ uint base;
+} __attribute__((packed));
+
+extern void isr0();
+extern void isr1();
+extern void isr2();
+extern void isr3();
+extern void isr4();
+extern void isr5();
+extern void isr6();
+extern void isr7();
+extern void isr8();
+extern void isr9();
+extern void isr10();
+extern void isr11();
+extern void isr12();
+extern void isr13();
+extern void isr14();
+extern void isr15();
+extern void isr16();
+extern void isr17();
+extern void isr18();
+extern void isr19();
+extern void isr20();
+extern void isr21();
+extern void isr22();
+extern void isr23();
+extern void isr24();
+extern void isr25();
+extern void isr26();
+extern void isr27();
+extern void isr28();
+extern void isr29();
+extern void isr30();
+extern void isr31();
+
+extern void irq0();
+extern void irq1();
+extern void irq2();
+extern void irq3();
+extern void irq4();
+extern void irq5();
+extern void irq6();
+extern void irq7();
+extern void irq8();
+extern void irq9();
+extern void irq10();
+extern void irq11();
+extern void irq12();
+extern void irq13();
+extern void irq14();
+extern void irq15();
+
+void init_descriptor_tables();
+void init_idt();
+void init_gdt();
diff --git a/src/kernel/gdt_flush.s b/src/kernel/gdt_flush.s
new file mode 100644
index 0000000..f1dd8ac
--- /dev/null
+++ b/src/kernel/gdt_flush.s
@@ -0,0 +1,17 @@
+ [bits 32]
+ [global gdt_flush]
+
+gdt_flush:
+ mov eax, [esp + 4]
+ lgdt [eax] ; Load GDT
+
+ mov ax, 0x10 ; Offset of data segment
+ mov ds, ax,
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ jmp 0x08:.flush ; Implicitly reloads the code segment
+.flush:
+ ret
diff --git a/src/kernel/gen_scan_codes.py b/src/kernel/gen_scan_codes.py
new file mode 100644
index 0000000..6bf68c9
--- /dev/null
+++ b/src/kernel/gen_scan_codes.py
@@ -0,0 +1,48 @@
+# Generate scan_codes.h from scan_codes.tsv
+
+from functools import reduce
+
+def symbolify(s):
+ if not s.startswith("'"):
+ return s.replace('+', 'PLUS').replace('*', 'TIMES').replace('/', 'DIV').replace('-', 'MINUS').replace('.', 'DOT')
+ else: return s
+
+def gen_set_entry(set, line):
+ parts = line.split('\t')
+
+ make_break = parts[set]
+ [make, brk] = [[int(y, 16) for y in x.split(' ')] for x in make_break.replace('(base)', '').strip().split('/')]
+ brk_pfx = brk[0]
+ if not set == 1:
+ brk = brk[1:]
+
+ if make[0] == 0xe0 or make[0] == 0xe1:
+ return
+
+ [make, brk] = [reduce(lambda o, n: o << 8 | n, x, 0) for x in [make, brk]]
+
+ ascii = str(parts[6] == 'yes').lower()
+ symbol = symbolify(parts[7])
+ upper_symbol = symbolify(parts[8])
+
+ print(f"""\t[{make}] = {'{'} .ascii = {ascii}, .symbol = {symbol},
+\t\t.up_symbol = {upper_symbol}, .prefix = {brk_pfx} {'}'},""")
+
+ if set == 1:
+ print(f"""\t[{brk}] = {'{'} .ascii = {ascii}, .symbol = {symbol},
+\t\t.up_symbol = {upper_symbol}, .prefix = {brk_pfx}, .brk = true {'}'},""")
+
+def gen_set(lines, set):
+ # NOTE will only work with scan code set 3
+ print("const struct kbd_scan_codes scan_code_set_" + str(set) + "[0xff] =\n{")
+ for l in lines:
+ gen_set_entry(set, l)
+ print("};")
+
+with open('scan_codes.tsv', 'r') as f:
+ lines = f.read().split('\n')[1:]
+ print('#include "kbd.h"\n\n')
+ gen_set(lines, 1)
+ print('\n')
+ gen_set(lines, 3)
+
diff --git a/src/kernel/idt.s b/src/kernel/idt.s
new file mode 100644
index 0000000..3e2ce5d
--- /dev/null
+++ b/src/kernel/idt.s
@@ -0,0 +1,84 @@
+ [bits 32]
+ [global idt_flush]
+
+idt_flush:
+ mov eax, [esp + 4]
+ lidt [eax]
+ ret
+
+%macro ISRNOERR 1
+ [global isr%1]
+isr%1:
+ cli
+ push 0
+ push %1
+ jmp isr_common
+%endmacro
+
+%macro ISRERR 1
+ [global isr%1]
+isr%1:
+ cli
+ push byte %1
+ jmp isr_common
+%endmacro
+
+ISRNOERR 0
+ISRNOERR 1
+ISRNOERR 2
+ISRNOERR 3
+ISRNOERR 4
+ISRNOERR 5
+ISRNOERR 6
+ISRNOERR 7
+ISRERR 8
+ISRNOERR 9
+ISRERR 10
+ISRERR 11
+ISRERR 12
+ISRERR 13
+ISRERR 14
+ISRNOERR 15
+ISRNOERR 16
+ISRNOERR 17
+ISRNOERR 18
+ISRNOERR 19
+ISRNOERR 20
+ISRNOERR 21
+ISRNOERR 22
+ISRNOERR 23
+ISRNOERR 24
+ISRNOERR 25
+ISRNOERR 26
+ISRNOERR 27
+ISRNOERR 28
+ISRNOERR 29
+ISRNOERR 30
+ISRNOERR 31
+
+
+ [extern isr_handler]
+isr_common:
+ pusha ; Save all registers
+
+ mov ax, ds ; Save data segment
+ push eax
+
+ mov ax, 0x10 ; New segments
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ call isr_handler
+
+ pop eax ; Reset segments
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ popa
+ add esp, 8 ; Passed arguments
+ sti
+ iret ; Return from interrupt
diff --git a/src/kernel/io.c b/src/kernel/io.c
new file mode 100644
index 0000000..55bf7a7
--- /dev/null
+++ b/src/kernel/io.c
@@ -0,0 +1,91 @@
+#include "io.h"
+#include "kbd.h"
+#include "log.h"
+#include "pic.h"
+
+bool pressed_keys[LAST_KBD_KEY];
+char special_key_mappings[LAST_KBD_KEY - FIRST_KBD_KEY] =
+{
+ [KBD_ENTER - FIRST_KBD_KEY] = '\n',
+ [KBD_SPACEBAR - FIRST_KBD_KEY] = ' ',
+ [KBD_TAB - FIRST_KBD_KEY] = '\t',
+ [KBD_BACKSPACE - FIRST_KBD_KEY] = '\b',
+ 0
+};
+
+void outb(ushort port, uchar val)
+{
+ asm volatile("outb %1, %0" : : "dN"(port), "a"(val));
+}
+
+uchar inb(ushort port)
+{
+ uchar ret;
+ asm volatile("inb %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+ushort inw(ushort port)
+{
+ ushort ret;
+ asm volatile("inw %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+void *memset(void *s, int c, size_t n)
+{
+ for (size_t i = 0; i < n; i++)
+ {
+ ((uchar *)s)[i] = c;
+ }
+ return s;
+}
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ for (size_t i = 0; i < n; i++)
+ {
+ ((uchar *)dest)[i] = ((uchar *)src)[i];
+ }
+ return dest;
+}
+
+void io_wait()
+{
+ asm volatile("outb %0, $0x80" ::"a"(0));
+}
+
+uchar kbd_scan_code()
+{
+ return inb(KBD_DATA_PORT);
+}
+
+static bool kbd_shift_pressed()
+{
+ return pressed_keys[KBD_LEFT_SHIFT] || pressed_keys[KBD_RIGHT_SHIFT] ||
+ pressed_keys[KBD_CAPS_LOCK];
+}
+
+void kbd_handle_input(struct registers *registers)
+{
+ uchar byte = kbd_scan_code();
+
+ struct kbd_scan_codes code = scan_code_set_1[byte];
+
+ if (code.ascii && !code.brk)
+ {
+ kprintf("%c", kbd_shift_pressed() && code.up_symbol ? code.up_symbol
+ : code.symbol);
+ }
+ else if (!code.brk && special_key_mappings[code.symbol - FIRST_KBD_KEY])
+ {
+ kprintf("%c", special_key_mappings[code.symbol - FIRST_KBD_KEY]);
+ }
+ pressed_keys[code.symbol] = !code.brk;
+}
+
+void init_kbd()
+{
+ memset(pressed_keys, 0, LAST_KBD_KEY);
+ add_interrupt_handler(33, kbd_handle_input);
+}
diff --git a/src/kernel/io.h b/src/kernel/io.h
new file mode 100644
index 0000000..28af387
--- /dev/null
+++ b/src/kernel/io.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "kint.h"
+#include "registers.h"
+
+#define KBD_CMD_PORT 0x64
+#define KBD_DATA_PORT 0x60
+
+struct kbd_scan_code_info
+{
+ bool pressed;
+ bool escape;
+ char key;
+};
+
+extern struct kbd_scan_code_info scan_code_table[0xff];
+
+void outb(ushort port, uchar val);
+uchar inb(ushort port);
+ushort inw(ushort port);
+
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+
+void io_wait();
+
+uchar kbd_scan_code();
+void kbd_handle_input(struct registers *registers);
+void init_kbd();
diff --git a/src/kernel/irq.s b/src/kernel/irq.s
new file mode 100644
index 0000000..e340a61
--- /dev/null
+++ b/src/kernel/irq.s
@@ -0,0 +1,53 @@
+ [bits 32]
+
+%macro IRQ 2
+ [global irq%1]
+irq%1:
+ cli
+ push 0 ; Error code
+ push %2 ; Interrupt number
+ jmp irq_common
+%endmacro
+
+IRQ 0, 32
+IRQ 1, 33
+IRQ 2, 34
+IRQ 3, 35
+IRQ 4, 36
+IRQ 5, 37
+IRQ 6, 38
+IRQ 7, 39
+IRQ 8, 40
+IRQ 9, 41
+IRQ 10, 42
+IRQ 11, 43
+IRQ 12, 44
+IRQ 13, 45
+IRQ 14, 46
+IRQ 15, 47
+
+ [extern irq_handler]
+irq_common:
+ pusha
+ mov ax, ds ; Save data segment
+ push eax
+
+ mov ax, 0x10 ; New segments
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ call irq_handler
+
+ pop ebx ; Old data segment
+ mov ds, bx
+ mov es, bx
+ mov fs, bx
+ mov gs, bx
+
+ popa
+ add esp, 8
+ sti
+ iret
+
diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h
new file mode 100644
index 0000000..98d6fd7
--- /dev/null
+++ b/src/kernel/kbd.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "kint.h"
+
+struct kbd_scan_codes
+{
+ bool ascii;
+ int symbol;
+ int up_symbol;
+ uchar prefix;
+ bool brk;
+};
+
+enum kbd_keys
+{
+ FIRST_KBD_KEY = 129,
+ KBD_BACKSPACE = 129,
+ KBD_TAB,
+ KBD_CAPS_LOCK,
+ KBD_ENTER,
+ KBD_LEFT_SHIFT,
+ KBD_RIGHT_SHIFT,
+ KBD_LEFT_CTRL,
+ KBD_LEFT_ALT,
+ KBD_SPACEBAR,
+ KBD_RIGHT_ALT,
+ KBD_RIGHT_CTRL,
+ KBD_INSERT,
+ KBD_DELETE,
+ KBD_LEFT_ARROW,
+ KBD_HOME,
+ KBD_END,
+ KBD_UP_ARROW,
+ KBD_DOWN_ARROW,
+ KBD_RIGHT_ARROW,
+ KBD_NUM_LOCK,
+ KBD_KEYPAD_0,
+ KBD_KEYPAD_1,
+ KBD_KEYPAD_2,
+ KBD_KEYPAD_3,
+ KBD_KEYPAD_4,
+ KBD_KEYPAD_5,
+ KBD_KEYPAD_6,
+ KBD_KEYPAD_7,
+ KBD_KEYPAD_8,
+ KBD_KEYPAD_9,
+ KBD_KEYPAD_DOT,
+ KBD_KEYPAD_PLUS,
+ KBD_KEYPAD_MINUS,
+ KBD_KEYPAD_TIMES,
+ KBD_KEYPAD_DIV,
+ KBD_KEYPAD_ENTER,
+ KBD_ESC,
+ KBD_F1,
+ KBD_F2,
+ KBD_F3,
+ KBD_F4,
+ KBD_F5,
+ KBD_F6,
+ KBD_F7,
+ KBD_F8,
+ KBD_F9,
+ KBD_F10,
+ KBD_F11,
+ KBD_F12,
+ KBD_PRINT_SCREEN,
+ KBD_SCROLL_LOCK,
+ KBD_PAUSE_BREAK,
+ KBD_PAGE_UP,
+ KBD_PAGE_DOWN,
+ LAST_KBD_KEY,
+};
+
+extern const struct kbd_scan_codes scan_code_set_3[0xff];
+extern const struct kbd_scan_codes scan_code_set_1[0xff];
+extern bool pressed_keys[LAST_KBD_KEY];
+extern char special_key_mappings[LAST_KBD_KEY - FIRST_KBD_KEY];
diff --git a/src/kernel/kint.h b/src/kernel/kint.h
new file mode 100644
index 0000000..44b9bfd
--- /dev/null
+++ b/src/kernel/kint.h
@@ -0,0 +1,18 @@
+#pragma once
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+typedef unsigned long size_t;
+
+typedef uchar bool;
+
+enum
+{
+ false = 0,
+ true,
+};
+
+#define NULL 0
diff --git a/src/kernel/link.ld b/src/kernel/link.ld
new file mode 100644
index 0000000..2abbaeb
--- /dev/null
+++ b/src/kernel/link.ld
@@ -0,0 +1,27 @@
+ENTRY(start)
+SECTIONS
+{
+ .text 0x100000 :
+ {
+ code = .; _code = .; __code = .;
+ *(.text)
+ . = ALIGN(4096);
+ }
+
+ .data :
+ {
+ data = .; _data = .; __data = .;
+ *(.data)
+ *(.rodata)
+ . = ALIGN(4096);
+ }
+
+ .bss :
+ {
+ bss = .; _bss = .; __bss = .;
+ *(.bss)
+ . = ALIGN(4096);
+ }
+
+ end = .; _end = .; __end = .;
+}
diff --git a/src/kernel/log.c b/src/kernel/log.c
new file mode 100644
index 0000000..ac49971
--- /dev/null
+++ b/src/kernel/log.c
@@ -0,0 +1,68 @@
+#include "log.h"
+#include "kint.h"
+#include "stdarg.h"
+#include "vga.h"
+
+void kprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ format++;
+
+ switch (*format)
+ {
+ case 'd': {
+ uint x = (uint)va_arg(args, uint);
+ vga_putd(x);
+ break;
+ }
+
+ case 'x': {
+ // consider hex always unsigned
+ uint x = (uint)va_arg(args, uint);
+ vga_putx(x);
+ break;
+ }
+
+ case 's': {
+ char *s = va_arg(args, char *);
+ vga_write(s);
+ break;
+ }
+
+ case 'c': {
+ char s = va_arg(args, int);
+ vga_put(s);
+ break;
+ }
+ }
+ format++;
+ }
+ else
+ {
+ vga_put(*format);
+ format++;
+ }
+ }
+
+ va_end(args);
+}
+
+void kassert_int(bool condition, const char *message, const char *file,
+ const int line)
+{
+ if (!condition)
+ {
+ vga_set_color(LIGHT_RED, BLACK);
+ kprintf("ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
+
+ while (1)
+ {
+ }
+ }
+}
diff --git a/src/kernel/log.h b/src/kernel/log.h
new file mode 100644
index 0000000..fe5dcd9
--- /dev/null
+++ b/src/kernel/log.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "kint.h"
+
+void kprintf(const char *format, ...);
+void kassert_int(bool condition, const char *message, const char *file,
+ const int line);
+
+#define kassert(cond, msg) kassert_int((cond), (msg), __FILE__, __LINE__)
+#define kpanic(msg) \
+ kassert(false, msg); \
+ __builtin_unreachable()
diff --git a/src/kernel/main.c b/src/kernel/main.c
new file mode 100644
index 0000000..15b6c09
--- /dev/null
+++ b/src/kernel/main.c
@@ -0,0 +1,41 @@
+#include "descriptor_tables.h"
+#include "io.h"
+#include "log.h"
+#include "timer.h"
+#include "vga.h"
+#include "paging.h"
+
+int kmain(void *mboot)
+{
+ vga_clear();
+ vga_set_color(LIGHT_BLUE, BLACK);
+ vga_write("Hello!\nWelcome to Bluejay OS\n");
+ vga_set_color(WHITE, BLACK);
+
+ init_descriptor_tables();
+
+ vga_set_color(LIGHT_GREEN, BLACK);
+ vga_write("Setup complete!\n");
+ vga_set_color(WHITE, BLACK);
+
+ init_timer(20);
+
+ initialize_paging();
+ init_kbd();
+ asm volatile("sti");
+
+
+#ifdef TEST_PAGE_FAULT
+ kprintf("Causing page fault:\n");
+
+ volatile uint *ptr = (uint *) 0xa0000000;
+ volatile uint cause_page_fault = *ptr;
+
+ kprintf("Should have caused page fault: %d...\n", cause_page_fault);
+#endif
+
+ while (true)
+ asm volatile("hlt");
+
+ return 0xCAFEBABE;
+}
diff --git a/src/kernel/paging.c b/src/kernel/paging.c
new file mode 100644
index 0000000..128de4e
--- /dev/null
+++ b/src/kernel/paging.c
@@ -0,0 +1,142 @@
+#include "paging.h"
+#include "io.h"
+#include "kint.h"
+#include "log.h"
+#include "pic.h"
+
+extern uint end;
+static size_t alloc_base = (size_t)&end;
+
+/* frames bitset, 0 = free, 1 = used */
+static uint *frames;
+static ulong num_frames;
+
+static uint first_page_table[1024] __attribute__((aligned(4096)));
+static uint *page_directory[1024] __attribute__((aligned(4096)));
+
+static uint ***current_directory;
+
+void *_kmalloc(size_t size, bool align, void **phys)
+{
+ if (align && (alloc_base & 0xfff)) // if not yet aligned
+ {
+ alloc_base &= ~0xfff;
+ alloc_base += 0x1000;
+ }
+
+ if (phys)
+ {
+ *phys = (void *)alloc_base;
+ }
+
+ size_t addr = alloc_base;
+ alloc_base += size;
+ return (void *)addr;
+}
+
+void *kmalloc(size_t size)
+{
+ return _kmalloc(size, false, NULL);
+}
+
+void *kmalloc_a(size_t size)
+{
+ return _kmalloc(size, true, NULL);
+}
+
+void *kmalloc_ap(size_t size, void **p)
+{
+ return _kmalloc(size, true, p);
+}
+
+/* frame utils */
+
+#define BITS 32
+
+static void set_frame(size_t frame_addr)
+{
+ uint frame = frame_addr / 0x1000; // page aligned
+ frames[frame / BITS] |= 1 << (frame % BITS);
+}
+
+static bool test_frame(size_t frame_addr)
+{
+ uint frame = frame_addr / 0x1000; // page aligned
+ return frames[frame / BITS] & 1 << (frame % BITS);
+}
+
+static void clear_frame(size_t frame_addr)
+{
+ uint frame = frame_addr / 0x1000; // page aligned
+ frames[frame / BITS] &= ~(1 << (frame % BITS));
+}
+
+static uint first_free_frame()
+{
+ for (int i = 0; i < num_frames / BITS; i++)
+ {
+ /*
+ * If there are any zeroes, ~ will yield a non-zero result,
+ * meaning that there are pages free. Otherwise, check next set
+ */
+ if (!~frames[i])
+ continue;
+
+ for (int j = 0; j < BITS; j++)
+ {
+ if ((frames[i] & 1 << j) == 0)
+ {
+ /* found unused frame */
+ return i * BITS + j;
+ }
+ }
+ }
+
+ /* did not find a free frame, panic */
+ kpanic("first_free_frame failed! no free frames");
+}
+
+void alloc_frame(uint *page, bool for_kernel, bool writable)
+{
+ if (*page >> 12)
+ return; /* frame already allocated */
+
+ uint frame = first_free_frame();
+ // kprintf("first_free_frame found %d\n", frame);
+ set_frame(frame * 0x1000); /* mark as mapped */
+}
+
+void free_frame(uint page)
+{
+ clear_frame(page / 0x1000);
+}
+
+/* paging stuff */
+
+void initialize_paging()
+{
+ for (int i = 0; i < 1024; i++)
+ {
+ page_directory[i] = (uint *) 0b010; // kernel, rw, not present
+ }
+
+ for (int i = 0; i < 1024; i++)
+ {
+ first_page_table[i] = (i * 0x1000) | 3;
+ }
+
+ page_directory[0] = (uint *) (((size_t) (uint *) first_page_table) | 3);
+
+ kprintf("Set up page directory[0], %x\n", (uint)first_page_table);
+
+ load_page_directory((uint) page_directory);
+ enable_paging();
+
+ add_interrupt_handler(14, page_fault);
+}
+
+void page_fault(struct registers *regs)
+{
+ kprintf("Page fault! eip = %d\n", regs->eip);
+ kpanic("Page fault");
+}
diff --git a/src/kernel/paging.h b/src/kernel/paging.h
new file mode 100644
index 0000000..7c5000e
--- /dev/null
+++ b/src/kernel/paging.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "kint.h"
+#include "registers.h"
+
+/* defined in switch_table.s */
+extern uint load_page_directory(uint table_address);
+extern void enable_paging();
+
+void *_kmalloc(size_t size, bool align, void **phys);
+void *kmalloc(size_t size);
+void *kmalloc_a(size_t size);
+void *kmalloc_ap(size_t size, void **p);
+
+void initialize_paging();
+
+void page_fault(struct registers *regs);
diff --git a/src/kernel/pic.c b/src/kernel/pic.c
new file mode 100644
index 0000000..1c96543
--- /dev/null
+++ b/src/kernel/pic.c
@@ -0,0 +1,64 @@
+#include "pic.h"
+#include "io.h"
+#include "log.h"
+
+#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
+#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
+#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
+#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
+#define ICW1_INIT 0x10 /* Initialization - required! */
+
+#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
+#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
+#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
+#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
+#define ICW4_SFNM 0x10 /* Special fully nested (not) */
+
+void (*interrupt_handlers[256])(struct registers *);
+
+void pic_send_eoi(uchar interrupt)
+{
+ if (interrupt >= IRQ_TO_INT(8))
+ outb(PIC2_COMMAND, PIC_EOI);
+
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq_handler(struct registers regs)
+{
+ pic_send_eoi(regs.interrupt_number);
+
+ if (interrupt_handlers[regs.interrupt_number])
+ interrupt_handlers[regs.interrupt_number](®s);
+ else
+ kprintf("Unhandled hardware interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
+}
+
+void isr_handler(struct registers regs)
+{
+ if (interrupt_handlers[regs.interrupt_number])
+ interrupt_handlers[regs.interrupt_number](®s);
+ else
+ kprintf("Unhandled interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
+}
+
+void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *))
+{
+ interrupt_handlers[interrupt] = handler;
+}
+
+void pic_remap()
+{
+ 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);
+
+ return;
+}
diff --git a/src/kernel/pic.h b/src/kernel/pic.h
new file mode 100644
index 0000000..de11f3f
--- /dev/null
+++ b/src/kernel/pic.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "kint.h"
+#include "registers.h"
+
+#define PIC1 0x20
+#define PIC2 0xa0
+#define PIC1_COMMAND PIC1
+#define PIC1_DATA (PIC1 + 1)
+#define PIC2_COMMAND PIC2
+#define PIC2_DATA (PIC2 + 1)
+
+#define PIC_EOI 0x20 // End of input
+
+#define IRQ_TO_INT(irq) ((irq) + 32)
+
+void pic_send_eoi(uchar interrupt);
+void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *));
+
+void pic_remap();
diff --git a/src/kernel/registers.h b/src/kernel/registers.h
new file mode 100644
index 0000000..687bd0e
--- /dev/null
+++ b/src/kernel/registers.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "kint.h"
+
+struct registers
+{
+ uint ds;
+ uint edi, esi, ebp, esp, ebx, edx, ecx, eax;
+ uint interrupt_number, error_code;
+ uint eip, cs, eflags, useresp, ss;
+};
diff --git a/src/kernel/scan_codes.c b/src/kernel/scan_codes.c
new file mode 100644
index 0000000..530fd91
--- /dev/null
+++ b/src/kernel/scan_codes.c
@@ -0,0 +1,553 @@
+#include "kbd.h"
+
+
+const struct kbd_scan_codes scan_code_set_1[0xff] =
+{
+ [41] = { .ascii = true, .symbol = '`',
+ .up_symbol = '~', .prefix = 169 },
+ [169] = { .ascii = true, .symbol = '`',
+ .up_symbol = '~', .prefix = 169, .brk = true },
+ [2] = { .ascii = true, .symbol = '1',
+ .up_symbol = '!', .prefix = 130 },
+ [130] = { .ascii = true, .symbol = '1',
+ .up_symbol = '!', .prefix = 130, .brk = true },
+ [3] = { .ascii = true, .symbol = '2',
+ .up_symbol = '@', .prefix = 131 },
+ [131] = { .ascii = true, .symbol = '2',
+ .up_symbol = '@', .prefix = 131, .brk = true },
+ [4] = { .ascii = true, .symbol = '3',
+ .up_symbol = '#', .prefix = 132 },
+ [132] = { .ascii = true, .symbol = '3',
+ .up_symbol = '#', .prefix = 132, .brk = true },
+ [5] = { .ascii = true, .symbol = '4',
+ .up_symbol = '$', .prefix = 133 },
+ [133] = { .ascii = true, .symbol = '4',
+ .up_symbol = '$', .prefix = 133, .brk = true },
+ [6] = { .ascii = true, .symbol = '5',
+ .up_symbol = '%', .prefix = 134 },
+ [134] = { .ascii = true, .symbol = '5',
+ .up_symbol = '%', .prefix = 134, .brk = true },
+ [7] = { .ascii = true, .symbol = '6',
+ .up_symbol = '^', .prefix = 135 },
+ [135] = { .ascii = true, .symbol = '6',
+ .up_symbol = '^', .prefix = 135, .brk = true },
+ [8] = { .ascii = true, .symbol = '7',
+ .up_symbol = '&', .prefix = 136 },
+ [136] = { .ascii = true, .symbol = '7',
+ .up_symbol = '&', .prefix = 136, .brk = true },
+ [9] = { .ascii = true, .symbol = '8',
+ .up_symbol = '*', .prefix = 137 },
+ [137] = { .ascii = true, .symbol = '8',
+ .up_symbol = '*', .prefix = 137, .brk = true },
+ [10] = { .ascii = true, .symbol = '9',
+ .up_symbol = '(', .prefix = 138 },
+ [138] = { .ascii = true, .symbol = '9',
+ .up_symbol = '(', .prefix = 138, .brk = true },
+ [11] = { .ascii = true, .symbol = '0',
+ .up_symbol = ')', .prefix = 139 },
+ [139] = { .ascii = true, .symbol = '0',
+ .up_symbol = ')', .prefix = 139, .brk = true },
+ [12] = { .ascii = true, .symbol = '-',
+ .up_symbol = '_', .prefix = 140 },
+ [140] = { .ascii = true, .symbol = '-',
+ .up_symbol = '_', .prefix = 140, .brk = true },
+ [13] = { .ascii = true, .symbol = '=',
+ .up_symbol = '+', .prefix = 141 },
+ [141] = { .ascii = true, .symbol = '=',
+ .up_symbol = '+', .prefix = 141, .brk = true },
+ [14] = { .ascii = false, .symbol = KBD_BACKSPACE,
+ .up_symbol = NULL, .prefix = 142 },
+ [142] = { .ascii = false, .symbol = KBD_BACKSPACE,
+ .up_symbol = NULL, .prefix = 142, .brk = true },
+ [15] = { .ascii = false, .symbol = KBD_TAB,
+ .up_symbol = NULL, .prefix = 143 },
+ [143] = { .ascii = false, .symbol = KBD_TAB,
+ .up_symbol = NULL, .prefix = 143, .brk = true },
+ [16] = { .ascii = true, .symbol = 'q',
+ .up_symbol = 'Q', .prefix = 144 },
+ [144] = { .ascii = true, .symbol = 'q',
+ .up_symbol = 'Q', .prefix = 144, .brk = true },
+ [17] = { .ascii = true, .symbol = 'w',
+ .up_symbol = 'W', .prefix = 145 },
+ [145] = { .ascii = true, .symbol = 'w',
+ .up_symbol = 'W', .prefix = 145, .brk = true },
+ [18] = { .ascii = true, .symbol = 'e',
+ .up_symbol = 'E', .prefix = 146 },
+ [146] = { .ascii = true, .symbol = 'e',
+ .up_symbol = 'E', .prefix = 146, .brk = true },
+ [19] = { .ascii = true, .symbol = 'r',
+ .up_symbol = 'R', .prefix = 147 },
+ [147] = { .ascii = true, .symbol = 'r',
+ .up_symbol = 'R', .prefix = 147, .brk = true },
+ [20] = { .ascii = true, .symbol = 't',
+ .up_symbol = 'T', .prefix = 148 },
+ [148] = { .ascii = true, .symbol = 't',
+ .up_symbol = 'T', .prefix = 148, .brk = true },
+ [21] = { .ascii = true, .symbol = 'y',
+ .up_symbol = 'Y', .prefix = 149 },
+ [149] = { .ascii = true, .symbol = 'y',
+ .up_symbol = 'Y', .prefix = 149, .brk = true },
+ [22] = { .ascii = true, .symbol = 'u',
+ .up_symbol = 'U', .prefix = 150 },
+ [150] = { .ascii = true, .symbol = 'u',
+ .up_symbol = 'U', .prefix = 150, .brk = true },
+ [23] = { .ascii = true, .symbol = 'i',
+ .up_symbol = 'I', .prefix = 151 },
+ [151] = { .ascii = true, .symbol = 'i',
+ .up_symbol = 'I', .prefix = 151, .brk = true },
+ [24] = { .ascii = true, .symbol = 'o',
+ .up_symbol = 'O', .prefix = 152 },
+ [152] = { .ascii = true, .symbol = 'o',
+ .up_symbol = 'O', .prefix = 152, .brk = true },
+ [25] = { .ascii = true, .symbol = 'p',
+ .up_symbol = 'P', .prefix = 153 },
+ [153] = { .ascii = true, .symbol = 'p',
+ .up_symbol = 'P', .prefix = 153, .brk = true },
+ [26] = { .ascii = true, .symbol = '[',
+ .up_symbol = '{', .prefix = 154 },
+ [154] = { .ascii = true, .symbol = '[',
+ .up_symbol = '{', .prefix = 154, .brk = true },
+ [27] = { .ascii = true, .symbol = ']',
+ .up_symbol = '}', .prefix = 155 },
+ [155] = { .ascii = true, .symbol = ']',
+ .up_symbol = '}', .prefix = 155, .brk = true },
+ [58] = { .ascii = false, .symbol = KBD_CAPS_LOCK,
+ .up_symbol = NULL, .prefix = 186 },
+ [186] = { .ascii = false, .symbol = KBD_CAPS_LOCK,
+ .up_symbol = NULL, .prefix = 186, .brk = true },
+ [30] = { .ascii = true, .symbol = 'a',
+ .up_symbol = 'A', .prefix = 158 },
+ [158] = { .ascii = true, .symbol = 'a',
+ .up_symbol = 'A', .prefix = 158, .brk = true },
+ [31] = { .ascii = true, .symbol = 's',
+ .up_symbol = 'S', .prefix = 159 },
+ [159] = { .ascii = true, .symbol = 's',
+ .up_symbol = 'S', .prefix = 159, .brk = true },
+ [32] = { .ascii = true, .symbol = 'd',
+ .up_symbol = 'D', .prefix = 160 },
+ [160] = { .ascii = true, .symbol = 'd',
+ .up_symbol = 'D', .prefix = 160, .brk = true },
+ [33] = { .ascii = true, .symbol = 'f',
+ .up_symbol = 'F', .prefix = 161 },
+ [161] = { .ascii = true, .symbol = 'f',
+ .up_symbol = 'F', .prefix = 161, .brk = true },
+ [34] = { .ascii = true, .symbol = 'g',
+ .up_symbol = 'G', .prefix = 162 },
+ [162] = { .ascii = true, .symbol = 'g',
+ .up_symbol = 'G', .prefix = 162, .brk = true },
+ [35] = { .ascii = true, .symbol = 'h',
+ .up_symbol = 'H', .prefix = 163 },
+ [163] = { .ascii = true, .symbol = 'h',
+ .up_symbol = 'H', .prefix = 163, .brk = true },
+ [36] = { .ascii = true, .symbol = 'j',
+ .up_symbol = 'J', .prefix = 164 },
+ [164] = { .ascii = true, .symbol = 'j',
+ .up_symbol = 'J', .prefix = 164, .brk = true },
+ [37] = { .ascii = true, .symbol = 'k',
+ .up_symbol = 'K', .prefix = 165 },
+ [165] = { .ascii = true, .symbol = 'k',
+ .up_symbol = 'K', .prefix = 165, .brk = true },
+ [38] = { .ascii = true, .symbol = 'l',
+ .up_symbol = 'L', .prefix = 166 },
+ [166] = { .ascii = true, .symbol = 'l',
+ .up_symbol = 'L', .prefix = 166, .brk = true },
+ [39] = { .ascii = true, .symbol = ';',
+ .up_symbol = ':', .prefix = 167 },
+ [167] = { .ascii = true, .symbol = ';',
+ .up_symbol = ':', .prefix = 167, .brk = true },
+ [40] = { .ascii = true, .symbol = '\'',
+ .up_symbol = '"', .prefix = 168 },
+ [168] = { .ascii = true, .symbol = '\'',
+ .up_symbol = '"', .prefix = 168, .brk = true },
+ [28] = { .ascii = false, .symbol = KBD_ENTER,
+ .up_symbol = NULL, .prefix = 156 },
+ [156] = { .ascii = false, .symbol = KBD_ENTER,
+ .up_symbol = NULL, .prefix = 156, .brk = true },
+ [42] = { .ascii = false, .symbol = KBD_LEFT_SHIFT,
+ .up_symbol = NULL, .prefix = 170 },
+ [170] = { .ascii = false, .symbol = KBD_LEFT_SHIFT,
+ .up_symbol = NULL, .prefix = 170, .brk = true },
+ [44] = { .ascii = true, .symbol = 'z',
+ .up_symbol = 'Z', .prefix = 172 },
+ [172] = { .ascii = true, .symbol = 'z',
+ .up_symbol = 'Z', .prefix = 172, .brk = true },
+ [45] = { .ascii = true, .symbol = 'x',
+ .up_symbol = 'X', .prefix = 173 },
+ [173] = { .ascii = true, .symbol = 'x',
+ .up_symbol = 'X', .prefix = 173, .brk = true },
+ [46] = { .ascii = true, .symbol = 'c',
+ .up_symbol = 'C', .prefix = 174 },
+ [174] = { .ascii = true, .symbol = 'c',
+ .up_symbol = 'C', .prefix = 174, .brk = true },
+ [47] = { .ascii = true, .symbol = 'v',
+ .up_symbol = 'V', .prefix = 175 },
+ [175] = { .ascii = true, .symbol = 'v',
+ .up_symbol = 'V', .prefix = 175, .brk = true },
+ [48] = { .ascii = true, .symbol = 'b',
+ .up_symbol = 'B', .prefix = 176 },
+ [176] = { .ascii = true, .symbol = 'b',
+ .up_symbol = 'B', .prefix = 176, .brk = true },
+ [49] = { .ascii = true, .symbol = 'n',
+ .up_symbol = 'N', .prefix = 177 },
+ [177] = { .ascii = true, .symbol = 'n',
+ .up_symbol = 'N', .prefix = 177, .brk = true },
+ [50] = { .ascii = true, .symbol = 'm',
+ .up_symbol = 'M', .prefix = 178 },
+ [178] = { .ascii = true, .symbol = 'm',
+ .up_symbol = 'M', .prefix = 178, .brk = true },
+ [51] = { .ascii = true, .symbol = ',',
+ .up_symbol = '<', .prefix = 179 },
+ [179] = { .ascii = true, .symbol = ',',
+ .up_symbol = '<', .prefix = 179, .brk = true },
+ [52] = { .ascii = true, .symbol = '.',
+ .up_symbol = '>', .prefix = 180 },
+ [180] = { .ascii = true, .symbol = '.',
+ .up_symbol = '>', .prefix = 180, .brk = true },
+ [53] = { .ascii = true, .symbol = '/',
+ .up_symbol = '?', .prefix = 181 },
+ [181] = { .ascii = true, .symbol = '/',
+ .up_symbol = '?', .prefix = 181, .brk = true },
+ [54] = { .ascii = false, .symbol = KBD_RIGHT_SHIFT,
+ .up_symbol = NULL, .prefix = 182 },
+ [182] = { .ascii = false, .symbol = KBD_RIGHT_SHIFT,
+ .up_symbol = NULL, .prefix = 182, .brk = true },
+ [29] = { .ascii = false, .symbol = KBD_LEFT_CTRL,
+ .up_symbol = NULL, .prefix = 157 },
+ [157] = { .ascii = false, .symbol = KBD_LEFT_CTRL,
+ .up_symbol = NULL, .prefix = 157, .brk = true },
+ [56] = { .ascii = false, .symbol = KBD_LEFT_ALT,
+ .up_symbol = NULL, .prefix = 184 },
+ [184] = { .ascii = false, .symbol = KBD_LEFT_ALT,
+ .up_symbol = NULL, .prefix = 184, .brk = true },
+ [57] = { .ascii = false, .symbol = KBD_SPACEBAR,
+ .up_symbol = NULL, .prefix = 185 },
+ [185] = { .ascii = false, .symbol = KBD_SPACEBAR,
+ .up_symbol = NULL, .prefix = 185, .brk = true },
+ [69] = { .ascii = false, .symbol = KBD_NUM_LOCK,
+ .up_symbol = NULL, .prefix = 197 },
+ [197] = { .ascii = false, .symbol = KBD_NUM_LOCK,
+ .up_symbol = NULL, .prefix = 197, .brk = true },
+ [71] = { .ascii = false, .symbol = KBD_KEYPAD_7,
+ .up_symbol = NULL, .prefix = 199 },
+ [199] = { .ascii = false, .symbol = KBD_KEYPAD_7,
+ .up_symbol = NULL, .prefix = 199, .brk = true },
+ [75] = { .ascii = false, .symbol = KBD_KEYPAD_4,
+ .up_symbol = NULL, .prefix = 203 },
+ [203] = { .ascii = false, .symbol = KBD_KEYPAD_4,
+ .up_symbol = NULL, .prefix = 203, .brk = true },
+ [79] = { .ascii = false, .symbol = KBD_KEYPAD_1,
+ .up_symbol = NULL, .prefix = 207 },
+ [207] = { .ascii = false, .symbol = KBD_KEYPAD_1,
+ .up_symbol = NULL, .prefix = 207, .brk = true },
+ [72] = { .ascii = false, .symbol = KBD_KEYPAD_8,
+ .up_symbol = NULL, .prefix = 200 },
+ [200] = { .ascii = false, .symbol = KBD_KEYPAD_8,
+ .up_symbol = NULL, .prefix = 200, .brk = true },
+ [76] = { .ascii = false, .symbol = KBD_KEYPAD_5,
+ .up_symbol = NULL, .prefix = 204 },
+ [204] = { .ascii = false, .symbol = KBD_KEYPAD_5,
+ .up_symbol = NULL, .prefix = 204, .brk = true },
+ [80] = { .ascii = false, .symbol = KBD_KEYPAD_2,
+ .up_symbol = NULL, .prefix = 208 },
+ [208] = { .ascii = false, .symbol = KBD_KEYPAD_2,
+ .up_symbol = NULL, .prefix = 208, .brk = true },
+ [82] = { .ascii = false, .symbol = KBD_KEYPAD_0,
+ .up_symbol = NULL, .prefix = 210 },
+ [210] = { .ascii = false, .symbol = KBD_KEYPAD_0,
+ .up_symbol = NULL, .prefix = 210, .brk = true },
+ [55] = { .ascii = false, .symbol = KBD_KEYPAD_TIMES,
+ .up_symbol = NULL, .prefix = 183 },
+ [183] = { .ascii = false, .symbol = KBD_KEYPAD_TIMES,
+ .up_symbol = NULL, .prefix = 183, .brk = true },
+ [73] = { .ascii = false, .symbol = KBD_KEYPAD_9,
+ .up_symbol = NULL, .prefix = 201 },
+ [201] = { .ascii = false, .symbol = KBD_KEYPAD_9,
+ .up_symbol = NULL, .prefix = 201, .brk = true },
+ [77] = { .ascii = false, .symbol = KBD_KEYPAD_6,
+ .up_symbol = NULL, .prefix = 205 },
+ [205] = { .ascii = false, .symbol = KBD_KEYPAD_6,
+ .up_symbol = NULL, .prefix = 205, .brk = true },
+ [81] = { .ascii = false, .symbol = KBD_KEYPAD_3,
+ .up_symbol = NULL, .prefix = 209 },
+ [209] = { .ascii = false, .symbol = KBD_KEYPAD_3,
+ .up_symbol = NULL, .prefix = 209, .brk = true },
+ [83] = { .ascii = false, .symbol = KBD_KEYPAD_DOT,
+ .up_symbol = NULL, .prefix = 211 },
+ [211] = { .ascii = false, .symbol = KBD_KEYPAD_DOT,
+ .up_symbol = NULL, .prefix = 211, .brk = true },
+ [74] = { .ascii = false, .symbol = KBD_KEYPAD_MINUS,
+ .up_symbol = NULL, .prefix = 202 },
+ [202] = { .ascii = false, .symbol = KBD_KEYPAD_MINUS,
+ .up_symbol = NULL, .prefix = 202, .brk = true },
+ [78] = { .ascii = false, .symbol = KBD_KEYPAD_PLUS,
+ .up_symbol = NULL, .prefix = 206 },
+ [206] = { .ascii = false, .symbol = KBD_KEYPAD_PLUS,
+ .up_symbol = NULL, .prefix = 206, .brk = true },
+ [1] = { .ascii = false, .symbol = KBD_ESC,
+ .up_symbol = NULL, .prefix = 129 },
+ [129] = { .ascii = false, .symbol = KBD_ESC,
+ .up_symbol = NULL, .prefix = 129, .brk = true },
+ [59] = { .ascii = false, .symbol = KBD_F1,
+ .up_symbol = NULL, .prefix = 187 },
+ [187] = { .ascii = false, .symbol = KBD_F1,
+ .up_symbol = NULL, .prefix = 187, .brk = true },
+ [60] = { .ascii = false, .symbol = KBD_F2,
+ .up_symbol = NULL, .prefix = 188 },
+ [188] = { .ascii = false, .symbol = KBD_F2,
+ .up_symbol = NULL, .prefix = 188, .brk = true },
+ [61] = { .ascii = false, .symbol = KBD_F3,
+ .up_symbol = NULL, .prefix = 189 },
+ [189] = { .ascii = false, .symbol = KBD_F3,
+ .up_symbol = NULL, .prefix = 189, .brk = true },
+ [62] = { .ascii = false, .symbol = KBD_F4,
+ .up_symbol = NULL, .prefix = 190 },
+ [190] = { .ascii = false, .symbol = KBD_F4,
+ .up_symbol = NULL, .prefix = 190, .brk = true },
+ [63] = { .ascii = false, .symbol = KBD_F5,
+ .up_symbol = NULL, .prefix = 191 },
+ [191] = { .ascii = false, .symbol = KBD_F5,
+ .up_symbol = NULL, .prefix = 191, .brk = true },
+ [64] = { .ascii = false, .symbol = KBD_F6,
+ .up_symbol = NULL, .prefix = 192 },
+ [192] = { .ascii = false, .symbol = KBD_F6,
+ .up_symbol = NULL, .prefix = 192, .brk = true },
+ [65] = { .ascii = false, .symbol = KBD_F7,
+ .up_symbol = NULL, .prefix = 193 },
+ [193] = { .ascii = false, .symbol = KBD_F7,
+ .up_symbol = NULL, .prefix = 193, .brk = true },
+ [66] = { .ascii = false, .symbol = KBD_F8,
+ .up_symbol = NULL, .prefix = 194 },
+ [194] = { .ascii = false, .symbol = KBD_F8,
+ .up_symbol = NULL, .prefix = 194, .brk = true },
+ [67] = { .ascii = false, .symbol = KBD_F9,
+ .up_symbol = NULL, .prefix = 195 },
+ [195] = { .ascii = false, .symbol = KBD_F9,
+ .up_symbol = NULL, .prefix = 195, .brk = true },
+ [68] = { .ascii = false, .symbol = KBD_F10,
+ .up_symbol = NULL, .prefix = 196 },
+ [196] = { .ascii = false, .symbol = KBD_F10,
+ .up_symbol = NULL, .prefix = 196, .brk = true },
+ [87] = { .ascii = false, .symbol = KBD_F11,
+ .up_symbol = NULL, .prefix = 215 },
+ [215] = { .ascii = false, .symbol = KBD_F11,
+ .up_symbol = NULL, .prefix = 215, .brk = true },
+ [88] = { .ascii = false, .symbol = KBD_F12,
+ .up_symbol = NULL, .prefix = 216 },
+ [216] = { .ascii = false, .symbol = KBD_F12,
+ .up_symbol = NULL, .prefix = 216, .brk = true },
+ [70] = { .ascii = false, .symbol = KBD_SCROLL_LOCK,
+ .up_symbol = NULL, .prefix = 198 },
+ [198] = { .ascii = false, .symbol = KBD_SCROLL_LOCK,
+ .up_symbol = NULL, .prefix = 198, .brk = true },
+ [43] = { .ascii = true, .symbol = '\\',
+ .up_symbol = '|', .prefix = 171 },
+ [171] = { .ascii = true, .symbol = '\\',
+ .up_symbol = '|', .prefix = 171, .brk = true },
+};
+
+
+const struct kbd_scan_codes scan_code_set_3[0xff] =
+{
+ [14] = { .ascii = true, .symbol = '`',
+ .up_symbol = '~', .prefix = 240 },
+ [22] = { .ascii = true, .symbol = '1',
+ .up_symbol = '!', .prefix = 240 },
+ [30] = { .ascii = true, .symbol = '2',
+ .up_symbol = '@', .prefix = 240 },
+ [38] = { .ascii = true, .symbol = '3',
+ .up_symbol = '#', .prefix = 240 },
+ [37] = { .ascii = true, .symbol = '4',
+ .up_symbol = '$', .prefix = 240 },
+ [46] = { .ascii = true, .symbol = '5',
+ .up_symbol = '%', .prefix = 240 },
+ [54] = { .ascii = true, .symbol = '6',
+ .up_symbol = '^', .prefix = 240 },
+ [61] = { .ascii = true, .symbol = '7',
+ .up_symbol = '&', .prefix = 240 },
+ [62] = { .ascii = true, .symbol = '8',
+ .up_symbol = '*', .prefix = 240 },
+ [70] = { .ascii = true, .symbol = '9',
+ .up_symbol = '(', .prefix = 240 },
+ [69] = { .ascii = true, .symbol = '0',
+ .up_symbol = ')', .prefix = 240 },
+ [78] = { .ascii = true, .symbol = '-',
+ .up_symbol = '_', .prefix = 240 },
+ [85] = { .ascii = true, .symbol = '=',
+ .up_symbol = '+', .prefix = 240 },
+ [102] = { .ascii = false, .symbol = KBD_BACKSPACE,
+ .up_symbol = NULL, .prefix = 240 },
+ [13] = { .ascii = false, .symbol = KBD_TAB,
+ .up_symbol = NULL, .prefix = 240 },
+ [21] = { .ascii = true, .symbol = 'q',
+ .up_symbol = 'Q', .prefix = 240 },
+ [29] = { .ascii = true, .symbol = 'w',
+ .up_symbol = 'W', .prefix = 240 },
+ [36] = { .ascii = true, .symbol = 'e',
+ .up_symbol = 'E', .prefix = 240 },
+ [45] = { .ascii = true, .symbol = 'r',
+ .up_symbol = 'R', .prefix = 240 },
+ [44] = { .ascii = true, .symbol = 't',
+ .up_symbol = 'T', .prefix = 240 },
+ [53] = { .ascii = true, .symbol = 'y',
+ .up_symbol = 'Y', .prefix = 240 },
+ [60] = { .ascii = true, .symbol = 'u',
+ .up_symbol = 'U', .prefix = 240 },
+ [67] = { .ascii = true, .symbol = 'i',
+ .up_symbol = 'I', .prefix = 240 },
+ [68] = { .ascii = true, .symbol = 'o',
+ .up_symbol = 'O', .prefix = 240 },
+ [77] = { .ascii = true, .symbol = 'p',
+ .up_symbol = 'P', .prefix = 240 },
+ [84] = { .ascii = true, .symbol = '[',
+ .up_symbol = '{', .prefix = 240 },
+ [91] = { .ascii = true, .symbol = ']',
+ .up_symbol = '}', .prefix = 240 },
+ [88] = { .ascii = false, .symbol = KBD_CAPS_LOCK,
+ .up_symbol = NULL, .prefix = 240 },
+ [28] = { .ascii = true, .symbol = 'a',
+ .up_symbol = 'A', .prefix = 240 },
+ [27] = { .ascii = true, .symbol = 's',
+ .up_symbol = 'S', .prefix = 240 },
+ [35] = { .ascii = true, .symbol = 'd',
+ .up_symbol = 'D', .prefix = 240 },
+ [43] = { .ascii = true, .symbol = 'f',
+ .up_symbol = 'F', .prefix = 240 },
+ [52] = { .ascii = true, .symbol = 'g',
+ .up_symbol = 'G', .prefix = 240 },
+ [51] = { .ascii = true, .symbol = 'h',
+ .up_symbol = 'H', .prefix = 240 },
+ [59] = { .ascii = true, .symbol = 'j',
+ .up_symbol = 'J', .prefix = 240 },
+ [66] = { .ascii = true, .symbol = 'k',
+ .up_symbol = 'K', .prefix = 240 },
+ [75] = { .ascii = true, .symbol = 'l',
+ .up_symbol = 'L', .prefix = 240 },
+ [76] = { .ascii = true, .symbol = ';',
+ .up_symbol = ':', .prefix = 240 },
+ [82] = { .ascii = true, .symbol = '\'',
+ .up_symbol = '"', .prefix = 240 },
+ [90] = { .ascii = false, .symbol = KBD_ENTER,
+ .up_symbol = NULL, .prefix = 240 },
+ [18] = { .ascii = false, .symbol = KBD_LEFT_SHIFT,
+ .up_symbol = NULL, .prefix = 240 },
+ [26] = { .ascii = true, .symbol = 'z',
+ .up_symbol = 'Z', .prefix = 240 },
+ [34] = { .ascii = true, .symbol = 'x',
+ .up_symbol = 'X', .prefix = 240 },
+ [33] = { .ascii = true, .symbol = 'c',
+ .up_symbol = 'C', .prefix = 240 },
+ [42] = { .ascii = true, .symbol = 'v',
+ .up_symbol = 'V', .prefix = 240 },
+ [50] = { .ascii = true, .symbol = 'b',
+ .up_symbol = 'B', .prefix = 240 },
+ [49] = { .ascii = true, .symbol = 'n',
+ .up_symbol = 'N', .prefix = 240 },
+ [58] = { .ascii = true, .symbol = 'm',
+ .up_symbol = 'M', .prefix = 240 },
+ [65] = { .ascii = true, .symbol = ',',
+ .up_symbol = '<', .prefix = 240 },
+ [73] = { .ascii = true, .symbol = '.',
+ .up_symbol = '>', .prefix = 240 },
+ [74] = { .ascii = true, .symbol = '/',
+ .up_symbol = '?', .prefix = 240 },
+ [89] = { .ascii = false, .symbol = KBD_RIGHT_SHIFT,
+ .up_symbol = NULL, .prefix = 240 },
+ [17] = { .ascii = false, .symbol = KBD_LEFT_CTRL,
+ .up_symbol = NULL, .prefix = 240 },
+ [25] = { .ascii = false, .symbol = KBD_LEFT_ALT,
+ .up_symbol = NULL, .prefix = 240 },
+ [41] = { .ascii = false, .symbol = KBD_SPACEBAR,
+ .up_symbol = NULL, .prefix = 240 },
+ [57] = { .ascii = false, .symbol = KBD_RIGHT_ALT,
+ .up_symbol = NULL, .prefix = 240 },
+ [88] = { .ascii = false, .symbol = KBD_RIGHT_CTRL,
+ .up_symbol = NULL, .prefix = 240 },
+ [103] = { .ascii = false, .symbol = KBD_INSERT,
+ .up_symbol = NULL, .prefix = 240 },
+ [100] = { .ascii = false, .symbol = KBD_DELETE,
+ .up_symbol = NULL, .prefix = 240 },
+ [97] = { .ascii = false, .symbol = KBD_LEFT_ARROW,
+ .up_symbol = NULL, .prefix = 240 },
+ [110] = { .ascii = false, .symbol = KBD_HOME,
+ .up_symbol = NULL, .prefix = 240 },
+ [101] = { .ascii = false, .symbol = KBD_END,
+ .up_symbol = NULL, .prefix = 240 },
+ [99] = { .ascii = false, .symbol = KBD_UP_ARROW,
+ .up_symbol = NULL, .prefix = 240 },
+ [96] = { .ascii = false, .symbol = KBD_DOWN_ARROW,
+ .up_symbol = NULL, .prefix = 240 },
+ [111] = { .ascii = false, .symbol = KBD_PAGE_UP,
+ .up_symbol = NULL, .prefix = 240 },
+ [109] = { .ascii = false, .symbol = KBD_PAGE_DOWN,
+ .up_symbol = NULL, .prefix = 240 },
+ [106] = { .ascii = false, .symbol = KBD_RIGHT_ARROW,
+ .up_symbol = NULL, .prefix = 240 },
+ [118] = { .ascii = false, .symbol = KBD_NUM_LOCK,
+ .up_symbol = NULL, .prefix = 240 },
+ [108] = { .ascii = false, .symbol = KBD_KEYPAD_7,
+ .up_symbol = NULL, .prefix = 240 },
+ [107] = { .ascii = false, .symbol = KBD_KEYPAD_4,
+ .up_symbol = NULL, .prefix = 240 },
+ [105] = { .ascii = false, .symbol = KBD_KEYPAD_1,
+ .up_symbol = NULL, .prefix = 240 },
+ [119] = { .ascii = false, .symbol = KBD_KEYPAD_DIV,
+ .up_symbol = NULL, .prefix = 240 },
+ [117] = { .ascii = false, .symbol = KBD_KEYPAD_8,
+ .up_symbol = NULL, .prefix = 240 },
+ [115] = { .ascii = false, .symbol = KBD_KEYPAD_5,
+ .up_symbol = NULL, .prefix = 240 },
+ [114] = { .ascii = false, .symbol = KBD_KEYPAD_2,
+ .up_symbol = NULL, .prefix = 240 },
+ [112] = { .ascii = false, .symbol = KBD_KEYPAD_0,
+ .up_symbol = NULL, .prefix = 240 },
+ [126] = { .ascii = false, .symbol = KBD_KEYPAD_TIMES,
+ .up_symbol = NULL, .prefix = 240 },
+ [125] = { .ascii = false, .symbol = KBD_KEYPAD_9,
+ .up_symbol = NULL, .prefix = 240 },
+ [116] = { .ascii = false, .symbol = KBD_KEYPAD_6,
+ .up_symbol = NULL, .prefix = 240 },
+ [122] = { .ascii = false, .symbol = KBD_KEYPAD_3,
+ .up_symbol = NULL, .prefix = 240 },
+ [113] = { .ascii = false, .symbol = KBD_KEYPAD_DOT,
+ .up_symbol = NULL, .prefix = 240 },
+ [132] = { .ascii = false, .symbol = KBD_KEYPAD_MINUS,
+ .up_symbol = NULL, .prefix = 240 },
+ [124] = { .ascii = false, .symbol = KBD_KEYPAD_PLUS,
+ .up_symbol = NULL, .prefix = 240 },
+ [121] = { .ascii = false, .symbol = KBD_KEYPAD_ENTER,
+ .up_symbol = NULL, .prefix = 240 },
+ [8] = { .ascii = false, .symbol = KBD_ESC,
+ .up_symbol = NULL, .prefix = 240 },
+ [7] = { .ascii = false, .symbol = KBD_F1,
+ .up_symbol = NULL, .prefix = 240 },
+ [15] = { .ascii = false, .symbol = KBD_F2,
+ .up_symbol = NULL, .prefix = 240 },
+ [23] = { .ascii = false, .symbol = KBD_F3,
+ .up_symbol = NULL, .prefix = 240 },
+ [31] = { .ascii = false, .symbol = KBD_F4,
+ .up_symbol = NULL, .prefix = 240 },
+ [39] = { .ascii = false, .symbol = KBD_F5,
+ .up_symbol = NULL, .prefix = 240 },
+ [47] = { .ascii = false, .symbol = KBD_F6,
+ .up_symbol = NULL, .prefix = 240 },
+ [55] = { .ascii = false, .symbol = KBD_F7,
+ .up_symbol = NULL, .prefix = 240 },
+ [63] = { .ascii = false, .symbol = KBD_F8,
+ .up_symbol = NULL, .prefix = 240 },
+ [71] = { .ascii = false, .symbol = KBD_F9,
+ .up_symbol = NULL, .prefix = 240 },
+ [79] = { .ascii = false, .symbol = KBD_F10,
+ .up_symbol = NULL, .prefix = 240 },
+ [86] = { .ascii = false, .symbol = KBD_F11,
+ .up_symbol = NULL, .prefix = 240 },
+ [94] = { .ascii = false, .symbol = KBD_F12,
+ .up_symbol = NULL, .prefix = 240 },
+ [87] = { .ascii = false, .symbol = KBD_PRINT_SCREEN,
+ .up_symbol = NULL, .prefix = 240 },
+ [95] = { .ascii = false, .symbol = KBD_SCROLL_LOCK,
+ .up_symbol = NULL, .prefix = 240 },
+ [98] = { .ascii = false, .symbol = KBD_PAUSE_BREAK,
+ .up_symbol = NULL, .prefix = 240 },
+ [92] = { .ascii = true, .symbol = '\\',
+ .up_symbol = '|', .prefix = 240 },
+};
diff --git a/src/kernel/scan_codes.tsv b/src/kernel/scan_codes.tsv
new file mode 100644
index 0000000..d036329
--- /dev/null
+++ b/src/kernel/scan_codes.tsv
@@ -0,0 +1,102 @@
+IBM Key No. Set 1 Make/Break Set 2 Make/Break Set 3 Make/Break Base Case Upper Case Is ASCII char Symbol Uppercase Symbol
+1 29/A9 0E/F0 0E 0E/F0 0E ` ~ yes '`' '~'
+2 02/82 16/F0 16 16/F0 16 1 ! yes '1' '!'
+3 03/83 1E/F0 1E 1E/F0 1E 2 @ yes '2' '@'
+4 04/84 26/F0 26 26/F0 26 3 # yes '3' '#'
+5 05/85 25/F0 25 25/F0 25 4 $ yes '4' '$'
+6 06/86 2E/F0 2E 2E/F0 2E 5 % yes '5' '%'
+7 07/87 36/F0 36 36/F0 36 6 ^ yes '6' '^'
+8 08/88 3D/F0 3D 3D/F0 3D 7 & yes '7' '&'
+9 09/89 3E/F0 3E 3E/F0 3E 8 * yes '8' '*'
+10 0A/8A 46/F0 46 46/F0 46 9 ( yes '9' '('
+11 0B/8B 45/F0 45 45/F0 45 0 ) yes '0' ')'
+12 0C/8C 4E/F0 4E 4E/F0 4E - _ yes '-' '_'
+13 0D/8D 55/F0 55 55/F0 55 = + yes '=' '+'
+15 0E/8E 66/F0 66 66/F0 66 Backspace no KBD_BACKSPACE NULL
+16 0F/8F 0D/F0 0D 0D/F0 0D Tab no KBD_TAB NULL
+17 10/90 15/F0 15 15/F0 15 q Q yes 'q' 'Q'
+18 11/91 1D/F0 1D 1D/F0 1D w W yes 'w' 'W'
+19 12/92 24/F0 24 24/F0 24 e E yes 'e' 'E'
+20 13/93 2D/F0 2D 2D/F0 2D r R yes 'r' 'R'
+21 14/94 2C/F0 2C 2C/F0 2C t T yes 't' 'T'
+22 15/95 35/F0 35 35/F0 35 y Y yes 'y' 'Y'
+23 16/96 3C/F0 3C 3C/F0 3C u U yes 'u' 'U'
+24 17/97 43/F0 43 43/F0 43 i I yes 'i' 'I'
+25 18/98 44/F0 44 44/F0 44 o O yes 'o' 'O'
+26 19/99 4D/F0 4D 4D/F0 4D p P yes 'p' 'P'
+27 1A/9A 54/F0 54 54/F0 54 [ { yes '[' '{'
+28 1B/9B 5B/F0 5B 5B/F0 5B ] } yes ']' '}'
+30 3A/BA 58/F0 58 58/F0 58 Caps Lock no KBD_CAPS_LOCK NULL
+31 1E/9E 1C/F0 1C 1C/F0 1C a A yes 'a' 'A'
+32 1F/9F 1B/F0 1B 1B/F0 1B s S yes 's' 'S'
+33 20/A0 23/F0 23 23/F0 23 d D yes 'd' 'D'
+34 21/A1 2B/F0 2B 2B/F0 2B f F yes 'f' 'F'
+35 22/A2 34/F0 34 34/F0 34 g G yes 'g' 'G'
+36 23/A3 33/F0 33 33/F0 33 h H yes 'h' 'H'
+37 24/A4 3B/F0 3B 3B/F0 3B j J yes 'j' 'J'
+38 25/A5 42/F0 42 42/F0 42 k K yes 'k' 'K'
+39 26/A6 4B/F0 4B 4B/F0 4B l L yes 'l' 'L'
+40 27/A7 4C/F0 4C 4C/F0 4C ; : yes ';' ':'
+41 28/A8 52/F0 52 52/F0 52 ' " yes '\'' '"'
+43 1C/9C 5A/F0 5A 5A/F0 5A Enter Enter no KBD_ENTER NULL
+44 2A/AA 12/F0 12 12/F0 12 Left Shift no KBD_LEFT_SHIFT NULL
+46 2C/AC 1A/F0 1A 1A/F0 1A z Z yes 'z' 'Z'
+47 2D/AD 22/F0 22 22/F0 22 x X yes 'x' 'X'
+48 2E/AE 21/F0 21 21/F0 21 c C yes 'c' 'C'
+49 2F/AF 2A/F0 2A 2A/F0 2A v V yes 'v' 'V'
+50 30/B0 32/F0 32 32/F0 32 b B yes 'b' 'B'
+51 31/B1 31/F0 31 31/F0 31 n N yes 'n' 'N'
+52 32/B2 3A/F0 3A 3A/F0 3A m M yes 'm' 'M'
+53 33/B3 41/F0 41 41/F0 41 , < yes ',' '<'
+54 34/B4 49/F0 49 49/F0 49 . > yes '.' '>'
+55 35/B5 4A/F0 4A 4A/F0 4A / ? yes '/' '?'
+57 36/B6 59/F0 59 59/F0 59 Right Shift no KBD_RIGHT_SHIFT NULL
+58 1D/9D 14/F0 14 11/F0 11 Left Ctrl no KBD_LEFT_CTRL NULL
+60 38/B8 11/F0 11 19/F0 19 Left Alt no KBD_LEFT_ALT NULL
+61 39/B9 29/F0 29 29/F0 29 Spacebar no KBD_SPACEBAR NULL
+62 E0 38/E0 B8 E0 11/E0 F0 11 39/F0 39 Right Alt no KBD_RIGHT_ALT NULL
+64 E0 1D/E0 9D E0 14/E0 F0 14 58/F0 58 Right Ctrl no KBD_RIGHT_CTRL NULL
+75 E0 52/E0 D2 (base) E0 70/E0 F0 70 (base) 67/F0 67 Insert no KBD_INSERT NULL
+76 E0 4B/E0 CB (base) E0 71/E0 F0 71 (base) 64/F0 64 Delete no KBD_DELETE NULL
+79 E0 4B/E0 CB (base) E0 6B/E0 F0 6B (base) 61/F0 61 Left Arrow no KBD_LEFT_ARROW NULL
+80 E0 47/E0 C7 (base) E0 6C/E0 F0 6C (base) 6E/F0 6E Home no KBD_HOME NULL
+81 E0 4F/E0 CF (base) E0 69/E0 F0 69 (base) 65/F0 65 End no KBD_END NULL
+83 E0 48/E0 C8 (base) E0 75/E0 F0 75 (base) 63/F0 63 Up Arrow no KBD_UP_ARROW NULL
+84 E0 50/E0 D0 (base) E0 72/E0 F0 72 (base) 60/F0 60 Down Arrow no KBD_DOWN_ARROW NULL
+85 E0 49/E0 C9 (base) E0 7D/E0 F0 7D (base) 6F/F0 6F Page Up no KBD_PAGE_UP NULL
+86 E0 51/E0 D1 (base) E0 7A/E0 F0 7A (base) 6D/F0 6D Page Down no KBD_PAGE_DOWN NULL
+89 E0 4D/E0 CD (base) E0 74/E0 F0 74 (base) 6A/F0 6A Right Arrow no KBD_RIGHT_ARROW NULL
+90 45/C5 77/F0 77 76/F0 76 Num Lock no KBD_NUM_LOCK NULL
+91 47/C7 6C/F0 6C 6C/F0 6C Keypad 7 no KBD_KEYPAD_7 NULL
+92 4B/CB 6B/F0 6B 6B/F0 6B Keypad 4 no KBD_KEYPAD_4 NULL
+93 4F/CF 69/F0 69 69/F0 69 Keypad 1 no KBD_KEYPAD_1 NULL
+95 E0 35/E0 B5 (base) E0 4A/E0 F0 4A (base) 77/F0 77 Keypad / no KBD_KEYPAD_/ NULL
+96 48/C8 75/F0 75 75/F0 75 Keypad 8 no KBD_KEYPAD_8 NULL
+97 4C/CC 73/F0 73 73/F0 73 Keypad 5 no KBD_KEYPAD_5 NULL
+98 50/D0 72/F0 72 72/F0 72 Keypad 2 no KBD_KEYPAD_2 NULL
+99 52/D2 70/F0 70 70/F0 70 Keypad 0 no KBD_KEYPAD_0 NULL
+100 37/B7 7C/F0 7C 7E/F0 7E Keypad * no KBD_KEYPAD_* NULL
+101 49/C9 7D/F0 7D 7D/F0 7D Keypad 9 no KBD_KEYPAD_9 NULL
+102 4D/CD 74/F0 74 74/F0 74 Keypad 6 no KBD_KEYPAD_6 NULL
+103 51/D1 7A/F0 7A 7A/F0 7A Keypad 3 no KBD_KEYPAD_3 NULL
+104 53/D3 71/F0 71 71/F0 71 Keypad . no KBD_KEYPAD_. NULL
+105 4A/CA 7B/F0 7B 84/F0 84 Keypad - no KBD_KEYPAD_- NULL
+106 4E/CE 79/F0 79 7C/F0 7C Keypad + no KBD_KEYPAD_+ NULL
+108 E0 1C/E0 9C E0 5A/E0 F0 5A 79/F0 79 Keypad Enter no KBD_KEYPAD_ENTER NULL
+110 01/81 76/F0 76 08/F0 08 Esc no KBD_ESC NULL
+112 3B/BB 05/F0 05 07/F0 07 F1 no KBD_F1 NULL
+113 3C/BC 06/F0 06 0F/F0 0F F2 no KBD_F2 NULL
+114 3D/BD 04/F0 04 17/F0 17 F3 no KBD_F3 NULL
+115 3E/BE 0C/F0 0C 1F/F0 1F F4 no KBD_F4 NULL
+116 3F/BF 03/F0 03 27/F0 27 F5 no KBD_F5 NULL
+117 40/C0 0B/F0 0B 2F/F0 2F F6 no KBD_F6 NULL
+118 41/C1 83/F0 83 37/F0 37 F7 no KBD_F7 NULL
+119 42/C2 0A/F0 0A 3F/F0 3F F8 no KBD_F8 NULL
+120 43/C3 01/F0 01 47/F0 47 F9 no KBD_F9 NULL
+121 44/C4 09/F0 09 4F/F0 4F F10 no KBD_F10 NULL
+122 57/D7 78/F0 78 56/F0 56 F11 no KBD_F11 NULL
+123 58/D8 07/F0 07 5E/F0 5E F12 no KBD_F12 NULL
+124 E0 2A E0 37/E0 B7 E0 AA E0 12 E0 7C/E0 F0 7C E0 F0 12 57/F0 57 Print Screen no KBD_PRINT_SCREEN NULL
+125 46/C6 7E/F0 7E 5F/F0 5F Scroll Lock no KBD_SCROLL_LOCK NULL
+126 E1 1D 45/E1 9D C5 E1 14 77 E1/F0 14 F0 77 62/F0 62 Pause Break no KBD_PAUSE_BREAK NULL
+29 2B/AB 5D/F0 5D 5C/F0 5C \ | yes '\\' '|'
\ No newline at end of file
diff --git a/src/kernel/srcmap.txt b/src/kernel/srcmap.txt
new file mode 100644
index 0000000..c9219a7
--- /dev/null
+++ b/src/kernel/srcmap.txt
@@ -0,0 +1,17 @@
++------------+
+| Source map |
++------------+
+
+
+Source File Description
+----------------------------------------------------------------
+io.c low level memory management stuff, io utils
+log.c logging, panics, assert, etc
+vga.c vga drivers
+timer.c sets up interrupt timer
+descriptor_tables.c sets up IDT and GDT
+paging.c sets up paging
+pic.c IRQ handler
+interrupts.c ISR handler
+boot.s calls kmain
+main.c entry point
diff --git a/src/kernel/stdarg.h b/src/kernel/stdarg.h
new file mode 100644
index 0000000..ce9bbc4
--- /dev/null
+++ b/src/kernel/stdarg.h
@@ -0,0 +1,130 @@
+/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ * ISO C Standard: 7.15 Variable arguments <stdarg.h>
+ */
+
+#ifndef _STDARG_H
+#ifndef _ANSI_STDARG_H_
+#ifndef __need___va_list
+#define _STDARG_H
+#define _ANSI_STDARG_H_
+#endif /* not __need___va_list */
+#undef __need___va_list
+
+/* Define __gnuc_va_list. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+/* Define the standard macros for the user,
+ if this invocation was from the user program. */
+#ifdef _STDARG_H
+
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || \
+ __cplusplus + 0 >= 201103L
+#define va_copy(d, s) __builtin_va_copy(d, s)
+#endif
+#define __va_copy(d, s) __builtin_va_copy(d, s)
+
+/* Define va_list, if desired, from __gnuc_va_list. */
+/* We deliberately do not define va_list when called from
+ stdio.h, because ANSI C says that stdio.h is not supposed to define
+ va_list. stdio.h needs to have access to that data type,
+ but must not use that name. It should use the name __gnuc_va_list,
+ which is safe because it is reserved for the implementation. */
+
+#ifdef _BSD_VA_LIST
+#undef _BSD_VA_LIST
+#endif
+
+#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
+/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
+ so we must avoid testing it and setting it here.
+ SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
+ have no conflict with that. */
+#ifndef _VA_LIST_
+#define _VA_LIST_
+#ifdef __i860__
+#ifndef _VA_LIST
+#define _VA_LIST va_list
+#endif
+#endif /* __i860__ */
+typedef __gnuc_va_list va_list;
+#ifdef _SCO_DS
+#define __VA_LIST
+#endif
+#endif /* _VA_LIST_ */
+#else /* not __svr4__ || _SCO_DS */
+
+/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+#if !defined(_VA_LIST_) || defined(__BSD_NET2__) || defined(____386BSD____) || \
+ defined(__bsdi__) || defined(__sequent__) || defined(__FreeBSD__) || \
+ defined(WINNT)
+/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */
+#ifndef _VA_LIST_DEFINED
+/* The macro _VA_LIST is used in SCO Unix 3.2. */
+#ifndef _VA_LIST
+/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+#ifndef _VA_LIST_T_H
+/* The macro __va_list__ is used by BeOS. */
+#ifndef __va_list__
+typedef __gnuc_va_list va_list;
+#endif /* not __va_list__ */
+#endif /* not _VA_LIST_T_H */
+#endif /* not _VA_LIST */
+#endif /* not _VA_LIST_DEFINED */
+#if !(defined(__BSD_NET2__) || defined(____386BSD____) || defined(__bsdi__) || \
+ defined(__sequent__) || defined(__FreeBSD__))
+#define _VA_LIST_
+#endif
+#ifndef _VA_LIST
+#define _VA_LIST
+#endif
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+#endif
+#ifndef _VA_LIST_T_H
+#define _VA_LIST_T_H
+#endif
+#ifndef __va_list__
+#define __va_list__
+#endif
+
+#endif /* not _VA_LIST_, except on certain systems */
+
+#endif /* not __svr4__ */
+
+#endif /* _STDARG_H */
+
+#endif /* not _ANSI_STDARG_H_ */
+#endif /* not _STDARG_H */
diff --git a/src/kernel/switch_table.s b/src/kernel/switch_table.s
new file mode 100644
index 0000000..d04629b
--- /dev/null
+++ b/src/kernel/switch_table.s
@@ -0,0 +1,25 @@
+ [section .text]
+ [bits 32]
+
+;;; TODO: remove useless frame pointer stuff
+
+ [global load_page_directory]
+load_page_directory:
+ push ebp ; Save frame pointer
+ mov ebp, esp
+ mov eax, [esp + 8] ; Pointer to directory
+ mov cr3, eax
+ mov esp, ebp
+ pop ebp
+ ret
+
+ [global enable_paging]
+enable_paging:
+ push ebp
+ mov ebp, esp
+ mov eax, cr0
+ or eax, 0x80000000
+ mov cr0, eax
+ mov esp, ebp
+ pop ebp
+ ret
diff --git a/src/kernel/timer.c b/src/kernel/timer.c
new file mode 100644
index 0000000..145f8f8
--- /dev/null
+++ b/src/kernel/timer.c
@@ -0,0 +1,32 @@
+#include "timer.h"
+#include "io.h"
+#include "log.h"
+#include "pic.h"
+#include "registers.h"
+
+static ulong tick = 0;
+
+static void timer_cb(struct registers *regs)
+{
+ // do nothing :)
+}
+
+void init_timer(uint hz)
+{
+ add_interrupt_handler(IRQ_TO_INT(0), timer_cb);
+
+ uint divisor = TIMER_FREQ / hz;
+
+ kprintf("Divisor is %d\n", divisor);
+
+ outb(0x43, 0x36);
+ io_wait();
+ uchar l = divisor & 0xff, h = (divisor >> 8) & 0xff;
+
+ outb(0x40, l);
+ io_wait();
+ outb(0x40, h);
+ io_wait();
+
+ kprintf("Initialized timer\n");
+}
diff --git a/src/kernel/timer.h b/src/kernel/timer.h
new file mode 100644
index 0000000..50297c4
--- /dev/null
+++ b/src/kernel/timer.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "kint.h"
+
+#define TIMER_FREQ 1193180
+
+void init_timer(uint hz);
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
new file mode 100644
index 0000000..bfd13e0
--- /dev/null
+++ b/src/kernel/vga.c
@@ -0,0 +1,133 @@
+#include "vga.h"
+#include "io.h"
+#include "log.h"
+
+static uint cursor_x = 0;
+static uint cursor_y = 0;
+
+static ushort color = WHITE;
+
+static ushort *fb = (ushort *)0xB8000;
+
+static void move_cursor()
+{
+ ushort loc = cursor_y * 80 + cursor_x;
+ outb(0x3d4, 14); // Setting high cursor byte
+ outb(0x3d4, loc >> 8);
+
+ outb(0x3d4, 15); // low byte
+ outb(0x3d4, loc & 0xff);
+}
+
+static void scroll()
+{
+ ushort blank = ' ' | color << 8;
+
+ while (cursor_y >= 25) // end of line
+ {
+ // scroll everything up
+ memcpy(fb, &fb[80], 24 * 80 * 2);
+
+ for (int i = 24 * 80; i < 25 * 80; i++)
+ {
+ fb[i] = blank;
+ }
+
+ cursor_y--;
+ }
+}
+
+void vga_set_color(enum vga_colors fg, enum vga_colors bg)
+{
+ color = (bg << 4) | fg & 0xf;
+}
+
+void vga_put(char c)
+{
+ switch (c)
+ {
+ case '\b':
+ if (cursor_x > 0)
+ cursor_x--;
+ fb[cursor_y * 80 + cursor_x] = ' ' | (color << 8);
+ break;
+ case '\t':
+ cursor_x = (cursor_x + 8) & ~7;
+ break;
+ case '\n':
+ cursor_y++;
+ case '\r':
+ cursor_x = 0;
+ break;
+ default:
+ fb[cursor_y * 80 + cursor_x] = c | (color << 8);
+ cursor_x++;
+ }
+
+ if (cursor_x >= 80) // off screen
+ {
+ cursor_x = 0;
+ cursor_y++;
+ }
+
+ scroll();
+ move_cursor();
+}
+
+void vga_clear()
+{
+ memset(fb, 0, 80 * 25 * 2);
+ cursor_x = 0;
+ cursor_y = 0;
+ move_cursor();
+}
+
+void vga_write(char *c)
+{
+ for (int i = 0; c[i]; i++)
+ vga_put(c[i]);
+}
+
+void vga_putd(uint d)
+{
+ char str[48];
+ memset(str, 0, 48);
+ uint i = 0;
+
+ do
+ {
+ str[i++] = (d % 10) + '0';
+ d /= 10;
+ } while (d > 0 && i < 48); // should never be more than 48 digits anyway
+
+ for (uint j = i; j; j--)
+ {
+ vga_put(str[j - 1]);
+ }
+}
+
+static bool vga_put_nibble(uchar n, bool first)
+{
+// if (first && n == 0)
+// return true;
+
+ if (n <= 9)
+ vga_put('0' + n);
+ else
+ vga_put('A' + n - 10);
+
+ return false;
+}
+
+void vga_putx(uint x)
+{
+ bool first = false;
+
+ for (int shift = 24; shift >= 0; shift -= 8)
+ {
+ uchar byte = x >> shift;
+
+ first = vga_put_nibble((byte & 0xf0) >> 4, first);
+ first = vga_put_nibble(byte & 0x0f, first);
+ }
+}
diff --git a/src/kernel/vga.h b/src/kernel/vga.h
new file mode 100644
index 0000000..9c7ba16
--- /dev/null
+++ b/src/kernel/vga.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "kint.h"
+
+enum vga_colors
+{
+ BLACK = 0,
+ BLUE,
+ GREEN,
+ CYAN,
+ RED,
+ MAGENTA,
+ BROWN,
+ LIGHT_GREY,
+ DARK_GREY,
+ LIGHT_BLUE,
+ LIGHT_GREEN,
+ LIGHT_CYAN,
+ LIGHT_RED,
+ LIGHT_MAGENTA,
+ LIGHT_BROWN,
+ WHITE,
+};
+
+void vga_set_color(enum vga_colors fg, enum vga_colors bg);
+void vga_put(char c);
+void vga_putd(uint d);
+void vga_putx(uint x);
+void vga_clear();
+void vga_write(char *c);