diff --git a/.tokeignore b/.tokeignore index 9b34107..ac8ae9d 100644 --- a/.tokeignore +++ b/.tokeignore @@ -5,4 +5,5 @@ kernel/data *.md tools/ bootloader/ -bootloader/src/uefi \ No newline at end of file +bootloader/src/uefi +initramfs/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c23b984..b95f628 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ if(QEMU_EXE) -net none -serial stdio -m 512M + -s DEPENDS image ) endif() \ No newline at end of file diff --git a/kernel/inc/arch/x86_64/gdt.h b/kernel/inc/arch/x86_64/gdt.h index 1da893f..9367b4c 100644 --- a/kernel/inc/arch/x86_64/gdt.h +++ b/kernel/inc/arch/x86_64/gdt.h @@ -37,4 +37,6 @@ typedef struct { u16 iomap_base; } __attribute__((packed)) TSS; +extern TSS tss; + void gdt_init(); diff --git a/kernel/inc/core/scheduler.h b/kernel/inc/core/scheduler.h index 4013c20..d2efc49 100644 --- a/kernel/inc/core/scheduler.h +++ b/kernel/inc/core/scheduler.h @@ -8,9 +8,10 @@ typedef struct task { struct task* next; u32 id; u32 sleep_ticks; -} task_t; + u64 kernel_stack_top; +} task; void sched_init(); -task_t* sched_spawn(void(*entry)()); +task* sched_spawn(void(*entry)()); u64 sched_next(u64 curr_rsp); void yield(u64 ticks); \ No newline at end of file diff --git a/kernel/src/arch/x86_64/gdt.c b/kernel/src/arch/x86_64/gdt.c index 76c8c92..8d75e60 100644 --- a/kernel/src/arch/x86_64/gdt.c +++ b/kernel/src/arch/x86_64/gdt.c @@ -4,8 +4,9 @@ // just fucking kill me already #include +#define GDT_ENTIRES 7 -GDTDescriptor gdt[5]; +GDTDescriptor gdt[GDT_ENTIRES]; GDTPtr gdt_ptr; TSS tss; u8 double_fault_stack[4096] = {0}; @@ -40,7 +41,7 @@ void write_tss(int num) { extern void gdt_flush(u64 gdt_ptr_addr); // entry.asm void gdt_init() { - gdt_ptr.limit = (sizeof(GDTDescriptor) * 5) - 1; + gdt_ptr.limit = (sizeof(GDTDescriptor) * GDT_ENTIRES) - 1; gdt_ptr.base = (u64)&gdt; // 0: Null @@ -53,17 +54,25 @@ void gdt_init() { // 0x20 = 0010 0000 bit 5 is "Long mode" // 2: Kernel Data (Ring 0) // Access: 0x92 (Present, Ring0, Read/Write) - gdt_set_gate(2, 0, 0, 0x92, 0); // 0x92 can't exec + gdt_set_gate(2, 0, 0, 0x92, 0); // 0x92 = 1 00 1 0 0 1 - for (u64 i = 0; i < sizeof(TSS); i++) ((u8*)&tss)[i] = 0; // hack. zeroifying tss struct + // 3: User Data (Ring 3) + // Access: 0xF2 (Present, Ring3, Read/Write) + gdt_set_gate(3, 0, 0, 0xF2, 0); // 0xF2 = 1 11 1 0 0 1 + + // 4: User Code (Ring 3) + // Access: 0xFA (Present, Ring3, RWX) + gdt_set_gate(4, 0, 0, 0xFA, 0x20); // 0xFA = 1 11 1 1 0 1 + + for (u64 i = 0; i < sizeof(TSS); i++) ((u8*)&tss)[i] = 0; // zeroifying tss struct tss.iomap_base = sizeof(TSS); tss.ist1 = (u64)double_fault_stack + sizeof(double_fault_stack); - write_tss(3); + write_tss(5); gdt_flush((u64)&gdt_ptr); - // telling cpu that TSS info located at gdt[3]; offset = 3 * 8 = 24 = 0x18 - __asm__ volatile ("ltr %%ax" :: "a" (0x18)); + // telling cpu that TSS info located at gdt[5]; offset = 5 * 8 = 40 = 0x28 + __asm__ volatile ("ltr %%ax" :: "a" (0x28)); } diff --git a/kernel/src/core/panic.c b/kernel/src/core/panic.c index 3057511..cf6bc8d 100644 --- a/kernel/src/core/panic.c +++ b/kernel/src/core/panic.c @@ -133,7 +133,7 @@ __attribute__((noreturn)) void panic_exception(Registers *regs) { u64 user = (regs->err_code & (1 << 2)) != 0; u64 reserved = (regs->err_code & (1 << 3)) != 0; u64 instruction = (regs->err_code & (1 << 4)) != 0; - kprintf("\t\t\t[^bP^!] ^yReason^! %s\n", present ? "Page Protection violation" : "Non-present page"); + kprintf("\t\t\t[^bP^!] ^yReason^!: %s\n", present ? "Page Protection violation" : "Non-present page"); kprintf("\t\t\t[^bW^!] ^yCaused by^! %s\n", write ? "WRITE" : "READ"); kprintf("\t\t\t[^bU^!] ^yRing^! %s\n", user ? "3" : "0"); if (reserved) kprintf("\t\t\t[^bR^!] CPU Wrote 1 to a reserved field in page table entry. ^rCorrupt page table?^!\n"); diff --git a/kernel/src/core/scheduler.c b/kernel/src/core/scheduler.c index 9ef5501..a9eed8b 100644 --- a/kernel/src/core/scheduler.c +++ b/kernel/src/core/scheduler.c @@ -4,14 +4,15 @@ #include #include #include +#include -task_t* curr_task = nullptr; +task* curr_task = nullptr; u32 next_pid = 1; extern void irq0_handler(); void sched_init() { - task_t* kt = (task_t*)malloc(sizeof(task_t)); + task* kt = (task*)malloc(sizeof(task)); kt->id = 0; kt->sleep_ticks = 0; @@ -20,8 +21,8 @@ void sched_init() { curr_task = kt; } -task_t* sched_spawn(void(*entry)()) { - task_t* t = (task_t*)malloc(sizeof(task_t)); +task* sched_spawn(void(*entry)()) { + task* t = (task*)malloc(sizeof(task)); if (!t) return nullptr; u64 stack_size = 16384; @@ -44,8 +45,8 @@ task_t* sched_spawn(void(*entry)()) { t->id = next_pid++; t->sleep_ticks = 0; t->next = curr_task->next; + t->kernel_stack_top = (u64)stack_base + stack_size; curr_task->next = t; - return t; } @@ -53,7 +54,7 @@ u64 sched_next(u64 curr_rsp) { if (!curr_task) return curr_rsp; curr_task->rsp = curr_rsp; - task_t* it = curr_task->next; + task* it = curr_task->next; do { if (it->sleep_ticks > 0) it->sleep_ticks--; @@ -62,10 +63,11 @@ u64 sched_next(u64 curr_rsp) { if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--; - task_t* next = curr_task->next; + task* next = curr_task->next; while (next != curr_task && next->sleep_ticks > 0) next = next->next; // what the fuck i just wrote curr_task = next; + tss.rsp0 = curr_task->kernel_stack_top; return curr_task->rsp; } diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 6a1236a..7c40f36 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -63,10 +63,10 @@ void kmain(Bootinfo* info) { fs_node* root = cpio_mount(PHYS_TO_HHDM(info->initramfs.addr), info->initramfs.size); vfs_init(root); - kprintf("VFS initialized"); + kprintf("VFS initialized\n"); u32 *fb = (u32*)info->framebuffer.base; - if (!fb) return serial_write("No framebuffer found!!"); + if (!fb) return kprintf("No framebuffer found!!"); sg_ctx.fb = fb; sg_ctx.height = info->framebuffer.height; diff --git a/kernel/src/mm/vmm.c b/kernel/src/mm/vmm.c index 8415fd9..0bc0666 100644 --- a/kernel/src/mm/vmm.c +++ b/kernel/src/mm/vmm.c @@ -18,7 +18,6 @@ extern u64 _kernel_end; extern u8* bitmap; extern u64 bitmap_size_g; extern GDTDescriptor gdt[]; -extern TSS tss[]; extern IDTEntry idt[]; extern u8 double_fault_stack[]; extern u8 stack_guard; @@ -37,12 +36,16 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) { u64* pml4_virt = pml4; if (is_initialized) pml4_virt = (u64*)PHYS_TO_HHDM((u64)pml4); + u64 table_flags = PTE_PRESENT | PTE_RW | (flags & PTE_USER); + if (!(pml4_virt[pml4_idx] & PTE_PRESENT)) { u64* addr = pmm_alloc_page(); if (!addr) return nullptr; u64* addr_virt = get_table_virt((u64)addr); memset(addr_virt, 0, PAGE_SIZE); - pml4_virt[pml4_idx] = (u64)addr | PTE_PRESENT | PTE_RW; + pml4_virt[pml4_idx] = (u64)addr | table_flags; + } else { + pml4_virt[pml4_idx] |= (flags & PTE_USER); } u64* pdpt = (u64*)PTE_GET_ADDR(pml4_virt[pml4_idx]); @@ -53,7 +56,9 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) { if (!addr) return nullptr; u64* addr_virt = get_table_virt((u64)addr); memset(addr_virt, 0, PAGE_SIZE); - pdpt_virt[pdpt_idx] = (u64)addr | PTE_PRESENT | PTE_RW; + pdpt_virt[pdpt_idx] = (u64)addr | table_flags; + } else { + pdpt_virt[pdpt_idx] |= (flags & PTE_USER); } u64* pd = (u64*)PTE_GET_ADDR(pdpt_virt[pdpt_idx]); @@ -64,7 +69,9 @@ u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags) { if (!addr) return nullptr; u64* addr_virt = get_table_virt((u64)addr); memset(addr_virt, 0, PAGE_SIZE); - pd_virt[pd_idx] = (u64)addr | PTE_PRESENT | PTE_RW; + pd_virt[pd_idx] = (u64)addr | table_flags; + } else { + pd_virt[pd_idx] |= (flags & PTE_USER); } u64* pt = (u64*)PTE_GET_ADDR(pd_virt[pd_idx]); diff --git a/kernel/src/shell/dbgcmd.c b/kernel/src/shell/dbgcmd.c index 120773f..5c6c8fa 100644 --- a/kernel/src/shell/dbgcmd.c +++ b/kernel/src/shell/dbgcmd.c @@ -3,29 +3,55 @@ // contents of this file will be changed CONSTANTLY // im just testing new stuff here -#include +#include "mm/vmm.h" +#include #include -#include -#include +#include + +extern u64* pml4_kernel; + +#define USER_DS (0x18 | 3) +#define USER_CS (0x20 | 3) +#define RFLAGS_IF 0x202 + +void jump_to_userspace(void* entry, void* user_stack_top) { + __asm__ volatile ( + "mov %0, %%ds\n" + "mov %0, %%es\n" + "mov %0, %%fs\n" + "mov %0, %%gs\n" + :: "r" ((u64)USER_DS) : "memory" + ); + + __asm__ volatile ( + "pushq %0\n" // SS (User Data Selector) + "pushq %1\n" // RSP (User Stack Pointer) + "pushq %2\n" // RFLAGS + "pushq %3\n" // CS (User Code Selector) + "pushq %4\n" // RIP (Entry Point) + "iretq\n" // jump + : + : "r" ((u64)USER_DS), + "r" ((u64)user_stack_top), + "r" ((u64)RFLAGS_IF), + "r" ((u64)USER_CS), + "r" ((u64)entry) + : "memory" + ); +} u64 debug() { - kprintf("Debug: Trying to open /test1.txt...\n"); - - fs_node* file = vfs_open("/test1.txt"); - - if (file == nullptr) { - kprintf("Error: File not found! Check initrd or filename.\n"); - return 1; - } - - kprintf("Success!\n"); - kprintf("\tFilename: %s\n", file->name); - kprintf("\tSize: %d bytes\n", file->len); - - char buf[64]; - memset(buf, 0, 64); - vfs_read(file, 0, 63, (u8*)buf); - kprintf("\tContent: %s\n", buf); + void* phys_code = pmm_alloc_page(); + void* phys_stack = pmm_alloc_page(); + u64 virt_code = 0x400000; + u64 virt_stack = 0x800000; + vmm_map_page(pml4_kernel, (u64)phys_code, virt_code, PTE_PRESENT | PTE_RW | PTE_USER); + vmm_map_page(pml4_kernel, (u64)phys_stack, virt_stack, PTE_PRESENT | PTE_RW | PTE_USER); + u8* kernel_view = (u8*)(HHDM_OFFSET + phys_code); + kernel_view[0] = 0xEB; // jmp + kernel_view[1] = 0xFE; // to self + kprintf("Jumping to userspace. Goodbye."); + jump_to_userspace((void*)virt_code, (void*)(virt_stack + 4096)); return 0; } \ No newline at end of file