From 597dc958a73664a11a8d9fb548a15cb9d05fac21 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 19:49:26 +0530 Subject: [PATCH 1/7] Add externally accessible idt_set_flags --- kernel/include/kernel/idt.h | 1 + kernel/src/kernel/idt.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/kernel/include/kernel/idt.h b/kernel/include/kernel/idt.h index 63e0e24..ad4886f 100644 --- a/kernel/include/kernel/idt.h +++ b/kernel/include/kernel/idt.h @@ -36,5 +36,6 @@ typedef void (*irq_handler_t) (registers_t*); void __init_idt__ (void); void idt_register_handler (int vector, irq_handler_t handler); +void idt_set_flags (int vector, uint8_t gate_type, uint8_t dpl, uint8_t ist); #endif \ No newline at end of file diff --git a/kernel/src/kernel/idt.c b/kernel/src/kernel/idt.c index 45ce7e2..7d9de72 100644 --- a/kernel/src/kernel/idt.c +++ b/kernel/src/kernel/idt.c @@ -91,6 +91,14 @@ void idt_register_handler (int vector, irq_handler_t handler) { interrupt_handlers[vector] = handler; } +void idt_set_flags (int vector, uint8_t gate_type, uint8_t dpl, uint8_t ist) { + idt_entry_t* descriptor = &idt[vector]; + + descriptor->gate_type = gate_type; + descriptor->dpl = dpl; + descriptor->ist = ist; +} + void __init_idt__ (void) { idtr.size = (uint16_t)(sizeof (idt_entry_t) * 256) - 1; idtr.offset = (uint64_t)&idt[0]; From 456bda45e15bc522b211cd85c75292fb5f1edaa3 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 19:49:37 +0530 Subject: [PATCH 2/7] Add basic framework for syscall --- kernel/include/kernel/syscall.h | 10 ++++++++++ kernel/src/kernel/syscall.c | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 kernel/include/kernel/syscall.h create mode 100644 kernel/src/kernel/syscall.c diff --git a/kernel/include/kernel/syscall.h b/kernel/include/kernel/syscall.h new file mode 100644 index 0000000..8e160d1 --- /dev/null +++ b/kernel/include/kernel/syscall.h @@ -0,0 +1,10 @@ + +#ifndef SYSCALL_H +#define SYSCALL_H + +#include + +void syscall_handler (registers_t* registers); +void __init_syscalls__ (void); + +#endif \ No newline at end of file diff --git a/kernel/src/kernel/syscall.c b/kernel/src/kernel/syscall.c new file mode 100644 index 0000000..6776feb --- /dev/null +++ b/kernel/src/kernel/syscall.c @@ -0,0 +1,9 @@ +#include +#include + +void syscall_handler (registers_t* registers) { uint8_t syscall_number = registers->rax; } + +void __init_syscalls__ (void) { + idt_register_handler (0x80, syscall_handler); + idt_set_flags (0x80, 0x0E, 3, 0); +} From 0cb2c5e569d4d91077b0a4adf65b074f2f35bc20 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 19:49:47 +0530 Subject: [PATCH 3/7] Initialise syscalls --- kernel/src/kernel/entry.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/src/kernel/entry.c b/kernel/src/kernel/entry.c index 2e45fed..dc10512 100644 --- a/kernel/src/kernel/entry.c +++ b/kernel/src/kernel/entry.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ void _start (void) { } __init_memmgt__ (hhdm_base, memmap_req.response); + __init_syscalls__ (); set_color (0x44eeaa); From 5b178871f730cb596af87bf9211cba857769f821 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 20:01:24 +0530 Subject: [PATCH 4/7] Add user flag in page allocator --- kernel/include/kernel/memmgt.h | 4 ++-- kernel/src/kernel/memmgt.c | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/include/kernel/memmgt.h b/kernel/include/kernel/memmgt.h index 0566dc1..061f7cd 100644 --- a/kernel/include/kernel/memmgt.h +++ b/kernel/include/kernel/memmgt.h @@ -89,8 +89,8 @@ vaddr_t get_vaddr_t_from_ptr (void* ptr); void* get_vaddr_hhdm (uint64_t phys_address); void* vaddr_t_to_ptr (vaddr_t* virtual_addr); -void* alloc_vpages (size_t req_count); -void* alloc_vpage (void); +void* alloc_vpages (size_t req_count, bool user); +void* alloc_vpage (bool user); void free_vpages (void* ptr, size_t count); void free_vpage (void* ptr); diff --git a/kernel/src/kernel/memmgt.c b/kernel/src/kernel/memmgt.c index 0aa6a97..2742013 100644 --- a/kernel/src/kernel/memmgt.c +++ b/kernel/src/kernel/memmgt.c @@ -275,7 +275,7 @@ static bool is_vaddr_t_lt (vaddr_t* a, vaddr_t* b) { * @param last last virtual address in range * @param base_addr base address of physical memory of corresponding size */ -static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base_addr) { +static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base_addr, bool user) { uint64_t phys_base_track = (uint64_t)base_addr; pml4t_entry_t* pml4t_entry = &pml4_base_ptr[first.pml4_index]; @@ -291,6 +291,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base pdpt_entry->present = 1; pdpt_entry->read_write = 1; pdpt_entry->pd_base_address = (uint64_t)new_table / PAGE_SIZE; + pdpt_entry->user_supervisor = user; memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE); } @@ -302,6 +303,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base pd_entry->present = 1; pd_entry->rw = 1; pd_entry->pt_base_address = (uint64_t)new_table / PAGE_SIZE; + pd_entry->us = user; memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE); } @@ -311,6 +313,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base pt_entry->present = 1; pt_entry->rw = 1; pt_entry->frame_base_address = phys_base_track / PAGE_SIZE; + pt_entry->us = user; phys_base_track += PAGE_SIZE; if (!is_vaddr_t_lt (¤t, &last)) @@ -333,7 +336,7 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base * @param count number of consecutive pages to allocate * @return base virtual address of allocated pages */ -void* alloc_vpages (size_t req_count) { +void* alloc_vpages (size_t req_count, bool user) { // all memory allocations are currently under one pml4 entry. this is 512 gb of memory, which // should be plenty for literally any use case of COS. pml4t_entry_t* pml4t_entry = &pml4_base_ptr[1]; @@ -414,7 +417,7 @@ void* alloc_vpages (size_t req_count) { ((start_page_idx + req_count - 1) >> 9) & 0x1FF, (start_page_idx + req_count - 1) & 0x1FF, 0}; - alloc_all_vpages_in_range (first_vaddr, last_vaddr, base_physical); + alloc_all_vpages_in_range (first_vaddr, last_vaddr, base_physical, user); return vaddr_t_to_ptr (&first_vaddr); } @@ -425,7 +428,7 @@ void* alloc_vpages (size_t req_count) { * Allocate one virtual page * @return base virtual address of allocated page */ -void* alloc_vpage (void) { return alloc_vpages (1); } +void* alloc_vpage (bool user) { return alloc_vpages (1, user); } /*! * Check if page structure is empty @@ -675,7 +678,7 @@ int liballoc_unlock () { return 0; } -void* liballoc_alloc (size_t count) { return alloc_vpages (count); } +void* liballoc_alloc (size_t count) { return alloc_vpages (count, false); } int liballoc_free (void* ptr, size_t count) { if (is_locked) From 326f7b00e59a87f001d5208f31d3867e190787bc Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 20:06:58 +0530 Subject: [PATCH 5/7] Fixes for user supervisor --- kernel/src/kernel/memmgt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/src/kernel/memmgt.c b/kernel/src/kernel/memmgt.c index 2742013..84a44f0 100644 --- a/kernel/src/kernel/memmgt.c +++ b/kernel/src/kernel/memmgt.c @@ -291,9 +291,9 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base pdpt_entry->present = 1; pdpt_entry->read_write = 1; pdpt_entry->pd_base_address = (uint64_t)new_table / PAGE_SIZE; - pdpt_entry->user_supervisor = user; memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE); } + pdpt_entry->user_supervisor = user; pd_entry_t* pd_base = (pd_entry_t*)get_vaddr_from_frame (pdpt_entry->pd_base_address); pd_entry_t* pd_entry = &pd_base[current.pd_index]; @@ -303,9 +303,9 @@ static void alloc_all_vpages_in_range (vaddr_t first, vaddr_t last, paddr_t base pd_entry->present = 1; pd_entry->rw = 1; pd_entry->pt_base_address = (uint64_t)new_table / PAGE_SIZE; - pd_entry->us = user; memset (get_vaddr_from_frame ((uint64_t)new_table / PAGE_SIZE), 0, PAGE_SIZE); } + pd_entry->us = user; pt_entry_t* pt_base = (pt_entry_t*)get_vaddr_from_frame (pd_entry->pt_base_address); pt_entry_t* pt_entry = &pt_base[current.pt_index]; @@ -567,6 +567,7 @@ void __init_memmgt__ (uint64_t p_hhdm_offset, struct limine_memmap_response* mem pml4_base_ptr[1].present = 1; pml4_base_ptr[1].read_write = 1; + pml4_base_ptr[1].user_supervisor = 1; pml4_base_ptr[1].pdpt_base_address = ((uint64_t)pdpt_frame) / PAGE_SIZE; } From 541e109ae6fd5dbee24f7fa2b455a2fdbcea9b83 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 20:18:00 +0530 Subject: [PATCH 6/7] Add handlers.c --- kernel/include/kernel/handlers.h | 11 +++++++++++ kernel/src/kernel/handlers.c | 10 ++++++++++ 2 files changed, 21 insertions(+) create mode 100644 kernel/include/kernel/handlers.h create mode 100644 kernel/src/kernel/handlers.c diff --git a/kernel/include/kernel/handlers.h b/kernel/include/kernel/handlers.h new file mode 100644 index 0000000..5f47442 --- /dev/null +++ b/kernel/include/kernel/handlers.h @@ -0,0 +1,11 @@ + +#ifndef HANDLERS_H +#define HANDLERS_H + +#include + +void handle_gpf (registers_t* registers); + +void __init_handlers__ (); + +#endif \ No newline at end of file diff --git a/kernel/src/kernel/handlers.c b/kernel/src/kernel/handlers.c new file mode 100644 index 0000000..12e4269 --- /dev/null +++ b/kernel/src/kernel/handlers.c @@ -0,0 +1,10 @@ +#include +#include + +void handle_gpf (registers_t* registers) { + write_serial_str ("\nOopsy! Looks like someone tried to execute a disallowed instruction!"); + for (;;) + ; +} + +void __init_handlers__ (void) { idt_register_handler (0xD, handle_gpf); } \ No newline at end of file From d15ad24785960ecdc6a5ab5309aa8048239724da Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sun, 15 Mar 2026 20:52:46 +0530 Subject: [PATCH 7/7] Add jump_to_usermode to entry.c --- kernel/src/kernel/entry.c | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/kernel/src/kernel/entry.c b/kernel/src/kernel/entry.c index dc10512..63535b8 100644 --- a/kernel/src/kernel/entry.c +++ b/kernel/src/kernel/entry.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +34,33 @@ static void hcf (void) { } } +__attribute__ ((noreturn)) void jump_to_usermode (uintptr_t entry_point, uintptr_t user_stack) { + __asm__ volatile ( + "cli \n\t" // 1. Disable interrupts while swapping states + "mov $0x3B, %%ax \n\t" // 2. Load User Data Segment descriptor (0x38 | 3 = 0x3B) + "mov %%ax, %%ds \n\t" + "mov %%ax, %%es \n\t" + "mov %%ax, %%fs \n\t" + "mov %%ax, %%gs \n\t" // (Note: if you use swapgs later, handling GS changes) + + // 3. Push the structure for iretq + "pushq $0x3B \n\t" // Push SS (User Data Segment) + "pushq %0 \n\t" // Push RSP (User Stack Pointer) + "pushq $0x202 \n\t" // Push RFLAGS (0x202 = Interrupts Enabled) + "pushq $0x43 \n\t" // Push CS (User Code Segment, 0x40 | 3 = 0x43) + "pushq %1 \n\t" // Push RIP (Entry Point) + + "iretq \n\t" // 4. Fire iretq to pop registers and drop to Ring 3 + : + : "r"(user_stack), "r"(entry_point) // Inputs from C + : "memory", "rax" // Clobbers + ); + + // This loop should never be reached, but satisfies compiling with noreturn + while (1) + ; +} + /*! Entry point of kernel. Everything is set up here. */ @@ -49,7 +78,7 @@ void _start (void) { asm ("cli"); gdt_init (); - // tss_init(); + tss_init (); __init_pic__ (); __init_idt__ (); @@ -75,6 +104,7 @@ void _start (void) { __init_memmgt__ (hhdm_base, memmap_req.response); __init_syscalls__ (); + __init_handlers__ (); set_color (0x44eeaa); @@ -105,6 +135,18 @@ void _start (void) { printf ("CR3: %lx", cr3); + printf ("\nJumping to user land!\n"); + + /* + * TODO: bunch of stuff + * - [ ] set up user mode code to actually compile + * - [ ] set up limine loading it as a module + * - [ ] set up a vfs + * - [ ] set up elf-loading + * - [ ] set up cpio reading and ramfs driver + * only THEN actually jump to user code + */ + // We're done, just hang... printf ("\n\nAll execution completed."); hcf ();