diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs index f7f99ac220b2903d1333b21bec1a98b6c89c3caf..2f1247e5d70f31c21dcd9ad75a1893bb043f7cba 100644 --- a/src/arch/x86_64/interrupt/syscall.rs +++ b/src/arch/x86_64/interrupt/syscall.rs @@ -1,5 +1,90 @@ -use arch::x86_64::pti; +use arch::{gdt, pti}; use syscall; +use x86::shared::msr; + +pub unsafe fn init() { + msr::wrmsr(msr::IA32_STAR, ((gdt::GDT_KERNEL_CODE as u64) << 3) << 32); + msr::wrmsr(msr::IA32_LSTAR, syscall_instruction as u64); + msr::wrmsr(msr::IA32_FMASK, 1 << 9); + msr::wrmsr(msr::IA32_KERNEL_GS_BASE, &gdt::TSS as *const _ as u64); + + let efer = msr::rdmsr(msr::IA32_EFER); + msr::wrmsr(msr::IA32_EFER, efer | 1); +} + +#[naked] +pub unsafe extern fn syscall_instruction() { + #[inline(never)] + unsafe fn inner(stack: &mut SyscallStack) -> usize { + let rbp; + asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); + + syscall::syscall(stack.rax, stack.rdi, stack.rsi, stack.rdx, stack.r10, stack.r8, rbp, stack) + } + + // Yes, this is magic. No, you don't need to understand + asm!("xchg bx, bx + swapgs // Set gs segment to TSS + mov gs:[28], rsp // Save userspace rsp + mov rsp, gs:[4] // Load kernel rsp + push 5 * 8 + 3 // Push userspace data segment + push qword ptr gs:[28] // Push userspace rsp + mov qword ptr gs:[28], 0 // Clear userspace rsp + push r11 // Push rflags + push 4 * 8 + 3 // Push userspace code segment + push rcx // Push userspace return pointer + swapgs // Restore gs + " + : + : + : + : "intel", "volatile"); + + // Push scratch registers + asm!("push rax + push rbx + push rcx + push rdx + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + push fs + mov r11, 0x18 + mov fs, r11" + : : : : "intel", "volatile"); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel + pti::map(); + + let a = inner(&mut *(rsp as *mut SyscallStack)); + + // Unmap kernel + pti::unmap(); + + asm!("" : : "{rax}"(a) : : "intel", "volatile"); + + // Interrupt return + asm!("pop fs + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rdx + pop rcx + pop rbx + add rsp, 8 + iretq" + : : : : "intel", "volatile"); +} #[naked] pub unsafe extern fn syscall() { diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index 81b12bb3bff77651943ad50a3c36a227c2851fc6..46151703ffc8b590f8df43dc8cb9e1b140a12b0a 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -90,6 +90,9 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Set up IDT idt::init_paging(); + // Set up syscall instruction + interrupt::syscall::init(); + // Test tdata and tbss { assert_eq!(TBSS_TEST_ZERO, 0);