From c913c3be804fb77625069a0e6cd8dbdde0bc3df6 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 8 Feb 2021 08:44:48 +0100 Subject: [PATCH] Use sysretq in usermode(). --- src/arch/x86_64/start.rs | 95 +++++++++++++++++++++++++--------------- src/context/signal.rs | 2 +- src/syscall/process.rs | 2 +- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index 7f28eaa..24874d8 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -240,13 +240,10 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { } #[naked] -pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, singlestep: bool) -> ! { - let mut flags = FLAG_INTERRUPTS; - if singlestep { - flags |= FLAG_SINGLESTEP; - } - - asm!("push r10 +#[inline(never)] +// TODO: AbiCompatBool +pub unsafe extern "C" fn usermode(_ip: usize, _sp: usize, _arg: usize, _singlestep: u32) -> ! { + /*asm!("push r10 push r11 push r12 push r13 @@ -258,36 +255,62 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, singlestep: bool) -> ! in("r13") (gdt::GDT_USER_CODE << 3 | 3), // Code segment in("r14") ip, // IP in("r15") arg, // Argument - ); + );*/ + // rdi, rsi, rdx, rcx + asm!( + " + mov rbx, {flag_interrupts} + test ecx, ecx + jz .after_singlestep_branch + or rbx, {flag_singlestep} - // Unmap kernel - pti::unmap(); + .after_singlestep_branch: + mov r12, rdi + mov r13, rsi + mov rdi, rdx + call {pti_unmap} - // Go to usermode - asm!("mov ds, r14d - mov es, r14d - mov fs, r15d - mov gs, r14d - xor rax, rax - xor rbx, rbx - xor rcx, rcx - xor rdx, rdx - xor rsi, rsi - xor rdi, rdi - xor rbp, rbp - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r11, r11 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - fninit - pop rdi - iretq", - in("r14") (gdt::GDT_USER_DATA << 3 | 3), // Data segment - in("r15") (gdt::GDT_USER_TLS << 3 | 3), // TLS segment - options(noreturn), + // Go to usermode + mov r14, {user_data_seg_selector} + mov r15, {user_tls_seg_selector} + mov ds, r14d + mov es, r14d + mov fs, r15d + mov gs, r14d + + // Target RFLAGS + mov r11, rbx + // Target instruction pointer + mov rcx, r12 + // Target stack pointer + mov rsp, r13 + + xor rax, rax + xor rbx, rbx + // Don't zero rcx; it's used for `ip`. + xor rdx, rdx + // Don't zero rdi; it's used for `arg`. + xor rsi, rsi + xor rbp, rbp + // Don't zero rsp, obviously. + xor r8, r8 + xor r9, r9 + xor r10, r10 + // Don't zero r11; it's used for `rflags`. + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + fninit + sysretq + ", + + flag_interrupts = const(FLAG_INTERRUPTS), + flag_singlestep = const(FLAG_SINGLESTEP), + pti_unmap = sym pti::unmap, + user_data_seg_selector = const(gdt::GDT_USER_DATA << 3 | 3), + user_tls_seg_selector = const(gdt::GDT_USER_TLS << 3 | 3), + options(noreturn), ); } diff --git a/src/context/signal.rs b/src/context/signal.rs index bc5add1..3fe1687 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -122,7 +122,7 @@ pub extern "C" fn signal_handler(sig: usize) { sp -= mem::size_of::(); *(sp as *mut usize) = restorer; - usermode(handler, sp, sig, singlestep); + usermode(handler, sp, sig, u32::from(singlestep)); } } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 995ead9..08d0407 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -845,7 +845,7 @@ fn fexec_noreturn( } // Go to usermode - unsafe { usermode(entry, sp, 0, singlestep) } + unsafe { usermode(entry, sp, 0, u32::from(singlestep)) } } pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option>, auxv: Option>) -> Result {