sys: Refactor GDT initialization, enhance syscall handling, and improve user mode entry

Finally we got usermode working again, It took awhile but we got it done. A few things we did in this commit:

- Simplified GDT entry initialization in gdt.c for kernel and user segments.
- Fixed TSS structure for task switching.
- Implemented cr2 handling in a page fault.
- Enhanced user stack setup in usermode.c to return the correct RSP.
- Improved syscall implementation in syscall.c, including new syscall numbers.
- Updated syscall entry to correctly handle context switching and argument passing.
- Refactored init.c to demonstrate file operations using syscalls.
- Added new syscalls for file operations in syscalls.h.
- Modified VFS to handle leading slashes in paths correctly.

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-04-26 02:06:28 -04:00
parent 3b6e68bc16
commit e6e8b1209b
19 changed files with 263 additions and 266 deletions
+17 -29
View File
@@ -50,39 +50,27 @@ void x86_64_GDT_Initialize(void) {
// null desc
memset(&gdt.entries[0], 0, sizeof(struct gdt_desc));
// Kernel code 0x08
gdt.entries[1].limit = 0xFFFF;
gdt.entries[1].base_low = 0;
gdt.entries[1].base_mid = 0;
gdt.entries[1].base_hi = 0;
gdt.entries[1].access = 0b10011010;
gdt.entries[1].granularity = 0b00100000;
// Kernel code
gdt.entries[1].limit = 0xFFFF;
gdt.entries[1].access = 0x9A;
gdt.entries[1].granularity = 0x20;
// Kernel data 0x10
gdt.entries[2].limit = 0xFFFF;
gdt.entries[2].base_low = 0;
gdt.entries[2].base_mid = 0;
gdt.entries[2].base_hi = 0;
gdt.entries[2].access = 0b10010010;
gdt.entries[2].granularity = 0b00100000;
// Kernel data
gdt.entries[2].limit = 0xFFFF;
gdt.entries[2].access = 0x92;
gdt.entries[2].granularity = 0x00;
// User data 0x1B
gdt.entries[3].limit = 0xFFFF;
gdt.entries[3].base_low = 0;
gdt.entries[3].base_mid = 0;
gdt.entries[3].base_hi = 0;
gdt.entries[3].access = 0b11110010;
gdt.entries[3].granularity = 0b00100000;
// User data
gdt.entries[3].limit = 0xFFFF;
gdt.entries[3].access = 0xF2;
gdt.entries[3].granularity = 0x00;
// User code 0x23
gdt.entries[4].limit = 0xFFFF;
gdt.entries[4].base_low = 0;
gdt.entries[4].base_mid = 0;
gdt.entries[4].base_hi = 0;
gdt.entries[4].access = 0b11111010;
gdt.entries[4].granularity = 0b00100000;
// User code
gdt.entries[4].limit = 0xFFFF;
gdt.entries[4].access = 0xFA;
gdt.entries[4].granularity = 0x20;
// TSS
// TSS 0x28
gdt.tss.length = sizeof(struct tss);
gdt.tss.flags1 = 0b10001001;
+2
View File
@@ -30,5 +30,7 @@ struct tss {
uint16_t iomap_base;
} __attribute__((packed));
extern struct tss kernel_tss;
void x86_64_GDT_Initialize(void);
void gdt_load_tss(size_t addr);
+2 -2
View File
@@ -6,13 +6,13 @@
gdt_reload:
lgdt [rip + gdt_pointer]
push 8
push 0x08
lea rax, [rip + .flush]
push rax
lretq
.flush:
mov eax, 0x10
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
+42
View File
@@ -5,6 +5,12 @@
#include "idt.h"
#define MODULE "ISR"
static inline uint64_t x86_64_read_cr2(void)
{
uint64_t value;
__asm__ volatile ("mov %%cr2, %0" : "=r"(value));
return value;
}
ISRHandler g_ISRHandlers[256];
static const char* const g_Exceptions[] = {
@@ -52,8 +58,44 @@ void x86_64_ISR_Initialize(void)
x86_64_IDT_DisableGate(0x80); // syscall gate if you want
}
void page_fault_handler(Registers* regs, uint64_t cr2)
{
// You can decode error bits here:
// bit 0: present
// bit 1: write
// bit 2: user-mode
// bit 3: reserved overwrite
// bit 4: instruction fetch
log_crit(MODULE, "KERNEL PANIC! Exception %d (%s)", regs->interrupt, g_Exceptions[regs->interrupt]);
log_crit(MODULE, " rax=%x rbx=%x rcx=%x rdx=%x rsi=%x rdi=%x",
regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);
log_crit(MODULE, " rsp=%x rbp=%x rip=%x rflags=%x cs=%x ss=%x",
regs->rsp, regs->rbp, regs->rip, regs->rflags, regs->cs, regs->ss);
log_crit(MODULE, " interrupt=%x errorcode=%x", regs->interrupt, regs->error);
log_crit("PAGEFAULT", "Fault at address %lx (rip=%lx, err=%x)",
cr2, regs->rip, regs->error);
log_crit(MODULE, "KERNEL PANIC!");
x86_64_Panic(); // or attempt recovery
}
void __attribute__((used)) x86_64_ISR_Handler(Registers* regs)
{
if (regs->interrupt == 14)
{
uint64_t cr2 = x86_64_read_cr2();
page_fault_handler(regs, cr2);
}
if (g_ISRHandlers[regs->interrupt])
g_ISRHandlers[regs->interrupt](regs);
else if (regs->interrupt >= 32)
+42 -24
View File
@@ -22,54 +22,73 @@ static uint64_t user_stack_phys_base = 0;
extern struct pagemap *kernel_pagemap;
static void setup_user_stack()
uintptr_t setup_user_stack(void)
{
// Allocate contiguous physical pages for the stack
user_stack_phys_base = (uint64_t)pmm_alloc(USER_STACK_PAGES);
if (!user_stack_phys_base) {
printf("Failed to allocate user stack pages!\n");
for (;;);
}
uintptr_t stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
uintptr_t virt = stack_bottom;
for (int i = 0; i < USER_STACK_PAGES; i++) {
uint64_t phys = user_stack_phys_base + i * PAGE_SIZE;
uintptr_t virt = stack_bottom + i * PAGE_SIZE;
uintptr_t phys = user_stack_phys_base + i * PAGE_SIZE;
if (!vmm_map_page(kernel_pagemap, virt, phys,
PAGE_READ | PAGE_WRITE | PAGE_USER, Size4KiB)) {
printf("Failed to map user stack at 0x%lx\n", virt);
if (!vmm_map_page(kernel_pagemap,
virt,
phys,
PAGE_READ | PAGE_WRITE | PAGE_USER,
Size4KiB))
{
printf("Failed mapping user stack page\n");
for (;;);
}
virt += PAGE_SIZE;
}
// Zero the stack
memset((void*)stack_bottom, 0, USER_STACK_SIZE);
}
// zero physical page through HHDM
//memset((void *)(phys + g_hhdm_offset), 0, PAGE_SIZE);
}
uintptr_t rsp = USER_STACK_TOP;
rsp &= ~0xFULL;
return rsp;
}
// usermode.c
__attribute__((naked))
void enter_user_mode(uint64_t rip, uint64_t rsp)
{
asm volatile (
asm volatile(
"cli\n\t"
"mov $0x1B, %%ax\n\t" // User data segment
"mov $0x1B, %%ax\n\t"
"mov %%ax, %%ds\n\t"
"mov %%ax, %%es\n\t"
"mov %%ax, %%fs\n\t"
"mov %%ax, %%gs\n\t"
"push $0x1B\n\t" // SS (user data)
"push %1\n\t" // RSP
// SS
"pushq $0x1B\n\t"
// RSP
"pushq %1\n\t"
// RFLAGS
"pushfq\n\t"
"pop %%rax\n\t"
"or $0x200, %%rax\n\t" // Enable interrupts
"push %%rax\n\t" // RFLAGS
"push $0x23\n\t" // CS (user code)
"push %0\n\t" // RIP
"or $0x200, %%rax\n\t"
"push %%rax\n\t"
// CS
"pushq $0x23\n\t"
// RIP
"pushq %0\n\t"
"iretq\n\t"
:
: "r"(rip), "r"(rsp)
@@ -91,10 +110,9 @@ void start_userspace(void)
for(;;);
}
setup_user_stack();
uintptr_t rsp = setup_user_stack();
printf("Jumping to user entry: 0x%lx with stack top 0x%lx\n",
(uint64_t)entry, USER_STACK_TOP);
printf("Entering usermode RIP=%p RSP=%p\n", entry, (void*)rsp);
enter_user_mode((uint64_t)entry, USER_STACK_TOP);
enter_user_mode((uint64_t)entry, (rsp & ~0xFULL));
}