summaryrefslogtreecommitdiff
path: root/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src')
-rw-r--r--kernel/src/boot/boot.S181
-rw-r--r--kernel/src/boot/boot64.S19
-rw-r--r--kernel/src/boot/header.S40
-rw-r--r--kernel/src/boot/multiboot2.c41
-rw-r--r--kernel/src/cpu/idt.c88
-rw-r--r--kernel/src/cpu/io.c13
-rw-r--r--kernel/src/cpu/irq.c289
-rw-r--r--kernel/src/cpu/irq_stub.S108
-rw-r--r--kernel/src/cpu/pic.c24
-rw-r--r--kernel/src/devices/keyboard.c20
-rw-r--r--kernel/src/grub.cfg8
-rw-r--r--kernel/src/kernel.ld39
-rw-r--r--kernel/src/main.c18
-rw-r--r--kernel/src/misc/debug.c6
-rw-r--r--kernel/src/misc/graphics.c119
15 files changed, 1013 insertions, 0 deletions
diff --git a/kernel/src/boot/boot.S b/kernel/src/boot/boot.S
new file mode 100644
index 0000000..ee35eeb
--- /dev/null
+++ b/kernel/src/boot/boot.S
@@ -0,0 +1,181 @@
+.global _start
+.extern begin_long_mode
+
+.section .text
+.code32
+
+_start:
+ cli
+ mov $stack_top, %esp
+ pushl $0
+ pushl %eax
+ pushl $0
+ pushl %ebx
+
+ call check_multiboot
+ call check_cpuid
+ call check_long_mode
+
+ call setup_page_tables
+ call enable_paging
+
+ lgdt gdt_pointer
+ ljmp $0x08, $begin_long_mode
+
+
+check_multiboot:
+ cmp $0x36d76289, %eax
+ jne no_multiboot
+
+ ret
+
+check_cpuid:
+ pushfl
+ pop %eax
+ mov %eax, %ecx
+ xor $1<<21, %eax
+ push %eax
+ popfl
+ pushfl
+ pop %eax
+ push %ecx
+ popfl
+ cmp %eax, %ecx
+ je no_cpuid
+
+ ret
+
+check_long_mode:
+ mov $0x80000000, %eax
+ cpuid
+ cmp $0x80000001, %eax
+ jb no_long_mode
+
+ mov $0x80000001, %eax
+ cpuid
+ test $1<<29, %edx
+ jz no_long_mode
+
+ ret
+
+setup_page_tables:
+ mov $page_table_lvl3, %eax
+ or $0x3, %eax
+ mov %eax, page_table_lvl4
+
+ mov $page_table_lvl2, %eax
+ or $0x3, %eax
+ mov %eax, page_table_lvl3
+
+ mov $page_table_lvl2 + 4096, %eax
+ or $0x3, %eax
+ mov %eax, page_table_lvl3+8
+
+ mov $page_table_lvl2 + 8192, %eax
+ or $0x3, %eax
+ mov %eax, page_table_lvl3+16
+
+ mov $page_table_lvl2 + 12288, %eax
+ or $0x3, %eax
+ mov %eax, page_table_lvl3+24
+
+
+ movl $0, %ecx
+1:
+ movl $0x200000, %eax
+ mul %ecx
+ or $0b10000011, %eax
+ movl $page_table_lvl2, %edx
+ leal (%edx, %ecx, 8), %edx
+ movl %eax, (%edx)
+ inc %ecx
+ cmp $512*4, %ecx
+ jne 1b
+
+ ret
+
+enable_paging:
+ // enable PAE
+ mov %cr4, %edx
+ or $1<<5 ,%edx
+ mov %edx, %cr4
+
+ // set LME (long mode enable)
+ mov $0xC0000080, %ecx
+ rdmsr
+ or $1<<8, %eax
+ wrmsr
+
+ // page_table_lvl4
+ mov $page_table_lvl4, %eax
+ mov %eax, %cr3
+
+ // enable paging (+ protected mode if not already enabled)
+ mov %cr0, %eax
+ or $1<<31 + 1<<0, %eax
+ mov %eax, %cr0
+
+ ret
+
+no_multiboot:
+ hlt
+
+no_cpuid:
+ hlt
+
+no_long_mode:
+ hlt
+
+
+.section .bss
+.align 4096
+
+// stack
+stack_bottom:
+ .skip 4096*4
+stack_top:
+
+// page tables
+page_table_lvl4:
+ .skip 4096
+page_table_lvl3:
+ .skip 4096
+// map first 4GB
+page_table_lvl2:
+ .skip 4096*4
+
+// Access bits
+.section .rodata
+.set PRESENT, 1 << 7
+.set NOT_SYS, 1 << 4
+.set EXEC, 1 << 3
+.set DC, 1 << 2
+.set RW, 1 << 1
+.set ACCESSED, 1 << 0
+
+// Flags bits
+.set GRAN_4K, 1 << 7
+.set SZ_32, 1 << 6
+.set LONG_MODE, 1 << 5
+
+gdt:
+gdt_null = . - gdt
+ .quad 0
+gdt_code = . - gdt
+ .long 0xFFFF // Limit & Base (low, bits 0-15)
+ .byte 0 // Base (mid, bits 16-23)
+ .byte PRESENT | NOT_SYS | EXEC | RW // Access
+ .byte GRAN_4K | LONG_MODE | 0xF // Flags & Limit (high, bits 16-19)
+ .byte 0 // Base (high, bits 24-31)
+gdt_data = . - gdt
+ .long 0xFFFF
+ .byte 0
+ .byte PRESENT | NOT_SYS | RW
+ .byte GRAN_4K | SZ_32 | 0xF
+ .byte 0
+gdt_tss = . - gdt
+ .long 0x00000068
+ .long 0x00CF8900
+gdt_pointer:
+ .word . - gdt - 1
+ .quad gdt
diff --git a/kernel/src/boot/boot64.S b/kernel/src/boot/boot64.S
new file mode 100644
index 0000000..be87412
--- /dev/null
+++ b/kernel/src/boot/boot64.S
@@ -0,0 +1,19 @@
+.global begin_long_mode
+
+.section .text
+.code64
+
+begin_long_mode:
+ // reload segment registers
+ mov $0x10, %eax
+ mov %eax, %ss
+ mov %eax, %ds
+ mov %eax, %es
+ mov %eax, %fs
+ mov %eax, %gs
+
+ popq %rdi
+ popq %rsi
+
+ call kernel_main
+ hlt
diff --git a/kernel/src/boot/header.S b/kernel/src/boot/header.S
new file mode 100644
index 0000000..bbcb9be
--- /dev/null
+++ b/kernel/src/boot/header.S
@@ -0,0 +1,40 @@
+// multiboot tags
+.set TAG_END, 0
+.set TAG_FRAMEBUFFER, 5
+
+// multiboot flags
+.set TAG_REQUIRED, 0
+.set TAG_OPTIONAL, 1
+
+# multiboot2 header constants
+.set MAGIC, 0xe85250d6
+.set ARCH, 0
+.set HEADER_LENGTH, (header_end - header_start)
+.set CHECKSUM, 0x100000000 - (MAGIC + ARCH + HEADER_LENGTH)
+
+.section .multiboot_header, "a"
+.align 4
+header_start:
+ # magic
+ .align 8
+ .long MAGIC
+ .long ARCH
+ .long HEADER_LENGTH
+ .long CHECKSUM
+
+ # framebuffer
+ .align 8
+ .word TAG_FRAMEBUFFER
+ .word TAG_REQUIRED
+ .long 20
+ .long 1024
+ .long 768
+ .long 32
+
+ # end tag
+ .align 8
+ .word TAG_END
+ .word TAG_REQUIRED
+ .long 8
+
+header_end:
diff --git a/kernel/src/boot/multiboot2.c b/kernel/src/boot/multiboot2.c
new file mode 100644
index 0000000..e228ce1
--- /dev/null
+++ b/kernel/src/boot/multiboot2.c
@@ -0,0 +1,41 @@
+#include <stdint.h>
+#include <multiboot2.h>
+#include <graphics.h>
+
+fb_t fb;
+
+/* https://www.gnu.org/software/grub/manual/multiboot2/html_node/Boot-information-format.html */
+
+void init_fb(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic)
+{
+ if (multiboot_magic != MB2_MAGIC) {
+ // not loaded by multiboot2 bootloader
+ __asm__ volatile ("hlt;");
+ }
+
+ // we will store framebuffer information here
+ static mb2_tag_fb* tag_fb;
+
+ // skip first 8 bytes (total_size + reserved)
+ mb2_tag_header* tag_header = multiboot_bootinfo + 1;
+
+ while (tag_header->type != MB2_TAG_END) {
+ // process tag_type
+ switch(tag_header->type) {
+ case MB2_TAG_FB:
+ tag_fb = (mb2_tag_fb*)tag_header;
+ break;
+ default:
+ break;
+ }
+
+ // next mb2_tag
+ tag_header += tag_header->size / 8 + ((tag_header->size % 8) > 0);
+ }
+
+ fb.addr = tag_fb->framebuffer_addr;
+ fb.width = tag_fb->framebuffer_width;
+ fb.height = tag_fb->framebuffer_height;
+ fb.pitch = tag_fb->framebuffer_pitch;
+ fb.bpp = tag_fb->framebuffer_bpp;
+}
diff --git a/kernel/src/cpu/idt.c b/kernel/src/cpu/idt.c
new file mode 100644
index 0000000..bf285b7
--- /dev/null
+++ b/kernel/src/cpu/idt.c
@@ -0,0 +1,88 @@
+#include <idt.h>
+#include <irq.h>
+#include <pic.h>
+
+__attribute__((aligned(0x10))) static idt_entry idt_table[256];
+idtp idt_pointer;
+
+void load_idt(idtp* pointer)
+{
+ __asm__ volatile ("lidt (%0); sti;" : : "r"(pointer) : );
+}
+
+void add_to_idt(uint16_t num, uint64_t offset, uint16_t selector, uint8_t type)
+{
+ idt_table[num].offset_1 = offset & 0xFFFF;
+ idt_table[num].offset_2 = (offset >> 16) & 0xFFFF;
+ idt_table[num].offset_3 = offset >> 32;
+ idt_table[num].selector = selector;
+ idt_table[num].type_attributes = type;
+ idt_table[num].ist = 0;
+ idt_table[num].zero = 0;
+}
+
+void init_idt_table(void)
+{
+ // exceptions
+ add_to_idt(0, (uint64_t)isr0, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(1, (uint64_t)isr1, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(2, (uint64_t)isr2, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(3, (uint64_t)isr3, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(4, (uint64_t)isr4, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(5, (uint64_t)isr5, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(6, (uint64_t)isr6, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(7, (uint64_t)isr7, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(8, (uint64_t)isr8, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(9, (uint64_t)isr9, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(10, (uint64_t)isr10, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(11, (uint64_t)isr11, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(12, (uint64_t)isr12, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(13, (uint64_t)isr13, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(14, (uint64_t)isr14, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(15, (uint64_t)isr15, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(16, (uint64_t)isr16, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(17, (uint64_t)isr17, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(18, (uint64_t)isr18, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(19, (uint64_t)isr19, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(20, (uint64_t)isr20, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(21, (uint64_t)isr21, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(22, (uint64_t)isr22, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(23, (uint64_t)isr23, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(24, (uint64_t)isr24, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(25, (uint64_t)isr25, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(26, (uint64_t)isr26, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(27, (uint64_t)isr27, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(28, (uint64_t)isr28, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(29, (uint64_t)isr29, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(30, (uint64_t)isr30, GDT_CODE_SEG, TRAP_GATE);
+ add_to_idt(31, (uint64_t)isr31, GDT_CODE_SEG, TRAP_GATE);
+
+ // interrupts
+ add_to_idt(32, (uint64_t)irq0, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(33, (uint64_t)irq1, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(34, (uint64_t)irq2, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(35, (uint64_t)irq3, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(36, (uint64_t)irq4, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(37, (uint64_t)irq5, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(38, (uint64_t)irq6, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(39, (uint64_t)irq7, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(40, (uint64_t)irq8, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(41, (uint64_t)irq9, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(42, (uint64_t)irq10, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(43, (uint64_t)irq11, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(44, (uint64_t)irq12, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(45, (uint64_t)irq13, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(46, (uint64_t)irq14, GDT_CODE_SEG, INTERRUPT_GATE);
+ add_to_idt(47, (uint64_t)irq15, GDT_CODE_SEG, INTERRUPT_GATE);
+}
+
+void init_idt()
+{
+ init_idt_table();
+ idt_pointer.size = sizeof(idt_entry) * 256 - 1;
+ idt_pointer.offset = (uint64_t)&idt_table;
+
+ remap_pic();
+
+ load_idt(&idt_pointer);
+}
diff --git a/kernel/src/cpu/io.c b/kernel/src/cpu/io.c
new file mode 100644
index 0000000..6bf67d0
--- /dev/null
+++ b/kernel/src/cpu/io.c
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+uint8_t inb(uint32_t port)
+{
+ uint8_t ret;
+ __asm__ volatile ("inb %%dx, %%al" : "=a"(ret) : "d"(port));
+ return ret;
+}
+
+void outb(uint32_t port, uint8_t value)
+{
+ __asm__ volatile ("outb %%al, %%dx" : : "d"(port), "a"(value));
+}
diff --git a/kernel/src/cpu/irq.c b/kernel/src/cpu/irq.c
new file mode 100644
index 0000000..1e02f23
--- /dev/null
+++ b/kernel/src/cpu/irq.c
@@ -0,0 +1,289 @@
+#include <stdint.h>
+#include <pic.h>
+#include <io.h>
+#include <keyboard.h>
+#include <graphics.h>
+
+char* exception_name[] = {
+ "Divide-by-zero Error",
+ "Debug",
+ "Non-maskable Interrupt",
+ "Breakpoint",
+ "Overflow",
+ "Bound Range Exceeded",
+ "Invalid Opcode",
+ "Device Not Available",
+ "Double Fault",
+ "Coprocessor Segment Overrun",
+ "Invalid TSS",
+ "Segment Not Present",
+ "Stack-Segment Fault",
+ "General Protection Fault",
+ "Page Fault",
+ "Reserved",
+ "x87 Floating-Point Exception",
+ "Alignment Check",
+ "Machine Check",
+ "SIMD Floating-Point Exception",
+ "Virtualization Exception",
+ "Control Protection Exception",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Hypervisor Injection Exception",
+ "VMM Communication Exception",
+ "Security Exception",
+ "Reserved",
+};
+
+void isr0_handler(void)
+{
+ fb_draw_string(fb, exception_name[0], 0, 0, WHITE, BLACK);
+}
+
+void isr1_handler(void)
+{
+ fb_draw_string(fb, exception_name[1], 0, 0, WHITE, BLACK);
+}
+
+void isr2_handler(void)
+{
+ fb_draw_string(fb, exception_name[2], 0, 0, WHITE, BLACK);
+}
+
+void isr3_handler(void)
+{
+ fb_draw_string(fb, exception_name[3], 0, 0, WHITE, BLACK);
+}
+
+void isr4_handler(void)
+{
+ fb_draw_string(fb, exception_name[4], 0, 0, WHITE, BLACK);
+}
+
+void isr5_handler(void)
+{
+ fb_draw_string(fb, exception_name[5], 0, 0, WHITE, BLACK);
+}
+
+void isr6_handler(void)
+{
+ fb_draw_string(fb, exception_name[6], 0, 0, WHITE, BLACK);
+}
+
+void isr7_handler(void)
+{
+ fb_draw_string(fb, exception_name[7], 0, 0, WHITE, BLACK);
+}
+
+void isr8_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[8], 0, 0, WHITE, BLACK);
+}
+
+void isr9_handler(void)
+{
+ fb_draw_string(fb, exception_name[9], 0, 0, WHITE, BLACK);
+}
+
+void isr10_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[10], 0, 0, WHITE, BLACK);
+}
+
+void isr11_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[11], 0, 0, WHITE, BLACK);
+}
+
+void isr12_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[12], 0, 0, WHITE, BLACK);
+}
+
+void isr13_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[13], 0, 0, WHITE, BLACK);
+}
+
+void isr14_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[14], 0, 0, WHITE, BLACK);
+}
+
+void isr15_handler(void)
+{
+ fb_draw_string(fb, exception_name[15], 0, 0, WHITE, BLACK);
+}
+
+void isr16_handler(void)
+{
+ fb_draw_string(fb, exception_name[16], 0, 0, WHITE, BLACK);
+}
+
+void isr17_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[17], 0, 0, WHITE, BLACK);
+}
+
+void isr18_handler(void)
+{
+ fb_draw_string(fb, exception_name[18], 0, 0, WHITE, BLACK);
+}
+
+void isr19_handler(void)
+{
+ fb_draw_string(fb, exception_name[19], 0, 0, WHITE, BLACK);
+}
+
+void isr20_handler(void)
+{
+ fb_draw_string(fb, exception_name[20], 0, 0, WHITE, BLACK);
+}
+
+void isr21_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[21], 0, 0, WHITE, BLACK);
+}
+
+void isr22_handler(void)
+{
+ fb_draw_string(fb, exception_name[22], 0, 0, WHITE, BLACK);
+}
+
+void isr23_handler(void)
+{
+ fb_draw_string(fb, exception_name[23], 0, 0, WHITE, BLACK);
+}
+
+void isr24_handler(void)
+{
+ fb_draw_string(fb, exception_name[24], 0, 0, WHITE, BLACK);
+}
+
+void isr25_handler(void)
+{
+ fb_draw_string(fb, exception_name[25], 0, 0, WHITE, BLACK);
+}
+
+void isr26_handler(void)
+{
+ fb_draw_string(fb, exception_name[26], 0, 0, WHITE, BLACK);
+}
+
+void isr27_handler(void)
+{
+ fb_draw_string(fb, exception_name[27], 0, 0, WHITE, BLACK);
+}
+
+void isr28_handler(void)
+{
+ fb_draw_string(fb, exception_name[28], 0, 0, WHITE, BLACK);
+}
+
+void isr29_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[29], 0, 0, WHITE, BLACK);
+}
+
+void isr30_handler(uint64_t error)
+{
+ fb_draw_string(fb, exception_name[30], 0, 0, WHITE, BLACK);
+}
+
+void isr31_handler(void)
+{
+ fb_draw_string(fb, exception_name[31], 0, 0, WHITE, BLACK);
+}
+
+void irq0_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq1_handler(void)
+{
+ keyboard_handler();
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq2_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq3_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq4_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq5_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq6_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq7_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+}
+
+void irq8_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq9_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq10_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq11_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq12_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq13_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq14_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
+
+void irq15_handler(void)
+{
+ outb(PIC1_COMMAND, PIC_EOI);
+ outb(PIC2_COMMAND, PIC_EOI);
+}
diff --git a/kernel/src/cpu/irq_stub.S b/kernel/src/cpu/irq_stub.S
new file mode 100644
index 0000000..ddd197a
--- /dev/null
+++ b/kernel/src/cpu/irq_stub.S
@@ -0,0 +1,108 @@
+.macro pushall
+ push %rax
+ push %rcx
+ push %rdx
+ push %rsi
+ push %rdi
+ push %r8
+ push %r9
+ push %r10
+ push %r11
+ pushfq
+.endm
+
+.macro popall
+ popfq
+ pop %r11
+ pop %r10
+ pop %r9
+ pop %r8
+ pop %rdi
+ pop %rsi
+ pop %rdx
+ pop %rcx
+ pop %rax
+.endm
+
+
+.macro isr_no_error number
+.global isr\number
+isr\number:
+ pushall
+ cld
+ call isr\number\()_handler
+ popall
+ iretq
+.endm
+
+.macro isr_error number
+.global isr\number
+isr\number:
+ # rdi not saved
+ pop %rdi
+ pushall
+ cld
+ call isr\number\()_handler
+ popall
+ iretq
+.endm
+
+isr_no_error 0
+isr_no_error 1
+isr_no_error 2
+isr_no_error 3
+isr_no_error 4
+isr_no_error 5
+isr_no_error 6
+isr_no_error 7
+isr_error 8
+isr_no_error 9
+isr_error 10
+isr_error 11
+isr_error 12
+isr_error 13
+isr_error 14
+isr_no_error 15
+isr_no_error 16
+isr_error 17
+isr_no_error 18
+isr_no_error 19
+isr_no_error 20
+isr_no_error 21
+isr_no_error 22
+isr_no_error 23
+isr_no_error 24
+isr_no_error 25
+isr_no_error 26
+isr_no_error 27
+isr_no_error 28
+isr_error 29
+isr_error 30
+isr_no_error 31
+
+.macro irq number
+.global irq\number
+irq\number:
+ pushall
+ cld
+ call irq\number\()_handler
+ popall
+ iretq
+.endm
+
+irq 0
+irq 1
+irq 2
+irq 3
+irq 4
+irq 5
+irq 6
+irq 7
+irq 8
+irq 9
+irq 10
+irq 11
+irq 12
+irq 13
+irq 14
+irq 15
diff --git a/kernel/src/cpu/pic.c b/kernel/src/cpu/pic.c
new file mode 100644
index 0000000..801556d
--- /dev/null
+++ b/kernel/src/cpu/pic.c
@@ -0,0 +1,24 @@
+#include <io.h>
+#include <pic.h>
+
+void remap_pic(void)
+{
+ // save masks
+// uint8_t a1 = inb(PIC1_DATA);
+// uint8_t a2 = inb(PIC2_DATA);
+
+ // starts the initialization sequence (in cascade mode)
+ outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
+ outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
+ outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset
+ outb(PIC2_DATA, 0x28); // ICW2: Slave PIC vector offset
+ outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
+ outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
+
+ outb(PIC1_DATA, ICW4_8086);
+ outb(PIC2_DATA, ICW4_8086);
+
+ // mask interrupts
+ outb(PIC1_DATA, 0xfd);
+ outb(PIC2_DATA, 0xff);
+}
diff --git a/kernel/src/devices/keyboard.c b/kernel/src/devices/keyboard.c
new file mode 100644
index 0000000..105c3a8
--- /dev/null
+++ b/kernel/src/devices/keyboard.c
@@ -0,0 +1,20 @@
+#include <stdint.h>
+#include <pic.h>
+#include <io.h>
+#include <graphics.h>
+#include <debug.h>
+
+#define KEYBOARD_DATA_PORT 0x60
+#define KEYBOARD_STATUS_PORT 0x64
+
+uint8_t i = 0;
+
+void keyboard_handler(void)
+{
+ uint8_t status = inb(KEYBOARD_STATUS_PORT);
+ if (!(status & 0x1)) {
+ return;
+ }
+ uint8_t keycode = inb(KEYBOARD_DATA_PORT);
+ fb_draw_character(fb, keycode, 0, 0, RED, BLACK);
+}
diff --git a/kernel/src/grub.cfg b/kernel/src/grub.cfg
new file mode 100644
index 0000000..05a13f7
--- /dev/null
+++ b/kernel/src/grub.cfg
@@ -0,0 +1,8 @@
+set timeout=0
+set default=0
+
+insmod efi_gop
+menuentry "mykernel64" {
+ multiboot2 /boot/kernel.bin
+ boot
+}
diff --git a/kernel/src/kernel.ld b/kernel/src/kernel.ld
new file mode 100644
index 0000000..da5c87c
--- /dev/null
+++ b/kernel/src/kernel.ld
@@ -0,0 +1,39 @@
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 1M;
+
+ .boot BLOCK(4K) : ALIGN(4K)
+ {
+ KEEP(*(.multiboot_header))
+ }
+
+ .text BLOCK(4K) : ALIGN(4K)
+ {
+ *(.text)
+ }
+
+ .rodata BLOCK(4K) : ALIGN(4K)
+ {
+ *(.rodata)
+ }
+
+ .data BLOCK(4K) : ALIGN(4K)
+ {
+ *(.data)
+ }
+
+ .bss BLOCK(4K) : ALIGN(4K)
+ {
+ *(COMMON)
+ *(.bss)
+ }
+
+ /DISCARD/ :
+ {
+ *(.comment.*)
+ *(.note.*)
+ *(.eh_frame)
+ }
+}
diff --git a/kernel/src/main.c b/kernel/src/main.c
new file mode 100644
index 0000000..96f3572
--- /dev/null
+++ b/kernel/src/main.c
@@ -0,0 +1,18 @@
+#include <stdint.h>
+#include <multiboot2.h>
+#include <graphics.h>
+#include <idt.h>
+#include <debug.h>
+
+int kernel_main(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic)
+{
+ init_idt();
+ init_fb(multiboot_bootinfo, multiboot_magic);
+
+ fb_draw_string(fb, "Still working...", 8, 0, WHITE, BLACK);
+
+ for(;;) {
+ __asm__ volatile ("hlt;");
+ }
+ return 0;
+}
diff --git a/kernel/src/misc/debug.c b/kernel/src/misc/debug.c
new file mode 100644
index 0000000..5f3c327
--- /dev/null
+++ b/kernel/src/misc/debug.c
@@ -0,0 +1,6 @@
+#include <stdint.h>
+
+void bochs_breakpoint(void)
+{
+ __asm__ volatile ("xchgw %bx, %bx;");
+}
diff --git a/kernel/src/misc/graphics.c b/kernel/src/misc/graphics.c
new file mode 100644
index 0000000..d4fc7c7
--- /dev/null
+++ b/kernel/src/misc/graphics.c
@@ -0,0 +1,119 @@
+#include <stdint.h>
+#include <multiboot2.h>
+#include <graphics.h>
+#include <font.h>
+
+uint64_t* pixel_offset(fb_t fb, uint32_t x, uint32_t y)
+{
+ return (uint64_t*)((char*)fb.addr + y * fb.pitch + x * fb.bpp / 8);
+}
+
+void fb_draw_pixel(fb_t fb, uint32_t x, uint32_t y, uint32_t col)
+{
+ if (x >= fb.width || y >= fb.height) return;
+
+ uint32_t* fb_offset = (uint32_t*)pixel_offset(fb, x, y);
+ *fb_offset = col;
+}
+
+/* https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm */
+
+void fb_draw_line_low(fb_t fb, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t col)
+{
+ int32_t dx = x1 - x0;
+ int32_t dy = y1 - y0;
+ int32_t yi = 1;
+ if (dy < 0) {
+ yi = -1;
+ dy = -dy;
+ }
+ int32_t D = (2 * dy) - dx;
+ int32_t y = y0;
+
+ for (int32_t x = x0; x <= x1; x++) {
+ fb_draw_pixel(fb, x, y, col);
+ if (D > 0) {
+ y = y + yi;
+ D = D + (2 * (dy - dx));
+ } else {
+ D = D + 2 * dy;
+ }
+ }
+
+}
+
+void fb_draw_line_high(fb_t fb, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t col)
+{
+ int32_t dx = x1 - x0;
+ int32_t dy = y1 - y0;
+ int32_t xi = 1;
+ if (dx < 0) {
+ xi = -1;
+ dx = -dx;
+ }
+ int32_t D = (2 * dx) - dy;
+ int32_t x = x0;
+
+ for (int32_t y = y0; y <= y1; y++) {
+ fb_draw_pixel(fb, x, y, col);
+ if (D > 0) {
+ x = x + xi;
+ D = D + (2 * (dx - dy));
+ } else {
+ D = D + 2 * dx;
+ }
+ }
+}
+
+int32_t abs(int32_t val)
+{
+ if (val < 0) return -val;
+ return val;
+}
+
+void fb_draw_line(fb_t fb, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t col)
+{
+ if (abs(y1 - y0) < abs(x1 - x0)) {
+ if (x0 > x1)
+ fb_draw_line_low(fb, x1, y1, x0, y0, col);
+ else
+ fb_draw_line_low(fb, x0, y0, x1, y1, col);
+ } else {
+ if (y0 > y1)
+ fb_draw_line_high(fb, x1, y1, x0, y0, col);
+ else
+ fb_draw_line_high(fb, x0, y0, x1, y1, col);
+ }
+}
+
+void fb_draw_character(fb_t fb, char c, uint32_t x, uint32_t y, uint32_t char_col, uint32_t bg_col)
+{
+ if (c < 0) return;
+
+ uint32_t offset = 32 + c * 16;
+ for (uint32_t i = 0 ; i < 16; i++)
+ {
+ for (uint32_t j = 0 ; j < 8; j++)
+ {
+ if (font[offset + i] & (1 << (7 - j))) {
+ fb_draw_pixel(fb, x + j, y + i, char_col);
+ } else {
+ fb_draw_pixel(fb, x + j, y + i, bg_col);
+ }
+ }
+ }
+}
+
+uint32_t strlen(const char* s)
+{
+ char *p = (char*)s;
+ while (*p) p++;
+ return p - s;
+}
+
+void fb_draw_string(fb_t fb, const char* s, uint32_t x, uint32_t y, uint32_t char_col, uint32_t bg_col)
+{
+ for (uint32_t i = 0; i < strlen(s); i++) {
+ fb_draw_character(fb, s[i], x + i * 8, y, char_col, bg_col);
+ }
+}