diff --git a/ext2_root/init.elf b/ext2_root/init.elf index b7bbf25..f98c858 100755 Binary files a/ext2_root/init.elf and b/ext2_root/init.elf differ diff --git a/src/arch/x86_64/gdt.c b/src/arch/x86_64/gdt.c index 8085d85..bd940e1 100644 --- a/src/arch/x86_64/gdt.c +++ b/src/arch/x86_64/gdt.c @@ -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; diff --git a/src/arch/x86_64/gdt.h b/src/arch/x86_64/gdt.h index d94d59e..fd79dc8 100644 --- a/src/arch/x86_64/gdt.h +++ b/src/arch/x86_64/gdt.h @@ -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); \ No newline at end of file diff --git a/src/arch/x86_64/gdt_asm.S b/src/arch/x86_64/gdt_asm.S index c73ea11..b2c8417 100644 --- a/src/arch/x86_64/gdt_asm.S +++ b/src/arch/x86_64/gdt_asm.S @@ -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 diff --git a/src/arch/x86_64/isr.c b/src/arch/x86_64/isr.c index daa2623..b255b6d 100644 --- a/src/arch/x86_64/isr.c +++ b/src/arch/x86_64/isr.c @@ -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) diff --git a/src/arch/x86_64/usermode.c b/src/arch/x86_64/usermode.c index 77cc2ac..5728f7e 100644 --- a/src/arch/x86_64/usermode.c +++ b/src/arch/x86_64/usermode.c @@ -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)); } \ No newline at end of file diff --git a/src/fs/vfs.c b/src/fs/vfs.c index 2ca34a7..72b12b3 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -3,6 +3,7 @@ #include #include "mp/spinlock.h" #include "stdio.h" +#include "mm/memory.h" #include "string.h" static spinlock_t s_vfs_lock = SPINLOCK_INIT; @@ -36,8 +37,11 @@ int VFS_RegisterCharDev(const char* path, fd_t VFS_Open_internal(const char* path) { + const char* p = path; + if (*p == '/') p++; + for (int i = 0; i < s_num_chardevs; i++) { - if (strcmp(s_chardevs[i].path, path) == 0) { + if (strcmp(s_chardevs[i].path, p) == 0) { for (int fd = 4; fd < VFS_MAX_FDS; fd++) { if (!vfs_fd_table[fd].used) { vfs_fd_table[fd].used = true; @@ -51,7 +55,9 @@ fd_t VFS_Open_internal(const char* path) } } - uint32_t ino = ext2_resolve_path(path); + + + uint32_t ino = ext2_resolve_path(p); if (ino == 0) return -1; @@ -124,7 +130,7 @@ int VFS_Read(fd_t fd, uint8_t* buf, size_t size) size = file_size - file->offset; // naive: read whole file then slice - uint8_t tmp[file_size]; + uint8_t* tmp = kmalloc(file_size); if (!ext2_read_file(&file->ext2.inode, tmp)) return -1; diff --git a/src/main.c b/src/main.c index 70a596b..7defe12 100644 --- a/src/main.c +++ b/src/main.c @@ -126,15 +126,15 @@ static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) { return UACPI_INTERRUPT_HANDLED; } -// The following will be our kernel's entry point. -// If renaming kmain() to something else, make sure to change the -// linker script accordingly. + void kmain(void) { - // Ensure the bootloader actually understands our base revision (see spec). if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { hcf(); } + uint64_t rsp; + asm volatile("mov %%rsp, %0" : "=r"(rsp)); + // Ensure we got a framebuffer. if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) { @@ -179,8 +179,6 @@ void kmain(void) { entry->type); } x86_64_DisableInterrupts(); - - uint32_t msr_lo, msr_hi; asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B)); @@ -202,7 +200,6 @@ void kmain(void) { x86_64_PIT_Initialize(1000); asm volatile("sti"); calibrate_tsc(); - //while (1) asm volatile("hlt"); @@ -220,102 +217,8 @@ void kmain(void) { hcf(); } + ext2_read_root_dir(); - printf("test"); - - - uint8_t* file_buffer = kmalloc(4096); // adjust if needed - uint32_t file_size = 0; - - if (ext2_read_file_from_root("a.txt", file_buffer, &file_size)) { - printf("Read file (size %d):\n", file_size); - - for (uint32_t i = 0; i < file_size; i++) { - printf("%c", file_buffer[i]); // or printf("%c", ...) - } - - printf("\n"); - } else { - printf("Failed to read file\n"); - } - - kfree(file_buffer); - - uint8_t* file2_buffer = kmalloc(4096); // adjust if needed - uint32_t file2_size = 0; - - if (ext2_read_file_from_root("dogcatman.txt", file2_buffer, &file2_size)) { - printf("Read file (size %d):\n", file2_size); - - for (uint32_t i = 0; i < file2_size; i++) { - printf("%c", file2_buffer[i]); // or printf("%c", ...) - } - - printf("\n"); - } else { - printf("Failed to read file\n"); - } - - kfree(file2_buffer); - - uint8_t* file3_buffer = kmalloc(4096); // adjust if needed - uint32_t file3_size = 0; - - if (ext2_read_file_from_root("test.txt", file3_buffer, &file3_size)) { - printf("Read file (size %d):\n", file3_size); - - for (uint32_t i = 0; i < file3_size; i++) { - printf("%c", file3_buffer[i]); // or printf("%c", ...) - } - - printf("\n"); - } else { - printf("Failed to read file\n"); - } - - kfree(file3_buffer); - - uint8_t* file4_buffer = kmalloc(4096); // adjust if needed - uint32_t file4_size = 0; - - if (ext2_read_file_from_root("qwerty.txt", file4_buffer, &file4_size)) { - printf("Read file (size %d):\n", file4_size); - - for (uint32_t i = 0; i < file4_size; i++) { - printf("%c", file4_buffer[i]); // or printf("%c", ...) - } - - printf("\n"); - } else { - printf("Failed to read file\n"); - } - - - - kfree(file4_buffer); - - const char* msg = "hello i wrote from kernel!"; - - ext2_write_file_from_root("qwerty.txt", (const uint8_t*)msg, strlen(msg), EXT2_WRITE_APPEND); - - uint8_t* file5_buffer = kmalloc(4096); // adjust if needed - uint32_t file5_size = 0; - - if (ext2_read_file_from_root("qwerty.txt", file5_buffer, &file5_size)) { - printf("Read file (size %d):\n", file5_size); - - for (uint32_t i = 0; i < file5_size; i++) { - printf("%c", file5_buffer[i]); // or printf("%c", ...) - } - - printf("\n"); - } else { - printf("Failed to read file\n"); - } - - - - kfree(file5_buffer); uint32_t inum = ext2_resolve_path("charlie.tga"); if (!inum) { @@ -364,20 +267,8 @@ void kmain(void) { kfree(img); //clear_screen(0xFF1E1E1E); + - fd_t fd = VFS_Open("/a.txt"); - if (fd < 0) { - printf("asudg"); - } - uint8_t buf[128]; - int n; - - while ((n = VFS_Read(fd, buf, sizeof(buf))) > 0) - { - VFS_Write(VFS_FD_STDOUT, buf, n); - } - - VFS_Close(fd); printf("\nKirkOS %s\n", KIRKOS_VERSION); x86_64_EnableInterrupts(); @@ -454,8 +345,12 @@ void kmain(void) { input_init(); ps2_kbd_init(); - //syscall_init(); - //start_userspace(); + gdt_load_tss((size_t)&kernel_tss); + kernel_tss.rsp0 = rsp; + + + syscall_init(); + start_userspace(); // We're done, just hang... hcf(); diff --git a/src/mm/pmm.c b/src/mm/pmm.c index 5b116bb..742d033 100644 --- a/src/mm/pmm.c +++ b/src/mm/pmm.c @@ -11,7 +11,7 @@ static uint64_t free_pages = 0; void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) { uint64_t highest_addr = 0; - size_t memmap_entries = memmapentries - 1; + size_t memmap_entries = memmapentries; for (size_t i = 0; i < memmap_entries; i++) { if (memmap[i]->type != LIMINE_MEMMAP_USABLE && memmap[i]->type != LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) @@ -22,43 +22,20 @@ void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) { total_page_count = highest_addr / PAGE_SIZE; size_t bitmap_size = ALIGN_UP(total_page_count / 8, PAGE_SIZE); - printf("MEM_PHYS_OFFSET: %x\n", MEM_PHYS_OFFSET); - printf("memmap_entries: %u\n", memmap_entries); // Find place for bitmap for (size_t i = 0; i < memmap_entries; i++) { - printf("i: %u\n", i); if (memmap[i]->type != LIMINE_MEMMAP_USABLE) continue; if (memmap[i]->length >= bitmap_size) { - printf("test\n"); bitmap = (uint8_t *)(memmap[i]->base + MEM_PHYS_OFFSET); - printf("bitmap: %x\n", bitmap); - printf("bitmap_size: %x\n", bitmap_size); memset(bitmap, 0xFF, bitmap_size); - printf("test3\n"); - printf("memmap base: %x\n", memmap[i]->base); - printf("memmap length: %x\n", memmap[i]->length); memmap[i]->base += bitmap_size; memmap[i]->length -= bitmap_size; - printf("test4\n"); - printf("memmap[7]->type: %u\n", memmap[7]->type); - printf("memmap[8]->type: %u\n", memmap[8]->type); - printf("memmap[9]->type: %u\n", memmap[9]->type); - printf("memmap[10]->type: %u\n", memmap[10]->type); //#define LIMINE_MEMMAP_USABLE 0 - printf("memmap[11]->type: %u\n", memmap[11]->type); //#define LIMINE_MEMMAP_RESERVED 1 - printf("memmap[12]->type: %u\n", memmap[12]->type); //#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 - printf("memmap[13]->type: %u\n", memmap[13]->type); //#define LIMINE_MEMMAP_ACPI_NVS 3 - printf("memmap[14]->type: %u\n", memmap[14]->type); //#define LIMINE_MEMMAP_BAD_MEMORY 4 - printf("memmap[15]->type: %u\n", memmap[15]->type); //#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 - printf("memmap[16]->type: %u\n", memmap[16]->type); //#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6 - printf("memmap[17]->type: %u\n", memmap[17]->type); //#define LIMINE_MEMMAP_FRAMEBUFFER 7 - //printf("memmap[18]->type: %u\n", memmap[18]->type); //#define LIMINE_MEMMAP_RESERVED_MAPPED 8, commented out because it triple faults for some reason break; } } - printf("break"); // Mark usable pages free for (size_t i = 0; i < memmap_entries; i++) { diff --git a/src/mp/percpu.h b/src/mp/percpu.h new file mode 100644 index 0000000..b922ce5 --- /dev/null +++ b/src/mp/percpu.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +struct cpu_local { + uint64_t self; // +0x00 (GS:0x00) + uint64_t user_rsp; // +0x08 (GS:0x08) — saved user RSP on syscall entry + uint64_t kernel_rsp; // +0x10 (GS:0x10) — kernel stack for syscall handler +}; \ No newline at end of file diff --git a/src/syscall/syscall.c b/src/syscall/syscall.c index 7f4245d..4e97b77 100644 --- a/src/syscall/syscall.c +++ b/src/syscall/syscall.c @@ -1,54 +1,72 @@ #include #include "stdio.h" +#include "mp/percpu.h" #include "fs/vfs.h" +#include "syscall.h" -#define MSR_EFER 0xC0000080 -#define MSR_STAR 0xC0000081 -#define MSR_LSTAR 0xC0000082 -#define MSR_SFMASK 0xC0000084 +#define MSR_EFER 0xC0000080 +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_SFMASK 0xC0000084 +#define MSR_KERNEL_GSBASE 0xC0000102 #define EFER_SCE (1 << 0) +static struct cpu_local g_cpu_local; + +static uint8_t g_syscall_kstack[16384] __attribute__((aligned(16))); + static inline void wrmsr(uint32_t msr, uint64_t value) { - uint32_t lo = value & 0xFFFFFFFF; - uint32_t hi = value >> 32; - - asm volatile("wrmsr" - : - : "c"(msr), "a"(lo), "d"(hi)); + asm volatile("wrmsr" :: "c"(msr), "a"((uint32_t)value), "d"((uint32_t)(value >> 32))); } static inline uint64_t rdmsr(uint32_t msr) { uint32_t lo, hi; - asm volatile("rdmsr" - : "=a"(lo), "=d"(hi) - : "c"(msr)); + asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); return ((uint64_t)hi << 32) | lo; } -void syscall_handler(uint64_t rax, // syscall num - uint64_t rdi, // arg1 - uint64_t rsi, // arg2 - uint64_t rdx, // arg3 - uint64_t r10, // arg4 - uint64_t r8, // arg5 - uint64_t r9) // arg6 +uint64_t syscall_handler(uint64_t num, + uint64_t arg1, uint64_t arg2, uint64_t arg3, + uint64_t arg4, uint64_t arg5, uint64_t arg6) { - switch (rax) - { - case 1: // write (int fd, const void *buf, size_t count); - int c = (char)rdi; - printf("%c", c); - break; + (void)arg4; (void)arg5; (void)arg6; + switch (num) + { + case SYS_READ: + { + int fd = (int)arg1; + uint8_t* buf = (uint8_t*)arg2; + size_t len = (size_t)arg3; - case 2: - // exit - break; + return (uint64_t)VFS_Read(fd, buf, len); + } + + case SYS_WRITE: + { + int fd = (int)arg1; + uint8_t* buf = (uint8_t*)arg2; + size_t len = (size_t)arg3; + + return (uint64_t)VFS_Write(fd, buf, len); + } + + case SYS_OPEN: + { + const char* path = (const char*)arg1; + return (uint64_t)VFS_Open(path); + } + + case SYS_CLOSE: + { + int fd = (int)arg1; + return (uint64_t)VFS_Close(fd); + } default: - break; + return (uint64_t)-1; } } @@ -56,21 +74,26 @@ void syscall_init(void) { extern void syscall_entry(void); - uint64_t kernel_cs = 0x08; - uint64_t user_cs = 0x23; + // ── per-CPU local block ───────────────────────────────────────────── + g_cpu_local.self = (uint64_t)&g_cpu_local; + g_cpu_local.kernel_rsp = (uint64_t)(g_syscall_kstack + sizeof(g_syscall_kstack)); - uint64_t star = - ((uint64_t)kernel_cs << 32) | - ((uint64_t)user_cs << 48); + // After swapgs in syscall_entry, GS points here. + wrmsr(MSR_KERNEL_GSBASE, (uint64_t)&g_cpu_local); + // ── STAR ──────────────────────────────────────────────────────────── + // Bits [47:32]: SYSCALL loads CS = 0x08 (kernel code), SS = 0x10 (kernel data) + // Bits [63:48]: SYSRET loads CS = (base+16)|3 = 0x23, SS = (base+8)|3 = 0x1B + // → base must be 0x10 + uint64_t star = ((uint64_t)0x08 << 32) | ((uint64_t)0x10 << 48); wrmsr(MSR_STAR, star); wrmsr(MSR_LSTAR, (uint64_t)syscall_entry); uint64_t efer = rdmsr(MSR_EFER); - efer |= (1 << 0); // SYSCALL/SYSRET enable + efer |= EFER_SCE; wrmsr(MSR_EFER, efer); - // disable interrupts on syscall entry + // Mask IF so interrupts are off during the syscall handler wrmsr(MSR_SFMASK, (1 << 9)); -} \ No newline at end of file +} diff --git a/src/syscall/syscall.h b/src/syscall/syscall.h index b1c4560..8e7f4ab 100644 --- a/src/syscall/syscall.h +++ b/src/syscall/syscall.h @@ -1,3 +1,10 @@ #pragma once + +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 + + void syscall_init(void); \ No newline at end of file diff --git a/src/syscall/syscall_entry.S b/src/syscall/syscall_entry.S index 1411abf..c50b674 100644 --- a/src/syscall/syscall_entry.S +++ b/src/syscall/syscall_entry.S @@ -3,30 +3,37 @@ syscall_entry: swapgs - mov %rsp, %gs:0x10 # save user rsp for per cpu + # Save user RSP, switch to kernel stack + mov %rsp, %gs:0x08 # cpu_local.user_rsp = user RSP + mov %gs:0x10, %rsp # RSP = cpu_local.kernel_rsp - push %rcx # save user rip - push %r11 # save rflags + push %rcx # save user RIP (syscall puts it in RCX) + push %r11 # save user RFLAGS - # Save original args before we clobber them - push %rdi # orig rdi (arg1) - push %rsi # orig rsi (arg2) - push %rdx # orig rdx (arg3) + # ── Shuffle syscall regs → SysV args for syscall_handler ────────── + # On entry: rax=num rdi=a1 rsi=a2 rdx=a3 r10=a4 r8=a5 r9=a6 + # We want: rdi=num rsi=a1 rdx=a2 rcx=a3 r8=a4 r9=a5 + # + # Move r8/r10 FIRST before the push/pop clobbers them + mov %r8, %r9 # r9 = orig r8 (a5) + mov %r10, %r8 # r8 = orig r10 (a4) - # Handle r8/r9 before r8 gets clobbered - mov %r8, %r9 # r9 = orig r8 (6th param) - mov %r10, %r8 # r8 = orig r10 (5th param) + push %rdi # save orig rdi (a1) + push %rsi # save orig rsi (a2) + push %rdx # save orig rdx (a3) - # Pop in reverse order to place into correct SysV registers - pop %rcx # rcx = orig rdx (4th param) - pop %rdx # rdx = orig rsi (3rd param) - pop %rsi # rsi = orig rdi (2nd param) - mov %rax, %rdi # rdi = rax (1st param = syscall number) + pop %rcx # rcx = a3 (4th param) + pop %rdx # rdx = a2 (3rd param) + pop %rsi # rsi = a1 (2nd param) + mov %rax, %rdi # rdi = num (1st param) call syscall_handler - pop %r11 - pop %rcx + # ── Restore user context ─────────────────────────────────────────── + pop %r11 # user RFLAGS + pop %rcx # user RIP + + mov %gs:0x08, %rsp # restore user RSP ← this was the missing piece swapgs sysretq \ No newline at end of file diff --git a/user/build/crt0.o b/user/build/crt0.o index d2d1951..39d5c6a 100644 Binary files a/user/build/crt0.o and b/user/build/crt0.o differ diff --git a/user/build/init.elf b/user/build/init.elf index b7bbf25..f98c858 100755 Binary files a/user/build/init.elf and b/user/build/init.elf differ diff --git a/user/build/init.o b/user/build/init.o index 9c6a95c..3d22091 100644 Binary files a/user/build/init.o and b/user/build/init.o differ diff --git a/user/crt0.S b/user/crt0.S index 4a5326e..a64be0c 100644 --- a/user/crt0.S +++ b/user/crt0.S @@ -1,12 +1,7 @@ .section .text .global _start +.global main _start: - mov $1, %rax - mov $'H', %rdi - syscall - - mov $1, %rax - mov $'i', %rdi - syscall + call main 1: jmp 1b \ No newline at end of file diff --git a/user/include/syscalls.h b/user/include/syscalls.h index fdc0d8e..3c59949 100644 --- a/user/include/syscalls.h +++ b/user/include/syscalls.h @@ -1,5 +1,10 @@ #pragma once +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 + static inline long syscall(long num, long a1, long a2, long a3) { long ret; @@ -8,7 +13,6 @@ static inline long syscall(long num, long a1, long a2, long a3) "syscall" : "=a"(ret) : "a"(num), "D"(a1), "S"(a2), "d"(a3) - : ); return ret; diff --git a/user/programs/init.c b/user/programs/init.c index e39ade2..e02580e 100644 --- a/user/programs/init.c +++ b/user/programs/init.c @@ -1,5 +1,7 @@ #include "../include/syscalls.h" +#define STDOUT 1 + unsigned strlen(const char* str) { unsigned len = 0; @@ -8,15 +10,37 @@ unsigned strlen(const char* str) ++len; ++str; } - return len; } void main() { - syscall(1, 'A', 0, 0); - syscall(1, 'B', 0, 0); - syscall(1, 'C', 0, 0); + const char* path = "/qwerty.txt"; + const char* msg = "Suki Suki Daisuki Kekkon Shiyo, my honey!"; + char buf[128]; + + // ── open file ───────────────────────────── + long fd = syscall(SYS_OPEN, (long)path, 0, 0); + + // ── write message ───────────────────────── + syscall(SYS_WRITE, fd, (long)msg, strlen(msg)); + + // ── close ──────────────────────────────── + syscall(SYS_CLOSE, fd, 0, 0); + + // ── reopen ─────────────────────────────── + fd = syscall(SYS_OPEN, (long)path, 0, 0); + + // ── read into buffer ───────────────────── + long n = syscall(SYS_READ, fd, (long)buf, sizeof(buf)); + + // ── close ──────────────────────────────── + syscall(SYS_CLOSE, fd, 0, 0); + + // ── print buffer to stdout ─────────────── + syscall(SYS_WRITE, STDOUT, (long)buf, n); + + // ── done ──────────────────────────────── while (1); } \ No newline at end of file