diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index 5e974c3db628b16d9090e636ad76cf506c8577fe..b55db056a0f89fd79c44ebdda3aac0e1bd82067e 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -78,9 +78,6 @@ pub static mut GDT: [GdtEntry; 10] = [ #[repr(C, align(16))] pub struct ProcessorControlRegion { - // NOTE: If you plan to change any fields here, please make sure that you also modify the - // offsets in the syscall instruction handler accordingly! - pub tcb_end: usize, pub user_rsp_tmp: usize, pub tss: TssWrapper, diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index 58ee4dd7d0bad535af5f071810377df9e8240597..4cf27e87dab3952a5da70607f0bdf690420ac8d1 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -203,34 +203,6 @@ impl InterruptErrorStack { } } -#[macro_export] -macro_rules! intel_asm { - ($($strings:expr,)+) => { - global_asm!(concat!( - $($strings),+, - )); - }; -} -#[macro_export] -macro_rules! function { - ($name:ident => { $($body:expr,)+ }) => { - intel_asm!( - ".global ", stringify!($name), "\n", - ".type ", stringify!($name), ", @function\n", - ".section .text.", stringify!($name), ", \"ax\", @progbits\n", - // Align the function to a 16-byte boundary, padding with multi-byte NOPs. - ".p2align 4,,15\n", - stringify!($name), ":\n", - $($body),+, - ".size ", stringify!($name), ", . - ", stringify!($name), "\n", - ".text\n", - ); - extern "C" { - pub fn $name(); - } - }; -} - #[macro_export] macro_rules! push_scratch { () => { " diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs index 3fbc49ac41e1a5ef343317b4b079e0c60e5de0f8..38c78c23033cb8b71a94ddce3c1df7fed4252cc0 100644 --- a/src/arch/x86_64/interrupt/syscall.rs +++ b/src/arch/x86_64/interrupt/syscall.rs @@ -5,7 +5,8 @@ use crate::{ syscall, syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL}, }; -use x86::msr; +use memoffset::offset_of; +use x86::{bits64::task::TaskStateSegment, msr, segmentation::SegmentSelector}; pub unsafe fn init() { // IA32_STAR[31:0] are reserved. @@ -58,16 +59,18 @@ pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack) }); } -function!(syscall_instruction => { +#[naked] +pub unsafe extern "C" fn syscall_instruction() { + asm!(concat!( // Yes, this is magic. No, you don't need to understand " swapgs // Set gs segment to TSS - mov gs:[0x08], rsp // Save userspace stack pointer - mov rsp, gs:[0x14] // Load kernel stack pointer - push QWORD PTR 5 * 8 + 3 // Push fake userspace SS (resembling iret frame) - push QWORD PTR gs:[0x08] // Push userspace rsp + mov gs:[{sp}], rsp // Save userspace stack pointer + mov rsp, gs:[{ksp}] // Load kernel stack pointer + push QWORD PTR {ss_sel} // Push fake userspace SS (resembling iret frame) + push QWORD PTR gs:[{sp}] // Push userspace rsp push r11 // Push rflags - push QWORD PTR 6 * 8 + 3 // Push fake CS (resembling iret stack frame) + push QWORD PTR {cs_sel} // Push fake CS (resembling iret stack frame) push rcx // Push userspace return pointer ", @@ -113,8 +116,8 @@ function!(syscall_instruction => { pop rcx // Pop userspace return pointer add rsp, 8 // Pop fake userspace CS pop r11 // Pop rflags - pop QWORD PTR gs:[0x08] // Pop userspace stack pointer - mov rsp, gs:[0x08] // Restore userspace stack pointer + pop QWORD PTR gs:[{sp}] // Pop userspace stack pointer + mov rsp, gs:[{sp}] // Restore userspace stack pointer swapgs // Restore gs from TSS to user data sysretq // Return into userspace; RCX=>RIP,R11=>RFLAGS @@ -125,8 +128,16 @@ function!(syscall_instruction => { xor r11, r11 swapgs iretq - ", -}); + "), + + sp = const(offset_of!(gdt::ProcessorControlRegion, user_rsp_tmp)), + ksp = const(offset_of!(gdt::ProcessorControlRegion, tss) + offset_of!(TaskStateSegment, rsp)), + ss_sel = const(SegmentSelector::new(gdt::GDT_USER_DATA as u16, x86::Ring::Ring3).bits()), + cs_sel = const(SegmentSelector::new(gdt::GDT_USER_CODE as u16, x86::Ring::Ring3).bits()), + + options(noreturn), + ); +} interrupt_stack!(syscall, |stack| { with_interrupt_stack!(|stack| { @@ -150,7 +161,9 @@ interrupt_stack!(syscall, |stack| { }) }); -function!(clone_ret => { +#[naked] +pub unsafe extern "C" fn clone_ret() { + asm!(concat!( // The address of this instruction is injected by `clone` in process.rs, on // top of the stack syscall->inner in this file, which is done using the rbp // register we save there. @@ -165,4 +178,5 @@ function!(clone_ret => { "pop rbp\n", // ...and we return to the address at the top of the stack "ret\n", -}); + ), options(noreturn)); +}