summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.org>2025-01-12 01:17:36 -0600
committerDanny Holman <dholman@gymli.org>2025-01-12 01:19:11 -0600
commit95cd78840f0891e60f5ebecc8a8eb4fbaf3c2ebf (patch)
treec8c35347b50477929727fa5be9f5d0f55cbe18fd /kernel
parent5e166f3042a8e7b3031aae4da7006f80caa53ecc (diff)
PROJECT RESTRUCTURING
Move the entire kernel into its own directory. Create new directories for system commands, libraries and other required essentials for a complete Unix-like operating system. Signed-off-by: Danny Holman <dholman@gymli.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/arch/x86/include/kernel/asm.h167
-rw-r--r--kernel/arch/x86/include/kernel/gdt.h53
-rw-r--r--kernel/arch/x86/include/kernel/idt.h31
-rw-r--r--kernel/arch/x86/include/kernel/paging.h45
-rw-r--r--kernel/arch/x86/include/kernel/pic.h44
-rw-r--r--kernel/arch/x86/include/kernel/pmem.h19
-rw-r--r--kernel/arch/x86/include/kernel/syscall.h34
-rw-r--r--kernel/arch/x86/include/kernel/timer.h9
-rw-r--r--kernel/arch/x86/include/kernel/vmem.h17
-rw-r--r--kernel/arch/x86/kernel/gdt.c54
-rw-r--r--kernel/arch/x86/kernel/idt.c149
-rw-r--r--kernel/arch/x86/kernel/kmalloc.c70
-rw-r--r--kernel/arch/x86/kernel/multiboot.c49
-rw-r--r--kernel/arch/x86/kernel/paging.c130
-rw-r--r--kernel/arch/x86/kernel/pic.c79
-rw-r--r--kernel/arch/x86/kernel/pmem.c66
-rw-r--r--kernel/arch/x86/kernel/serial.c42
-rw-r--r--kernel/arch/x86/kernel/syscall.c25
-rw-r--r--kernel/arch/x86/kernel/timer.c25
-rw-r--r--kernel/core/interrupt.c (renamed from kernel/interrupt.c)1
-rw-r--r--kernel/core/panic.c (renamed from kernel/panic.c)7
-rw-r--r--kernel/core/sched.c (renamed from kernel/sched.c)0
-rw-r--r--kernel/drivers/input/keyboard.c142
-rw-r--r--kernel/drivers/video/framebuffer.c109
-rw-r--r--kernel/init.c35
-rw-r--r--kernel/libk/io.c78
-rw-r--r--kernel/libk/string.c133
27 files changed, 1577 insertions, 36 deletions
diff --git a/kernel/arch/x86/include/kernel/asm.h b/kernel/arch/x86/include/kernel/asm.h
new file mode 100644
index 0000000..18f53c4
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/asm.h
@@ -0,0 +1,167 @@
+#ifndef I386_ASM_H
+#define I386_ASM_H
+
+#include <kernel/gdt.h>
+#include <stdint.h>
+#include <cpuid.h>
+
+#define PCI_CONFIG_ADDR 0xCF8
+#define PCI_CONFIG_DATA 0xCFC
+
+#define COM_PORT 0x3F8
+
+#define MAX_ISR 256
+
+struct regs {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t esp;
+
+ uint32_t cr0;
+ uint32_t cr2;
+ uint32_t cr3;
+ uint32_t cr4;
+};
+
+struct isr_frame {
+ uint32_t cr4;
+ uint32_t cr3;
+ uint32_t cr2;
+ uint32_t cr0;
+
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t ebx;
+ uint32_t eax;
+
+ uint32_t isr_vector;
+ uint32_t isr_err;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+} __attribute__((packed));
+
+struct cpuid_info {
+ char vendorID[12];
+ uint32_t feat_ecx;
+ uint32_t feat_edx;
+};
+
+void isr_stub_0(void);
+void isr_stub_1(void);
+void isr_stub_2(void);
+void isr_stub_3(void);
+void isr_stub_4(void);
+void isr_stub_5(void);
+void isr_stub_6(void);
+void isr_stub_7(void);
+void isr_stub_8(void);
+void isr_stub_9(void);
+void isr_stub_10(void);
+void isr_stub_11(void);
+void isr_stub_12(void);
+void isr_stub_13(void);
+void isr_stub_14(void);
+void isr_stub_15(void);
+void isr_stub_16(void);
+void isr_stub_17(void);
+void isr_stub_18(void);
+void isr_stub_19(void);
+void isr_stub_20(void);
+void isr_stub_21(void);
+void isr_stub_22(void);
+void isr_stub_23(void);
+void isr_stub_24(void);
+void isr_stub_25(void);
+void isr_stub_26(void);
+void isr_stub_27(void);
+void isr_stub_28(void);
+void isr_stub_29(void);
+void isr_stub_30(void);
+void isr_stub_31(void);
+
+void irq_stub_0(void);
+void irq_stub_1(void);
+void irq_stub_2(void);
+void irq_stub_3(void);
+void irq_stub_4(void);
+void irq_stub_5(void);
+void irq_stub_6(void);
+void irq_stub_7(void);
+void irq_stub_8(void);
+void irq_stub_9(void);
+void irq_stub_10(void);
+void irq_stub_11(void);
+void irq_stub_12(void);
+void irq_stub_13(void);
+void irq_stub_14(void);
+void irq_stub_15(void);
+
+void isr_stub_128(void);
+
+void enable_paging(uint32_t new_cr3);
+int cpuid_check(void);
+void flush_gdt(void);
+
+static inline void cpuid(int code, uint32_t *ecx, uint32_t *ebx) {
+ __asm__ volatile("cpuid" : "=a"(*ecx), "=d"(*ebx) : "a"(code) : "ecx","ebx");
+}
+
+static inline void outb(uint16_t port, uint8_t value) {
+ __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
+}
+
+static inline void outw(uint16_t port, uint16_t value) {
+ __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port));
+}
+
+static inline void outl(uint16_t port, uint32_t value) {
+ __asm__ volatile("outl %0, %1" : : "a"(value), "Nd"(port));
+}
+
+static inline uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ __asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline uint16_t inw(uint16_t port) {
+ uint16_t ret;
+ __asm__ volatile("inw %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline uint32_t inl(uint16_t port) {
+ uint32_t ret;
+ __asm__ volatile("inl %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline void enable_ints(void) {
+ __asm__ volatile("sti");
+}
+
+static inline void disable_ints(void) {
+ __asm__ volatile("cli");
+}
+
+static inline void flush_tss(void) {
+ __asm__ volatile("movw $0x28, %ax; ltr %ax");
+}
+
+static inline void flush_tlb(void) {
+ __asm__ volatile("movl %cr3, %eax; movl %eax, %cr3");
+}
+
+static inline void invlpg(void *addr) {
+ __asm__ volatile("invlpg (%0)" : : "b"(addr) : "memory");
+}
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/gdt.h b/kernel/arch/x86/include/kernel/gdt.h
new file mode 100644
index 0000000..aa05408
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/gdt.h
@@ -0,0 +1,53 @@
+#ifndef I386_GDT_H
+#define I386_GDT_H
+
+#include <stdint.h>
+
+struct gdt_entry {
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t gran;
+ uint8_t base_high;
+} __attribute__((packed));
+
+struct gdt_ptr {
+ uint16_t limit;
+ uint64_t base;
+} __attribute__((packed));
+
+struct tss_entry {
+ uint32_t link;
+ uint32_t esp0;
+ uint32_t ss0;
+ uint32_t esp1;
+ uint32_t ss2;
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t es;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t ldtr;
+ uint16_t trap;
+ uint16_t iomap_base;
+} __attribute__((packed));
+
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
+void write_tss(int num, uint32_t ss0, uint32_t esp0);
+void set_kernel_esp(uint32_t esp);
+void gdt_install(void);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/idt.h b/kernel/arch/x86/include/kernel/idt.h
new file mode 100644
index 0000000..29ec39f
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/idt.h
@@ -0,0 +1,31 @@
+#ifndef I386_IDT_H
+#define I386_IDT_H
+
+#include <stdint.h>
+
+#define SEGMENT_PRESENT 0x80
+#define SEGMENT_RING0 0x00
+#define SEGMENT_RING3 0x60
+#define SEGMENT_STORAGE 0x00
+#define SEGMENT_INTERRUPT 0x0E
+#define IDT_EXCEPTION (SEGMENT_PRESENT | SEGMENT_INTERRUPT)
+#define IDT_INTERRUPT (SEGMENT_PRESENT | SEGMENT_INTERRUPT)
+
+#define IDT_MAX_DESCRIPTORS 256
+
+struct idt_entry {
+ uint16_t isr_low;
+ uint16_t kernel_cs;
+ uint8_t reserved;
+ uint8_t flags;
+ uint16_t isr_high;
+} __attribute__((packed));
+
+struct idt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+void idt_install(void);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/paging.h b/kernel/arch/x86/include/kernel/paging.h
new file mode 100644
index 0000000..3a3c298
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/paging.h
@@ -0,0 +1,45 @@
+#ifndef I386_PAGING_H
+#define I386_PAGING_H
+
+#include <kernel/asm.h>
+#include <stdint.h>
+
+#define PAGE_SIZE 4096
+
+#define PD_PRES 0x0001
+#define PD_RW 0x0002
+#define PD_USR 0x0004
+#define PD_PWT 0x0008
+#define PD_PCD 0x0010
+#define PD_ACC 0x0020
+#define PD_DIRTY 0x0040
+#define PD_PS 0x0080
+#define PD_GLOB 0x0100
+#define PD_PAT 0x1000
+
+#define ERR_PRESENT 0x1
+#define ERR_RW 0x2
+#define ERR_USER 0x4
+#define ERR_RESERVED 0x8
+#define ERR_INST 0x10
+
+#define PGROUNDUP(size) (((size)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
+#define PGROUNDDN(size) (((size)) & ~(PAGE_SIZE-1))
+
+#define GET_PADDR(x) (((uint32_t)(x)) - 0xC0000000)
+#define GET_VADDR(x) (((uint32_t)(x)) + 0xC0000000)
+
+#define GET_PDX(x) ((uintptr_t)(x) >> 22)
+#define GET_PTX(x) (((uintptr_t)(x) >> 12) & 0x03FF)
+
+uintptr_t get_physaddr(void *vaddr);
+
+void paging_init(void);
+
+uintptr_t init_page_directory(void);
+void map_page(uintptr_t paddr, uintptr_t vaddr, uint32_t flags);
+void unmap_page(uintptr_t vaddr);
+
+void page_fault_handler(struct isr_frame *frame);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/pic.h b/kernel/arch/x86/include/kernel/pic.h
new file mode 100644
index 0000000..187d553
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/pic.h
@@ -0,0 +1,44 @@
+#ifndef I386_PIC_H
+#define I386_PIC_H
+
+#include <kernel/asm.h>
+#include <stdint.h>
+
+#define PIC1 0x20
+#define PIC2 0x28
+#define PIC1_COMMAND PIC1
+#define PIC1_DATA (PIC1+1)
+#define PIC2_COMMAND PIC2
+#define PIC2_DATA (PIC2+1)
+
+#define ICW1_ICW4 0x01
+#define ICW1_SINGLE 0x02
+#define ICW1_INTERVAL4 0x04
+#define ICW1_LEVEL 0x08
+#define ICW1_INIT 0x10
+
+#define ICW4_8086 0x01
+#define ICW4_AUTO 0x02
+#define ICW4_BUF_SLAVE 0x08
+#define ICW4_BUF_MASTER 0x0C
+#define ICW4_SFNM 0x10
+
+#define PIC_READ_IRR 0x0A
+#define PIC_READ_ISR 0x0B
+
+static inline void io_wait(void) {
+ outb(0x80, 0);
+}
+
+void pic_eoi(uint8_t irq);
+void pic_remap(void);
+uint16_t pic_get_irr(void);
+uint16_t pic_get_isr(void);
+
+void register_irq_handler(uint8_t irq, void (*handler)(struct isr_frame *frame));
+void irq_dispatch(struct isr_frame *frame);
+
+void irq_set_mask(uint8_t irq);
+void irq_clear_mask(uint8_t irq);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/pmem.h b/kernel/arch/x86/include/kernel/pmem.h
new file mode 100644
index 0000000..ea4fe29
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/pmem.h
@@ -0,0 +1,19 @@
+#ifndef I386_PMEM_H
+#define I386_PMEM_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+struct pfa_page {
+ struct pfa_page *next;
+};
+
+void pfa_init(struct mboot_info *header);
+
+uintptr_t pfa_alloc_dma(size_t num_pages);
+uintptr_t pfa_alloc(size_t num_pages);
+
+void pfa_free_dma(uintptr_t paddr, size_t num_pages);
+void pfa_free(uintptr_t paddr, size_t num_pages);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/syscall.h b/kernel/arch/x86/include/kernel/syscall.h
new file mode 100644
index 0000000..a657527
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/syscall.h
@@ -0,0 +1,34 @@
+#ifndef I386_SYSCALL_H
+#define I386_SYSCALL_H
+
+#include <kernel/asm.h>
+#include <stdint.h>
+#include <stddef.h>
+
+// Unix standard calls
+#define SYS_FORK 1
+#define SYS_EXIT 2
+#define SYS_WAIT 3
+#define SYS_PIPE 4
+#define SYS_READ 5
+#define SYS_WRITE 6
+#define SYS_KILL 7
+#define SYS_FSTAT 8
+#define SYS_CHDIR 9
+#define SYS_DUP 10
+#define SYS_GETPID 11
+#define SYS_SLEEP 12
+#define SYS_OPEN 13
+#define SYS_MKNOD 14
+#define SYS_UNLINK 15
+#define SYS_LINK 16
+#define SYS_MKDIR 17
+#define SYS_CLOSE 18
+#define SYS_EXEC 19
+
+#define SYS_HALT 87
+#define SYS_REBOOT 88
+
+void handle_syscall(struct isr_frame *frame);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/timer.h b/kernel/arch/x86/include/kernel/timer.h
new file mode 100644
index 0000000..c0b3a73
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/timer.h
@@ -0,0 +1,9 @@
+#ifndef I386_TIMER_H
+#define I386_TIMER_H
+
+#include <kernel/asm.h>
+
+void timer_handler(struct isr_frame *frame);
+void timer_init(void);
+
+#endif
diff --git a/kernel/arch/x86/include/kernel/vmem.h b/kernel/arch/x86/include/kernel/vmem.h
new file mode 100644
index 0000000..94aa32d
--- /dev/null
+++ b/kernel/arch/x86/include/kernel/vmem.h
@@ -0,0 +1,17 @@
+#ifndef I386_VMEM_H
+#define I386_VMEM_H
+
+extern uintptr_t _kernel_start;
+extern uintptr_t _kernel_end;
+
+#define KSTART ((uintptr_t)&_kernel_start)
+#define KEND ((uintptr_t)&_kernel_end - 0xC0000000)
+
+#define KHEAP_START (GET_VADDR(KEND) + 0x2000)
+#define KHEAP_STOP 0xFF7FF000
+
+#define PAGE_DIR_MAP 0xFFFFF000
+#define PAGE_TAB_MAP 0xFFC00000
+#define PAGE_TMP_MAP 0xFFBFF000
+
+#endif
diff --git a/kernel/arch/x86/kernel/gdt.c b/kernel/arch/x86/kernel/gdt.c
new file mode 100644
index 0000000..57424aa
--- /dev/null
+++ b/kernel/arch/x86/kernel/gdt.c
@@ -0,0 +1,54 @@
+#include <kernel/gdt.h>
+#include <kernel/asm.h>
+#include <libk/string.h>
+
+struct gdt_entry desc[6];
+struct gdt_ptr gp;
+struct tss_entry tss_entry;
+
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
+ desc[num].base_low = (base & 0xFFFF);
+ desc[num].base_middle = (base >> 16) & 0xFF;
+ desc[num].base_high = (base >> 24) & 0xFF;
+
+ desc[num].limit_low = (limit & 0xFFFF);
+ desc[num].gran = (limit >> 16) & 0x0F;
+ desc[num].gran |= (gran & 0xF0);
+ desc[num].access = access;
+}
+
+void write_tss(int num, uint32_t ss0, uint32_t esp0) {
+ uint64_t base = (uint64_t)&tss_entry;
+ uint32_t limit = base + sizeof(struct tss_entry);
+
+ gdt_set_gate(num, base, limit, 0x89, 0x00);
+ memset(&tss_entry, 0x0, sizeof(tss_entry));
+
+ tss_entry.ss0 = ss0;
+ tss_entry.esp0 = esp0;
+ tss_entry.cs = 0x0B;
+ tss_entry.ss = 0x13;
+ tss_entry.ds = 0x13;
+ tss_entry.es = 0x13;
+ tss_entry.fs = 0x13;
+ tss_entry.gs = 0x13;
+ tss_entry.iomap_base = sizeof(tss_entry);
+}
+
+void gdt_install(void) {
+ gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
+ gp.base = (uint64_t)&desc;
+
+ gdt_set_gate(0, 0, 0, 0, 0);
+ gdt_set_gate(1, 0, 0xFFFFF, 0x9A, 0xCF);
+ gdt_set_gate(2, 0, 0xFFFFF, 0x92, 0xCF);
+ gdt_set_gate(3, 0, 0xFFFFF, 0xFA, 0xCF);
+ gdt_set_gate(4, 0, 0xFFFFF, 0xF2, 0xCF);
+
+ uint64_t rsp;
+ __asm__ volatile("movq %%rsp, %0" : "=r"(rsp));
+ write_tss(5, 0x10, rsp);
+
+ flush_gdt();
+ flush_tss();
+}
diff --git a/kernel/arch/x86/kernel/idt.c b/kernel/arch/x86/kernel/idt.c
new file mode 100644
index 0000000..a178801
--- /dev/null
+++ b/kernel/arch/x86/kernel/idt.c
@@ -0,0 +1,149 @@
+#include <kernel/idt.h>
+#include <kernel/interrupt.h>
+#include <kernel/syscall.h>
+#include <kernel/panic.h>
+#include <kernel/gdt.h>
+#include <kernel/asm.h>
+#include <kernel/pic.h>
+#include <kernel/paging.h>
+#include <libk/io.h>
+#include <libk/string.h>
+#include <stdint.h>
+
+__attribute__((aligned(0x10)))
+struct idt_entry idt[256];
+struct idt_ptr idtr;
+
+const char* exceptions[] = {
+ "Division by zero",
+ "Debug",
+ "Non-maskable interrupt",
+ "Breakpoint",
+ "Overflow",
+ "Out-of-bounds",
+ "Invalid opcode",
+ "FPU not available",
+ "Double fault",
+ "RESERVED",
+ "Invalid TSS",
+ "Segment not present",
+ "Stack fault",
+ "General protection fault",
+ "Page fault",
+ "RESERVED",
+ "FPU exception",
+ "Alignment check",
+ "Machine check",
+ "FPU-SIMD exception",
+ "Virtualization exception",
+ "Control protection"
+ "RESERVED",
+ "Hypervisor injection",
+ "VMM exception",
+ "Security exception",
+ "RESERVED",
+ "Triple fault",
+ "RESERVED"
+};
+
+void exception_handler(struct isr_frame *frame) {
+ switch (frame->isr_vector) {
+ case 0x00:
+ panic("Division by zero in kernel address space");
+ break;
+ case 0x06:
+ panic("Invalid opcode in kernel address space");
+ break;
+ case 0x08:
+ panic("Double fault in interrupt handler");
+ break;
+ case 0x0D:
+ panic("Protection fault in kernel address space");
+ break;
+ case 0x0E:
+ page_fault_handler(frame);
+ break;
+ default:
+ panic("Unhandled exception");
+ }
+}
+
+void generic_handler(struct isr_frame *frame) {
+ kprintf("No handler registered for IRQ %d\n", frame->isr_vector);
+ if (frame->isr_vector > 32 && frame->isr_vector < 48)
+ pic_eoi(frame->isr_vector-32);
+}
+
+void idt_set_gate(uint8_t num, void (*handler)(void), uint16_t cs, uint8_t flags) {
+ struct idt_entry *desc = &idt[num];
+ desc->isr_low = (uint16_t)(((uint32_t)handler >> 0) & 0xFFFF);
+ desc->isr_high = (uint16_t)(((uint32_t)handler >> 16) & 0xFFFF);
+ desc->reserved = 0;
+ desc->kernel_cs = cs;
+ desc->flags = flags;
+}
+
+void idt_install(void) {
+ idtr.limit = (uint16_t)sizeof(struct idt_entry) * 256 - 1;
+ idtr.base = (uint32_t)idt;
+
+ for (int i = 0; i < 32; i++)
+ register_isr_handler(i, exception_handler);
+ for (int i = 32; i < 224; i++)
+ register_isr_handler(i, generic_handler);
+ register_isr_handler(0x80, handle_syscall);
+
+ idt_set_gate(0x0, isr_stub_0, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1, isr_stub_1, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x2, isr_stub_2, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x3, isr_stub_3, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x4, isr_stub_4, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x5, isr_stub_5, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x6, isr_stub_6, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x7, isr_stub_7, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x8, isr_stub_8, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x9, isr_stub_9, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xA, isr_stub_10, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xB, isr_stub_11, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xC, isr_stub_12, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xD, isr_stub_13, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xE, isr_stub_14, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0xF, isr_stub_15, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x10, isr_stub_16, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x11, isr_stub_17, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x12, isr_stub_18, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x13, isr_stub_19, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x14, isr_stub_20, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x15, isr_stub_21, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x16, isr_stub_22, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x17, isr_stub_23, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x18, isr_stub_24, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x19, isr_stub_25, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1A, isr_stub_26, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1B, isr_stub_27, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1C, isr_stub_28, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1D, isr_stub_29, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1E, isr_stub_30, 0x08, IDT_EXCEPTION);
+ idt_set_gate(0x1F, isr_stub_31, 0x08, IDT_EXCEPTION);
+
+ idt_set_gate(0x20, irq_stub_0, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x21, irq_stub_1, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x22, irq_stub_2, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x23, irq_stub_3, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x24, irq_stub_4, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x25, irq_stub_5, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x26, irq_stub_6, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x27, irq_stub_7, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x28, irq_stub_8, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x29, irq_stub_9, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2A, irq_stub_10, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2B, irq_stub_11, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2C, irq_stub_12, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2D, irq_stub_13, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2E, irq_stub_14, 0x08, IDT_INTERRUPT);
+ idt_set_gate(0x2F, irq_stub_15, 0x08, IDT_INTERRUPT);
+
+ idt_set_gate(0x80, isr_stub_128, 0x08, IDT_INTERRUPT);
+
+ __asm__ volatile("lidt %0" : : "memory"(idtr));
+}
diff --git a/kernel/arch/x86/kernel/kmalloc.c b/kernel/arch/x86/kernel/kmalloc.c
new file mode 100644
index 0000000..9e5254c
--- /dev/null
+++ b/kernel/arch/x86/kernel/kmalloc.c
@@ -0,0 +1,70 @@
+#include <libk/kmalloc.h>
+#include <kernel/paging.h>
+#include <kernel/pmem.h>
+#include <kernel/asm.h>
+#include <kernel/vmem.h>
+#include <kernel/panic.h>
+#include <stdint.h>
+
+static uintptr_t heap_start = KEND + 0xC0001000;
+static uintptr_t heap_end = 0xFFBFF000;
+
+static void *kbrk = NULL;
+static struct mem_block *first = NULL;
+
+void _request_page(void) {
+ uintptr_t paddr = pfa_alloc(1);
+ uintptr_t vaddr = PGROUNDDN((uintptr_t)kbrk + PAGE_SIZE);
+ kbrk += PAGE_SIZE;
+ map_page(paddr, vaddr, PD_PRES | PD_RW);
+}
+
+void kmalloc_init(void) {
+ kbrk = PGROUNDDN(heap_start);
+ _request_page();
+ first = (struct mem_block*)kbrk;
+ first->start = (uintptr_t)kbrk + sizeof(struct mem_block);
+ first->size = 0;
+ first->alloc = 1;
+ first->next = NULL;
+}
+
+void* kmalloc(size_t sz) {
+ if (kbrk == NULL)
+ panic("Attmpted to malloc before initialization");
+ if ((uintptr_t)kbrk >= heap_end)
+ return NULL;
+
+ struct mem_block *temp = first;
+ while (temp->next != NULL) {
+ if (temp->next->size <= sz && temp->next->alloc == 0) {
+ temp->next->alloc = 1;
+ return (void*)temp->next->start;
+ }
+ temp = temp->next;
+ }
+
+ temp->next = (struct mem_block*)((uintptr_t)temp + sizeof(struct mem_block) + temp->size);
+ if (temp->next > kbrk)
+ _request_page();
+ temp->next->prev = temp;
+ temp->next->start = (uintptr_t)(temp->next + sizeof(struct mem_block));
+ temp->next->size = sz;
+ temp->next->alloc = 1;
+ temp->next->next = NULL;
+ return (void*)temp->start;
+}
+
+void kfree(void *ptr) {
+ if (ptr == NULL)
+ return;
+ struct mem_block *temp = first;
+ while (temp != NULL) {
+ if (temp->start == (uintptr_t)ptr) {
+ temp->alloc = 0;
+ return;
+ }
+ temp = temp->next;
+ }
+ panic("Attempted to free memory not alloc'd");
+}
diff --git a/kernel/arch/x86/kernel/multiboot.c b/kernel/arch/x86/kernel/multiboot.c
new file mode 100644
index 0000000..dedf163
--- /dev/null
+++ b/kernel/arch/x86/kernel/multiboot.c
@@ -0,0 +1,49 @@
+#include <kernel/multiboot.h>
+#include <kernel/asm.h>
+#include <kernel/gdt.h>
+#include <kernel/idt.h>
+#include <kernel/pic.h>
+#include <kernel/paging.h>
+#include <kernel/pmem.h>
+#include <kernel/timer.h>
+#include <kernel/panic.h>
+#include <kernel/vmem.h>
+#include <kernel/video/framebuffer.h>
+#include <libk/io.h>
+#include <libk/string.h>
+#include <libk/kmalloc.h>
+
+void kernel_main(char *cmdline);
+
+void i386_entry(uint32_t mboot_magic, struct mboot_info *header) {
+ map_page(0xB8000, (uintptr_t)VGA_MEMORY, PD_RW);
+ fb_init();
+
+ if (mboot_magic != MBOOT_LOADER_MAGIC) {
+ disable_ints();
+ panic("Not booted with multiboot bootloader");
+ }
+
+ map_page(0x9000, 0x9000, PD_RW);
+ if (!(header->flags >> 6 & 0x1)) {
+ disable_ints();
+ panic("Physical memory map not provided by bootloader");
+ }
+
+ char cmdline[4096];
+ map_page(header->cmdline, PAGE_TMP_MAP, 0);
+ memcpy(cmdline, (char*)PAGE_TMP_MAP, strlen((char*)PAGE_TMP_MAP));
+ unmap_page(PAGE_TMP_MAP);
+ pfa_init(header);
+ gdt_install();
+ idt_install();
+ paging_init();
+ map_page(0xB8000, (uintptr_t)VGA_MEMORY, PD_RW);
+ pic_remap();
+ timer_init();
+
+ enable_ints();
+ kernel_main(cmdline);
+
+ while (1);
+}
diff --git a/kernel/arch/x86/kernel/paging.c b/kernel/arch/x86/kernel/paging.c
new file mode 100644
index 0000000..a0bbb92
--- /dev/null
+++ b/kernel/arch/x86/kernel/paging.c
@@ -0,0 +1,130 @@
+#include <kernel/paging.h>
+#include <kernel/asm.h>
+#include <kernel/vmem.h>
+#include <kernel/pmem.h>
+#include <kernel/panic.h>
+#include <kernel/syscall.h>
+#include <libk/io.h>
+#include <libk/string.h>
+
+static int paging_enabled = 0;
+
+void paging_init(void) {
+ if (paging_enabled == 1)
+ return;
+
+ uintptr_t phys_pt = pfa_alloc(1);
+ map_page(phys_pt, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ uintptr_t *pt = (uintptr_t*)PAGE_TMP_MAP;
+ for (uintptr_t i = KSTART; i < KEND; i += PAGE_SIZE)
+ pt[GET_PTX(GET_VADDR(i))] = i | PD_PRES;
+ unmap_page(PAGE_TMP_MAP);
+
+ uintptr_t temp_pt = pfa_alloc(1);
+
+ uintptr_t phys_pd = pfa_alloc(1);
+ map_page(phys_pd, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ uintptr_t *pd = (uintptr_t*)PAGE_TMP_MAP;
+ pd[GET_PDX(GET_VADDR(KSTART))] = phys_pt | PD_PRES | PD_RW;
+ pd[GET_PDX(PAGE_TMP_MAP)] = temp_pt | PD_PRES | PD_RW;
+ pd[1023] = phys_pd | PD_PRES | PD_RW;
+ unmap_page(PAGE_TMP_MAP);
+
+ enable_paging(phys_pd);
+ paging_enabled = 1;
+ return;
+}
+
+void init_page_table(int pdindex, uint32_t flags) {
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) != 0)
+ return;
+
+ uintptr_t paddr = pfa_alloc(1);
+ pd[pdindex] = paddr | PD_PRES | PD_RW | flags;
+
+ uintptr_t *pt = ((uintptr_t*)PAGE_TAB_MAP) + (pdindex << 12);
+ pd[GET_PDX(pt)] = paddr | PD_PRES | PD_RW;
+}
+
+uintptr_t init_page_directory(void) {
+ uintptr_t ret = pfa_alloc(1);
+ map_page(ret, PAGE_TMP_MAP, PD_RW);
+
+ uintptr_t *new_pd = (uintptr_t*)PAGE_TMP_MAP;
+ uintptr_t *cur_pd = (uintptr_t*)PAGE_DIR_MAP;
+ int kernel_pdx = GET_PDX(GET_VADDR(KSTART));
+ new_pd[kernel_pdx] = cur_pd[kernel_pdx];
+
+ unmap_page(PAGE_TMP_MAP);
+ return ret;
+}
+
+void map_page(uintptr_t paddr, uintptr_t vaddr, uint32_t flags) {
+ paddr = PGROUNDDN(paddr);
+ vaddr = PGROUNDDN(vaddr);
+
+ int pdindex = GET_PDX(vaddr);
+ int ptindex = GET_PTX(vaddr);
+
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) == 0)
+ init_page_table(pdindex, 0);
+
+ uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12));
+ pt[ptindex] = paddr | PD_PRES | flags;
+ invlpg((void*)vaddr);
+}
+
+void unmap_page(uintptr_t vaddr) {
+ uintptr_t pdindex = GET_PDX(vaddr);
+ uintptr_t ptindex = GET_PTX(vaddr);
+
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) == 0)
+ return;
+
+ uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12));
+ pt[ptindex] = 0;
+ invlpg((void*)vaddr);
+}
+
+void page_fault_handler(struct isr_frame *frame) {
+ uintptr_t fault_addr;
+ __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr));
+
+ kprintf("Faulting address: %x\n", fault_addr);
+ panic("Page fault not operational");
+ switch (frame->isr_err) {
+ case 0:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES);
+ break;
+ case 1:
+ panic("Kernel process caused protection fault on read\n");
+ break;
+ case 2:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW);
+ break;
+ case 3:
+ panic("Kernel process caused protection fault on write\n");
+ break;
+ case 4:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_USR);
+ break;
+ case 5:
+ // TODO: instead of panicking, kill process
+ panic("User process caused protection fault on read\n");
+ break;
+ case 6:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW | PD_USR);
+ break;
+ case 7:
+ // TODO: see case 101
+ panic("USER process caused protection fault on write\n");
+ break;
+ default:
+ kprintf("Unknown paging error occured on address %x\n", fault_addr);
+ panic("Paging error");
+ break;
+ }
+}
diff --git a/kernel/arch/x86/kernel/pic.c b/kernel/arch/x86/kernel/pic.c
new file mode 100644
index 0000000..0d29473
--- /dev/null
+++ b/kernel/arch/x86/kernel/pic.c
@@ -0,0 +1,79 @@
+#include <kernel/pic.h>
+
+static void (*irq_handlers[16])(struct isr_frame *frame);
+
+void pic_eoi(uint8_t irq) {
+ if (irq >= 8)
+ outb(PIC2_COMMAND, 0x20);
+ outb(PIC1_COMMAND, 0x20);
+}
+
+void pic_remap(void) {
+ unsigned char a1 = inb(PIC1_DATA);
+ unsigned char a2 = inb(PIC2_DATA);
+
+ outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
+ outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
+ outb(PIC1_DATA, PIC1);
+ outb(PIC2_DATA, PIC2);
+ outb(PIC1_DATA, 4);
+ outb(PIC2_DATA, 2);
+ outb(PIC1_DATA, ICW4_8086);
+ outb(PIC2_DATA, ICW4_8086);
+ outb(PIC1_DATA, a1);
+ outb(PIC2_DATA, a2);
+}
+
+static uint16_t _pic_get_irq_reg(int ocw3) {
+ outb(PIC1_COMMAND, ocw3);
+ outb(PIC2_COMMAND, ocw3);
+ return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
+}
+
+uint16_t pic_get_irr(void) {
+ return _pic_get_irq_reg(PIC_READ_IRR);
+}
+
+uint16_t pic_get_isr(void) {
+ return _pic_get_irq_reg(PIC_READ_ISR);
+}
+
+void register_irq_handler(uint8_t irq, void (*handler)(struct isr_frame *frame)) {
+ irq_handlers[irq] = handler;
+}
+
+void irq_dispatch(struct isr_frame *frame) {
+ (*irq_handlers[frame->isr_vector-32])(frame);
+ pic_eoi(frame->isr_vector-32);
+ return;
+}
+
+void irq_set_mask(uint8_t irq) {
+ uint16_t port;
+ uint8_t data;
+
+ if (irq < 8) {
+ port = PIC1_DATA;
+ } else {
+ port = PIC2_DATA;
+ irq -= 8;
+ }
+
+ data = inb(port) | (1 << irq);
+ outb(port, data);
+}
+
+void irq_clear_mask(uint8_t irq) {
+ uint16_t port;
+ uint8_t data;
+
+ if (irq < 8) {
+ port = PIC1_DATA;
+ } else {
+ port = PIC2_DATA;
+ irq -= 8;
+ }
+
+ data = inb(port) & ~(1 << irq);
+ outb(port, data);
+}
diff --git a/kernel/arch/x86/kernel/pmem.c b/kernel/arch/x86/kernel/pmem.c
new file mode 100644
index 0000000..edf71d9
--- /dev/null
+++ b/kernel/arch/x86/kernel/pmem.c
@@ -0,0 +1,66 @@
+#include <kernel/pmem.h>
+#include <kernel/asm.h>
+#include <kernel/vmem.h>
+#include <kernel/panic.h>
+#include <kernel/paging.h>
+#include <libk/io.h>
+#include <libk/string.h>
+
+static uintptr_t bitmap[5];
+static struct pfa_page freelist;
+
+void pfa_init(struct mboot_info *header) {
+ struct mboot_mmap_entry *mme;
+ for (uintptr_t i = 0; i < header->mmap_length; i += sizeof(struct mboot_mmap_entry)) {
+ mme = (struct mboot_mmap_entry*)(header->mmap_addr + i);
+ if (mme->type == MBOOT_MEM_AVAILABLE)
+ pfa_free(mme->addr_low, mme->len_low / PAGE_SIZE);
+ }
+}
+
+uintptr_t pfa_alloc_dma(size_t num_pages) {
+}
+
+uintptr_t pfa_alloc(size_t num_pages) {
+ struct pfa_page *temp = (struct pfa_page*)PAGE_TMP_MAP;
+ map_page(freelist.next, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ uintptr_t ret = freelist.next;
+ freelist.next = temp->next;
+ memset(temp, 0, 32);
+ unmap_page(PAGE_TMP_MAP);
+ return ret;
+}
+
+void pfa_free_dma(uintptr_t paddr, size_t num_pages) {
+ if (paddr % PAGE_SIZE != 0)
+ panic("Task attempted to free non-aligned memory");
+ if (paddr >= KSTART && paddr < KEND)
+ return;
+ if (paddr >= 0x00080000 && paddr < 0x00100000)
+ return;
+
+ int index = 0;
+ int bit = 0;
+ for (uintptr_t i = paddr; i < paddr + (num_pages * PAGE_SIZE); i += PAGE_SIZE) {
+ index = i / PAGE_SIZE / 32;
+ bit = i / PAGE_SIZE % 32;
+ bitmap[index] |= 1 << bit;
+ }
+}
+
+void pfa_free(uintptr_t paddr, size_t num_pages) {
+ uintptr_t addr;
+ struct pfa_page *temp = (struct pfa_page*)PAGE_TMP_MAP;
+ for (size_t i = 0; i < num_pages; i++) {
+ addr = (i * PAGE_SIZE + paddr);
+ if (addr >= KSTART && addr < KEND)
+ continue;
+ if (addr == 0)
+ continue;
+ map_page(addr, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ memset(PAGE_TMP_MAP, 1, 32);
+ temp->next = freelist.next;
+ freelist.next = addr;
+ unmap_page(PAGE_TMP_MAP);
+ }
+}
diff --git a/kernel/arch/x86/kernel/serial.c b/kernel/arch/x86/kernel/serial.c
new file mode 100644
index 0000000..dc2a8bd
--- /dev/null
+++ b/kernel/arch/x86/kernel/serial.c
@@ -0,0 +1,42 @@
+#include <kernel/serial.h>
+#include <kernel/pic.h>
+#include <libk/string.h>
+#include <stddef.h>
+
+#define PORT 0x3f8
+
+static inline int _serial_received(void) {
+ return inb(PORT + 5) & 1;
+}
+
+static inline int _is_transmit_empty(void) {
+ return inb(PORT + 5) & 0x20;
+}
+
+int serial_init(void) {
+ outb(PORT + 1, 0x00);
+ outb(PORT + 3, 0x80);
+ outb(PORT + 0, 0x03);
+ outb(PORT + 1, 0x00);
+ outb(PORT + 3, 0x03);
+ outb(PORT + 2, 0xC7);
+ outb(PORT + 4, 0x0B);
+ outb(PORT + 4, 0x1E);
+ outb(PORT + 0, 0xAE);
+
+ if (inb(PORT + 0) != 0xAE)
+ return -1;
+
+ outb(PORT + 4, 0x0F);
+ return 0;
+}
+
+void serial_putchar(char c) {
+ while (_is_transmit_empty() == 0);
+ outb(PORT, c);
+}
+
+char serial_getchar(void) {
+ while (_serial_received() == 0);
+ return inb(PORT);
+}
diff --git a/kernel/arch/x86/kernel/syscall.c b/kernel/arch/x86/kernel/syscall.c
new file mode 100644
index 0000000..1fa73e9
--- /dev/null
+++ b/kernel/arch/x86/kernel/syscall.c
@@ -0,0 +1,25 @@
+#include <kernel/syscall.h>
+#include <kernel/panic.h>
+#include <libk/string.h>
+#include <libk/io.h>
+#include <stddef.h>
+
+void sys_read(struct isr_frame *frame) {
+}
+
+void sys_write(struct isr_frame *frame) {
+}
+
+void handle_syscall(struct isr_frame *frame) {
+ switch (frame->eax) {
+ case SYS_READ:
+ sys_read(frame);
+ break;
+ case SYS_WRITE:
+ sys_write(frame);
+ break;
+ default:
+ kprintf("Invalid system call number %d\n", frame->eax);
+ break;
+ }
+}
diff --git a/kernel/arch/x86/kernel/timer.c b/kernel/arch/x86/kernel/timer.c
new file mode 100644
index 0000000..bd57cc2
--- /dev/null
+++ b/kernel/arch/x86/kernel/timer.c
@@ -0,0 +1,25 @@
+#include <kernel/timer.h>
+#include <kernel/asm.h>
+#include <kernel/pic.h>
+
+static uint32_t num_ticks = 0;
+
+void timer_handler(struct isr_frame *frame) {
+ num_ticks++;
+ if (num_ticks == 3) {
+ num_ticks = 0;
+ //schedule_next();
+ }
+ pic_eoi(frame->isr_vector-32);
+}
+
+void timer_init(void) {
+ disable_ints();
+ int divisor = 1193182 / 100;
+ outb(0x43, 0x34);
+ outb(0x40, divisor && 0xFF);
+ outb(0x40, divisor && 0xFF00 >> 8);
+ enable_ints();
+
+ //register_isr_handler(32, timer_handler);
+}
diff --git a/kernel/interrupt.c b/kernel/core/interrupt.c
index 9639aea..6d9e69d 100644
--- a/kernel/interrupt.c
+++ b/kernel/core/interrupt.c
@@ -1,4 +1,5 @@
#include <kernel/interrupt.h>
+#include <kernel/panic.h>
#include <kernel/asm.h>
static void (*isr_handlers[MAX_ISR])(struct isr_frame *frame);
diff --git a/kernel/panic.c b/kernel/core/panic.c
index 65279f0..a44a73c 100644
--- a/kernel/panic.c
+++ b/kernel/core/panic.c
@@ -1,8 +1,10 @@
#include <kernel/panic.h>
+#include <kernel/spinlock.h>
#include <libk/io.h>
#include <stdint.h>
#include <stddef.h>
+static struct spinlock panic_lock = {0};
static int panicked = 0;
void walk_stack(uintptr_t *addrs, size_t n);
@@ -19,8 +21,11 @@ void stack_trace(void) {
}
void panic(const char *str) {
+ disable_ints();
+ spin_lock(&panic_lock);
panicked = 1;
- kprintf("KERNEL PANIC: %s\n", str);
+ spin_unlock(&panic_lock);
+ kprintf("KERNEL PANIC - NOT SYNCING: %s\n", str);
stack_trace();
while (1);
}
diff --git a/kernel/sched.c b/kernel/core/sched.c
index b6096da..b6096da 100644
--- a/kernel/sched.c
+++ b/kernel/core/sched.c
diff --git a/kernel/drivers/input/keyboard.c b/kernel/drivers/input/keyboard.c
new file mode 100644
index 0000000..f2a8eba
--- /dev/null
+++ b/kernel/drivers/input/keyboard.c
@@ -0,0 +1,142 @@
+#include <kernel/input/keyboard.h>
+#include <kernel/tty/tty_vga.h>
+#include <kernel/tty.h>
+#include <kernel/kthread.h>
+#include <kernel/pic.h>
+#include <libk/string.h>
+
+static uint8_t keymap_modifiers[256] = {
+ [0x1D] KB_CTL,
+ [0x2A] KB_SHIFT,
+ [0x36] KB_SHIFT,
+ [0x38] KB_ALT,
+ [0x9D] KB_CTL,
+ [0xB8] KB_ALT
+};
+
+static uint8_t keymap_toggles[256] = {
+ [0x3A] KB_CPSLK,
+ [0x45] KB_NUMLK,
+ [0x46] KB_SCLLK
+};
+
+static uint8_t keymap_normal[256] = {
+ 0, 0x1B, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '\b', '\t',
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', '\n', 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', 0, '*',
+ 0, ' ', 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, '7',
+ '8', '9', '-', '4', '5', '6', '+', '1',
+ '2', '3', '0', '.', 0, 0, 0, 0,
+ [0x9C] '\n',
+ [0xB5] '/',
+ [0xC8] KB_UP,
+ [0xD0] KB_DOWN,
+ [0xC9] KB_PGUP,
+ [0xD1] KB_PGDN,
+ [0xCB] KB_LEFT,
+ [0xCD] KB_RGHT,
+ [0x97] KB_HOME,
+ [0xCF] KB_END,
+ [0xD2] KB_INS,
+ [0xD3] KB_DEL
+};
+
+static uint8_t keymap_shifted[256] = {
+ 0, 0x33, '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', '\b', '\t',
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', '\n', 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', 0, '*',
+ 0, ' ', 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, '7',
+ '8', '9', '-', '4', '5', '6', '+', '1',
+ '2', '3', '0', '.', 0, 0, 0, 0,
+ [0x9C] '\n',
+ [0xB5] '/',
+ [0xC8] KB_UP,
+ [0xD0] KB_DOWN,
+ [0xC9] KB_PGUP,
+ [0xD1] KB_PGDN,
+ [0xCB] KB_LEFT,
+ [0xCD] KB_RGHT,
+ [0x97] KB_HOME,
+ [0xCF] KB_END,
+ [0xD2] KB_INS,
+ [0xD3] KB_DEL
+};
+
+static uint8_t keymap_control[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'),
+ C('O'), C('P'), 0, 0, '\r', 0, C('A'), C('S'),
+ C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), 0,
+ 0, 0, 0, C('\\'), C('Z'), C('X'), C('C'), C('V'),
+ C('B'), C('N'), C('M'), 0, 0, C('/'), 0, 0,
+ [0x9C] '\r',
+ [0xB5] C('/'),
+ [0xC8] KB_UP,
+ [0xD0] KB_DOWN,
+ [0xC9] KB_PGUP,
+ [0xD1] KB_PGDN,
+ [0xCB] KB_LEFT,
+ [0xCD] KB_RGHT,
+ [0x97] KB_HOME,
+ [0xCF] KB_END,
+ [0xD2] KB_INS,
+ [0xD3] KB_DEL
+};
+
+static uint8_t* keymaps[4] = {
+ keymap_normal,
+ keymap_shifted,
+ keymap_control,
+ keymap_control,
+};
+
+char keyboard_getchar(void) {
+ static int shift = 0;
+ uint8_t st = inb(KB_STAT);
+ if ((st & KB_DIB) == 0)
+ return -1;
+
+ uint8_t data = inb(KB_DATA);
+
+ if (data == 0xE0) {
+ shift |= KB_E0ESC;
+ return -1;
+ } else if (data & 0x80) {
+ if (!(shift & KB_E0ESC))
+ data &= 0x7F;
+ shift &= ~(keymap_modifiers[data] | KB_E0ESC);
+ return -1;
+ } else if (shift & KB_E0ESC) {
+ data |= 0x80;
+ shift &= ~KB_E0ESC;
+ }
+
+ shift |= keymap_modifiers[data];
+ shift ^= keymap_toggles[data];
+ char c = keymaps[shift & (KB_CTL | KB_SHIFT)][data];
+ if (shift & KB_CPSLK) {
+ if ('a' <= c && c <= 'z')
+ c += 'A' - 'a';
+ else if ('A' <= c && c <= 'Z')
+ c += 'a' - 'A';
+ }
+ return c;
+}
+
+void keyboard_handler(struct isr_frame *frame) {
+ char c = keyboard_getchar();
+ if (c != -1)
+ tty_getchar(c);
+ return;
+}
diff --git a/kernel/drivers/video/framebuffer.c b/kernel/drivers/video/framebuffer.c
new file mode 100644
index 0000000..3df3df4
--- /dev/null
+++ b/kernel/drivers/video/framebuffer.c
@@ -0,0 +1,109 @@
+#include <kernel/video/framebuffer.h>
+#include <kernel/video/vga.h>
+#include <kernel/asm.h>
+#include <kernel/kthread.h>
+#include <kernel/paging.h>
+#include <kernel/pic.h>
+#include <libk/string.h>
+#include <stddef.h>
+#include <stdint.h>
+
+static size_t fb_row;
+static size_t fb_column;
+static uint8_t fb_color;
+static uint16_t *framebuffer;
+
+void _enable_cursor(uint8_t cursor_start, uint8_t cursor_end) {
+ outb(0x3D4, 0x0A);
+ outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);
+
+ outb(0x3D4, 0x0B);
+ outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
+}
+
+void _update_cursor(size_t x, size_t y) {
+ uint16_t pos = y * VGA_WIDTH + x;
+
+ outb(0x3D4, 0x0F);
+ outb(0x3D5, (uint8_t)(pos & 0xFF));
+ outb(0x3D4, 0x0E);
+ outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
+}
+
+void _fb_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
+ const size_t index = y * VGA_WIDTH + x;
+ framebuffer[index] = vga_entry(c, color);
+}
+
+void _fb_scroll(void) {
+ for (size_t i = 0; i < VGA_HEIGHT-1; i++) {
+ for (size_t j = 0; j < VGA_WIDTH; j++)
+ framebuffer[i * VGA_WIDTH + j] = VGA_MEMORY[(i+1) * VGA_WIDTH + j];
+ }
+}
+
+void fb_init(void) {
+ fb_row = 0;
+ fb_column = 0;
+ fb_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
+ framebuffer = VGA_MEMORY;
+ for (size_t y = 0; y < VGA_HEIGHT; y++) {
+ for (size_t x = 0; x < VGA_WIDTH; x++)
+ _fb_putentryat(' ', fb_color, x, y);
+ }
+ _enable_cursor(0, 0);
+ _update_cursor(0, 0);
+}
+
+void fb_setcolor(uint8_t color) {
+ fb_color = color;
+}
+
+void fb_setpos(int x, int y) {
+ fb_row = y;
+ fb_column = x;
+ _update_cursor(fb_column, fb_row+1);
+}
+
+void fb_offsetpos(int dx, int dy) {
+ fb_row += dy;
+ fb_column += dx;
+ _update_cursor(fb_column, fb_row+1);
+}
+
+void fb_putchar(char c) {
+ unsigned char uc = c;
+ switch (uc) {
+ case '\r':
+ fb_column = 0;
+ break;
+ case '\n':
+ fb_column = 0;
+ if (++fb_row == VGA_HEIGHT) {
+ fb_row--;
+ _fb_scroll();
+ }
+ break;
+ case '\t':
+ fb_column += 4;
+ if (++fb_column == VGA_WIDTH) {
+ fb_column = 4;
+ if (++fb_row == VGA_HEIGHT) {
+ fb_row--;
+ _fb_scroll();
+ }
+ }
+ break;
+ default:
+ _fb_putentryat(uc, fb_color, fb_column, fb_row);
+ if (++fb_column == VGA_WIDTH) {
+ fb_column = 0;
+ if (++fb_row == VGA_HEIGHT) {
+ fb_row--;
+ _fb_scroll();
+ }
+ }
+ break;
+ }
+ _update_cursor(fb_column, fb_row+1);
+}
diff --git a/kernel/init.c b/kernel/init.c
deleted file mode 100644
index d4a3638..0000000
--- a/kernel/init.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <libk/io.h>
-#include <libk/string.h>
-#include <libk/kmalloc.h>
-#include <kernel/sched.h>
-#include <kernel/kthread.h>
-#include <kernel/pci.h>
-#include <kernel/serial.h>
-
-void jump_userspace(void);
-
-char rootfs[1024];
-char init_bin[1024];
-int gdbstub = 0;
-
-void process_cmd(char *cmdline) {
- char *token = strtok(cmdline, " ");
- while (token != NULL) {
- if (strncmp(token, "root=", 5) == 0)
- strcpy(rootfs, &token[5]);
- if (strncmp(token, "init=", 5) == 0)
- strcpy(init_bin, &token[5]);
- if (strncmp(token, "gdb", 3) == 0)
- gdbstub = 1;
- token = strtok(NULL, " ");
- }
-}
-
-void kernel_main(char *cmdline) {
- kprintf("Box kernel version %s\n", VERSION);
- process_cmd(cmdline);
-
- serial_init();
- sched_init();
- //pci_check_buses();
-}
diff --git a/kernel/libk/io.c b/kernel/libk/io.c
new file mode 100644
index 0000000..eedc171
--- /dev/null
+++ b/kernel/libk/io.c
@@ -0,0 +1,78 @@
+#include <libk/io.h>
+#include <libk/string.h>
+#include <kernel/video/framebuffer.h>
+#include <kernel/tty/tty_vga.h>
+
+char* convert(unsigned int num, int base) {
+ static char rep[] = "0123456789ABCDEF";
+ static char buffer[50];
+ char *ptr;
+
+ ptr = &buffer[49];
+ *ptr = '\0';
+
+ do {
+ *--ptr = rep[num%base];
+ num /= base;
+ } while (num != 0);
+
+ return ptr;
+}
+
+int vkprintf(const char *fmt, va_list args) {
+ char *s;
+ int i;
+
+ char buffer[4096];
+ memset(buffer, 0, 4096);
+ for (size_t n = 0; n < strlen(fmt); n++) {
+ if (fmt[n] != '%') {
+ buffer[strlen(buffer)] = fmt[n];
+ continue;
+ } else {
+ n++;
+ }
+
+ switch (fmt[n]) {
+ case 'c':
+ i = va_arg(args, int);
+ buffer[strlen(buffer)] = i;
+ break;
+ case 's':
+ s = va_arg(args, char*);
+ strcat(buffer, s);
+ break;
+ case 'd':
+ i = va_arg(args, int);
+ if (i < 0) {
+ i = -i;
+ strcat(buffer, "-");
+ }
+ strcat(buffer, convert(i, 10));
+ break;
+ case 'o':
+ i = va_arg(args, unsigned int);
+ strcat(buffer, convert(i, 10));
+ break;
+ case 'x':
+ i = va_arg(args, unsigned int);
+ strcat(buffer, convert(i, 16));
+ break;
+ }
+ }
+ //tty_write(buffer, strlen(buffer));
+ fb_write(buffer, strlen(buffer));
+ memset(buffer, 0, 4096);
+ return 0;
+}
+
+int kprintf(const char *fmt, ...) {
+ va_list args;
+ int done;
+
+ va_start(args, fmt);
+ done = vkprintf(fmt, args);
+ va_end(args);
+
+ return done;
+}
diff --git a/kernel/libk/string.c b/kernel/libk/string.c
new file mode 100644
index 0000000..be59397
--- /dev/null
+++ b/kernel/libk/string.c
@@ -0,0 +1,133 @@
+#include <libk/string.h>
+
+int memcmp(const void *str1, const void *str2, size_t n) {
+ unsigned char const *p1 = str1;
+ unsigned char const *p2 = str2;
+ int ret = 0;
+
+ if (str1 == str2)
+ return 0;
+
+ while (n > 0) {
+ if (*p1 != *p2) {
+ ret = (*p1 > *p2)?1:-1;
+ break;
+ }
+ n--;
+ p1++;
+ p2++;
+ }
+ return ret;
+}
+
+void* memcpy(void* __restrict dest, const void* __restrict src, size_t n) {
+ if (dest == src)
+ return dest;
+
+ unsigned char *pdest = dest;
+ unsigned char const *psrc = src;
+ for (size_t i = 0; i < n; i++)
+ pdest[i] = psrc[i];
+ return dest;
+}
+
+char* strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
+ for (size_t i = 0; i < n; i++) {
+ if (src[i] == '\0')
+ break;
+ dest[i] = src[i];
+ }
+ return dest;
+}
+
+char* strcpy(char* __restrict dest, const char* __restrict src) {
+ return (char*)memcpy(dest, src, strlen(src));
+}
+
+char* strcat(char* __restrict dest, const char* __restrict src) {
+ return (char*)memcpy(&dest[strlen(dest)], src, strlen(src));
+}
+
+char* strncat(char* __restrict dest, const char* __restrict src, size_t n) {
+ return (char*)memcpy(&dest[strlen(dest)], src, n);
+}
+
+void* memmove(void* __restrict dest, const void* __restrict src, size_t n) {
+ if (dest == src)
+ return dest;
+
+ unsigned char const *psrc = src;
+ unsigned char buffer[n];
+
+ for (size_t i = 0; i < n; i++)
+ buffer[i] = psrc[i];
+ return memcpy(dest, (void*)buffer, n);
+}
+
+void* memset(void *str, int c, size_t n) {
+ unsigned char *p = str;
+ for (size_t i = 0; i < n; i++)
+ p[i] = (unsigned char)c;
+ return str;
+}
+
+int strncmp(const char *str1, const char *str2, size_t n) {
+ return memcmp(str1, str2, n);
+}
+
+int strcmp(const char *str1, const char *str2) {
+ size_t str1_sz = strlen(str1);
+ size_t str2_sz = strlen(str2);
+ if (str1_sz > str2_sz)
+ return memcmp(str1, str2, str2_sz);
+ return memcmp(str1, str2, str1_sz);
+}
+
+size_t strlen(const char *str) {
+ size_t i = 0;
+ while (str[i] != '\0')
+ i++;
+ return i;
+}
+
+int _is_delim(char c, const char *delim) {
+ while (*delim != '\0') {
+ if (c == *delim)
+ return 1;
+ delim++;
+ }
+ return 0;
+}
+
+char* strtok(char* __restrict str, const char* __restrict delim) {
+ static char *old_str;
+
+ if (str == NULL)
+ str = old_str;
+
+ while (1) {
+ if (_is_delim(*str, delim)) {
+ str++;
+ continue;
+ }
+
+ if (*str == '\0')
+ return NULL;
+ break;
+ }
+
+ char *ret = str;
+ while (1) {
+ if (*str == '\0') {
+ old_str = str;
+ return ret;
+ }
+
+ if (_is_delim(*str, delim)) {
+ *str = '\0';
+ old_str = str + 1;
+ return ret;
+ }
+ str++;
+ }
+}