#include "syscall/syscall.h" #include #include "debug/debug.h" #include "include/zcall.h" #include "loader/elf_loader.h" #include "scheduler/process.h" #include "scheduler/process_manager.h" #include "scheduler/scheduler.h" #define EFER 0xC0000080 #define STAR 0xC0000081 #define LSTAR 0xC0000082 namespace { uint64_t GetMSR(uint32_t msr) { uint32_t lo, hi; asm("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); return (static_cast(hi) << 32) | lo; } void SetMSR(uint32_t msr, uint64_t val) { uint32_t lo = static_cast(val); uint32_t hi = val >> 32; asm("wrmsr" ::"a"(lo), "d"(hi), "c"(msr)); } extern "C" void syscall_enter(); } // namespace // Used by syscall_enter.s extern "C" uint64_t GetKernelRsp() { return gScheduler->CurrentThread().Rsp0Start(); } void InitSyscall() { uint64_t efer_val = GetMSR(EFER); efer_val |= 1; SetMSR(EFER, efer_val); if (GetMSR(EFER) != efer_val) { panic("Failed to set EFER MSR"); } uint64_t star_val = GetMSR(STAR); // FIXME: Fix GDT such that we can properly set the user CS. // Due to the ability to jump from a 64 bit kernel into compatibility mode, // we set the user_cs to the kernel_cs because it adds 16 to jump to 64-bit // mode. See AMD Manual 3.4 instruction SYSRET for more info. uint64_t kernel_cs = 0x8; uint64_t user_cs = kernel_cs; star_val |= (kernel_cs << 32) | (user_cs << 48); SetMSR(STAR, star_val); SetMSR(LSTAR, reinterpret_cast(syscall_enter)); } uint64_t ProcessSpawn(ZProcessSpawnReq* req) { dbgln("Proc spawn: %u:%u", req->elf_base, req->elf_size); SharedPtr proc = MakeShared(); gProcMan->InsertProcess(proc); uint64_t entry = LoadElfProgram(*proc, req->elf_base, req->elf_size); proc->CreateThread(entry); return 0; } extern "C" uint64_t SyscallHandler(uint64_t call_id, char* message) { Thread& thread = gScheduler->CurrentThread(); switch (call_id) { case Z_THREAD_EXIT: thread.Exit(); panic("Returned from thread exit"); break; case Z_DEBUG_PRINT: dbgln("[Debug] %s", message); break; case Z_PROCESS_SPAWN: return ProcessSpawn(reinterpret_cast(message)); default: panic("Unhandled syscall number: %u", call_id); } return 1; }