Wireframe for syscalls in place
This commit is contained in:
parent
d3024211a7
commit
f86bbe6ea9
|
@ -12,6 +12,8 @@ add_executable(zion
|
||||||
scheduler/process.cpp
|
scheduler/process.cpp
|
||||||
scheduler/scheduler.cpp
|
scheduler/scheduler.cpp
|
||||||
scheduler/thread.cpp
|
scheduler/thread.cpp
|
||||||
|
syscall/syscall.cpp
|
||||||
|
syscall/syscall_enter.s
|
||||||
zion.cpp)
|
zion.cpp)
|
||||||
|
|
||||||
target_include_directories(zion
|
target_include_directories(zion
|
||||||
|
|
|
@ -28,6 +28,7 @@ Thread::Thread(Process* proc, uint64_t tid) : process_(proc), id_(tid) {
|
||||||
// 16: cr3
|
// 16: cr3
|
||||||
*(stack_ptr - 16) = proc->cr3();
|
*(stack_ptr - 16) = proc->cr3();
|
||||||
rsp0_ = reinterpret_cast<uint64_t>(stack_ptr - 16);
|
rsp0_ = reinterpret_cast<uint64_t>(stack_ptr - 16);
|
||||||
|
rsp0_start_ = reinterpret_cast<uint64_t>(stack_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Thread::pid() { return process_->id(); }
|
uint64_t Thread::pid() { return process_->id(); }
|
||||||
|
|
|
@ -17,6 +17,7 @@ class Thread {
|
||||||
Process& process() { return *process_; }
|
Process& process() { return *process_; }
|
||||||
|
|
||||||
uint64_t* Rsp0Ptr() { return &rsp0_; }
|
uint64_t* Rsp0Ptr() { return &rsp0_; }
|
||||||
|
uint64_t Rsp0Start() { return rsp0_start_; }
|
||||||
|
|
||||||
// Called the first time the thread starts up.
|
// Called the first time the thread starts up.
|
||||||
void Init();
|
void Init();
|
||||||
|
@ -33,4 +34,7 @@ class Thread {
|
||||||
// Stack pointer to take on resume.
|
// Stack pointer to take on resume.
|
||||||
// Stack will contain the full thread context.
|
// Stack will contain the full thread context.
|
||||||
uint64_t rsp0_;
|
uint64_t rsp0_;
|
||||||
|
// Stack pointer to take when returning from userspace.
|
||||||
|
// I don't think me mind clobbering the stack here.
|
||||||
|
uint64_t rsp0_start_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "syscall/syscall.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "debug/debug.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<uint64_t>(hi) << 32) | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMSR(uint32_t msr, uint64_t val) {
|
||||||
|
uint32_t lo = static_cast<uint32_t>(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 sched::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<uint64_t>(syscall_enter));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void SyscallHandler(uint64_t call_id, char* message) {
|
||||||
|
dbgln(message);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void InitSyscall();
|
|
@ -0,0 +1,60 @@
|
||||||
|
.global syscall_enter
|
||||||
|
syscall_enter:
|
||||||
|
# Technically don't need to save all of these as
|
||||||
|
# the SYS V ABI will preserve some of them by
|
||||||
|
# default but I doubt that this costs us much.
|
||||||
|
push %rbx
|
||||||
|
push %rcx # Special! This is the return address
|
||||||
|
push %rdx
|
||||||
|
push %rsi
|
||||||
|
push %rdi
|
||||||
|
push %r8
|
||||||
|
push %r9
|
||||||
|
push %r10
|
||||||
|
push %r11
|
||||||
|
push %r12
|
||||||
|
push %r13
|
||||||
|
push %r14
|
||||||
|
push %r15
|
||||||
|
|
||||||
|
call GetKernelRsp
|
||||||
|
|
||||||
|
# RAX holds the kernel RSP now.
|
||||||
|
mov %rsp, %rbx
|
||||||
|
mov %rax, %rsp
|
||||||
|
push %rbx
|
||||||
|
|
||||||
|
# Now that we are on the kernel stack we can re-enable interrupts.
|
||||||
|
sti
|
||||||
|
|
||||||
|
# Restore caller registers using the userspace rsp in rbx
|
||||||
|
mov 0x40(%rbx), %rdi
|
||||||
|
mov 0x48(%rbx), %rsi
|
||||||
|
mov 0x50(%rbx), %rdx
|
||||||
|
mov 0x58(%rbx), %rcx
|
||||||
|
# Don't push the rbp and rsp as the callee will do so.
|
||||||
|
call SyscallHandler
|
||||||
|
|
||||||
|
# Clear interrupts since we are moving back to the user stack here.
|
||||||
|
# The sysret call will re-enable them for us.
|
||||||
|
cli
|
||||||
|
|
||||||
|
# Pop the userspace rsp off the stack
|
||||||
|
pop %rsp
|
||||||
|
|
||||||
|
pop %r15
|
||||||
|
pop %r14
|
||||||
|
pop %r13
|
||||||
|
pop %r12
|
||||||
|
pop %r11 # Contains rflags.
|
||||||
|
pop %r10
|
||||||
|
pop %r9
|
||||||
|
pop %r8
|
||||||
|
pop %rdi
|
||||||
|
pop %rsi
|
||||||
|
pop %rdx
|
||||||
|
pop %rcx # Contains return address.
|
||||||
|
pop %rbx
|
||||||
|
# Because we haven't touched rax since calling syscall_handler it should still have the return value.
|
||||||
|
sysretq
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "memory/paging_util.h"
|
#include "memory/paging_util.h"
|
||||||
#include "memory/physical_memory.h"
|
#include "memory/physical_memory.h"
|
||||||
#include "scheduler/scheduler.h"
|
#include "scheduler/scheduler.h"
|
||||||
|
#include "syscall/syscall.h"
|
||||||
|
|
||||||
extern "C" void zion() {
|
extern "C" void zion() {
|
||||||
InitGdt();
|
InitGdt();
|
||||||
|
@ -17,6 +18,8 @@ extern "C" void zion() {
|
||||||
KernelHeap heap(0xFFFFFFFF'40000000, 0xFFFFFFFF'80000000);
|
KernelHeap heap(0xFFFFFFFF'40000000, 0xFFFFFFFF'80000000);
|
||||||
phys_mem::InitPhysicalMemoryManager();
|
phys_mem::InitPhysicalMemoryManager();
|
||||||
|
|
||||||
|
InitSyscall();
|
||||||
|
|
||||||
sched::InitScheduler();
|
sched::InitScheduler();
|
||||||
Process p1;
|
Process p1;
|
||||||
p1.CreateThread();
|
p1.CreateThread();
|
||||||
|
|
Loading…
Reference in New Issue