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:
+61
-38
@@ -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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user