Files
KirkOS/src/syscall/syscall.c
T
kaguya e6e8b1209b 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>
2026-04-26 02:06:28 -04:00

100 lines
2.9 KiB
C

#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_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)
{
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));
return ((uint64_t)hi << 32) | lo;
}
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)
{
(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;
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:
return (uint64_t)-1;
}
}
void syscall_init(void)
{
extern void syscall_entry(void);
// ── 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));
// 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 |= EFER_SCE;
wrmsr(MSR_EFER, efer);
// Mask IF so interrupts are off during the syscall handler
wrmsr(MSR_SFMASK, (1 << 9));
}