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:
Binary file not shown.
+17
-29
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
+9
-3
@@ -3,6 +3,7 @@
|
||||
#include <arch/x86_64/e9.h>
|
||||
#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;
|
||||
|
||||
|
||||
+11
-116
@@ -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) {
|
||||
@@ -180,8 +180,6 @@ void kmain(void) {
|
||||
}
|
||||
x86_64_DisableInterrupts();
|
||||
|
||||
|
||||
|
||||
uint32_t msr_lo, msr_hi;
|
||||
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
|
||||
msr_lo &= ~(1 << 11);
|
||||
@@ -204,7 +202,6 @@ void kmain(void) {
|
||||
calibrate_tsc();
|
||||
|
||||
|
||||
|
||||
//while (1) asm volatile("hlt");
|
||||
|
||||
ata_init();
|
||||
@@ -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) {
|
||||
@@ -365,19 +268,7 @@ void kmain(void) {
|
||||
|
||||
//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();
|
||||
|
||||
+1
-24
@@ -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++) {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
};
|
||||
+59
-36
@@ -1,54 +1,72 @@
|
||||
#include <stdint.h>
|
||||
#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)
|
||||
(void)arg4; (void)arg5; (void)arg6;
|
||||
switch (num)
|
||||
{
|
||||
case 1: // write (int fd, const void *buf, size_t count);
|
||||
int c = (char)rdi;
|
||||
printf("%c", c);
|
||||
break;
|
||||
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));
|
||||
}
|
||||
@@ -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);
|
||||
+24
-17
@@ -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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-7
@@ -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
|
||||
@@ -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;
|
||||
|
||||
+28
-4
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user