From eeb0d8c1e6f5821f09232fd609f33ad5ae9850bc Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 20 May 2023 11:31:16 +0200 Subject: [PATCH] Unify Interrupt{,Error}Stack. --- src/arch/x86_64/interrupt/exception.rs | 20 ++++---- src/arch/x86_64/interrupt/handler.rs | 64 +++++++++----------------- 2 files changed, 33 insertions(+), 51 deletions(-) diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index 1b06efc5..ace4c5a7 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -99,44 +99,44 @@ interrupt_stack!(device_not_available, |stack| { ksignal(SIGILL); }); -interrupt_error!(double_fault, |stack| { +interrupt_error!(double_fault, |stack, _code| { println!("Double fault"); stack.dump(); stack_trace(); ksignal(SIGSEGV); }); -interrupt_error!(invalid_tss, |stack| { +interrupt_error!(invalid_tss, |stack, _code| { println!("Invalid TSS fault"); stack.dump(); stack_trace(); ksignal(SIGSEGV); }); -interrupt_error!(segment_not_present, |stack| { +interrupt_error!(segment_not_present, |stack, _code| { println!("Segment not present fault"); stack.dump(); stack_trace(); ksignal(SIGSEGV); }); -interrupt_error!(stack_segment, |stack| { +interrupt_error!(stack_segment, |stack, _code| { println!("Stack segment fault"); stack.dump(); stack_trace(); ksignal(SIGSEGV); }); -interrupt_error!(protection, |stack| { +interrupt_error!(protection, |stack, _code| { println!("Protection fault"); stack.dump(); stack_trace(); ksignal(SIGSEGV); }); -interrupt_error!(page, |stack| { +interrupt_error!(page, |stack, code| { let cr2 = VirtualAddress::new(unsafe { x86::controlregs::cr2() }); - let arch_flags = PageFaultError::from_bits_truncate(stack.code as u32); + let arch_flags = PageFaultError::from_bits_truncate(code as u32); let mut generic_flags = GenericPfFlags::empty(); generic_flags.set(GenericPfFlags::PRESENT, arch_flags.contains(PageFaultError::P)); @@ -145,7 +145,7 @@ interrupt_error!(page, |stack| { generic_flags.set(GenericPfFlags::INVL, arch_flags.contains(PageFaultError::RSVD)); generic_flags.set(GenericPfFlags::INSTR_NOT_DATA, arch_flags.contains(PageFaultError::ID)); - if crate::memory::page_fault_handler(&mut stack.inner, generic_flags, cr2).is_err() { + if crate::memory::page_fault_handler(stack, generic_flags, cr2).is_err() { println!("Page fault: {:>016X} {:#?}", cr2.data(), arch_flags); stack.dump(); stack_trace(); @@ -160,7 +160,7 @@ interrupt_stack!(fpu_fault, |stack| { ksignal(SIGFPE); }); -interrupt_error!(alignment_check, |stack| { +interrupt_error!(alignment_check, |stack, _code| { println!("Alignment check fault"); stack.dump(); stack_trace(); @@ -188,7 +188,7 @@ interrupt_stack!(virtualization, |stack| { ksignal(SIGBUS); }); -interrupt_error!(security, |stack| { +interrupt_error!(security, |stack, _code| { println!("Security exception"); stack.dump(); stack_trace(); diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index 1af333b0..98cfe73c 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -62,13 +62,12 @@ pub struct IretRegisters { pub cs: usize, pub rflags: usize, - // ---- - // The following will only be present if interrupt is raised from another - // privilege ring. Otherwise, they are undefined values. - // ---- + // In x86 Protected Mode, i.e. 32-bit kernels, the following two registers are conditionally + // pushed if the privilege ring changes. In x86 Long Mode however, i.e. 64-bit kernels, they + // are unconditionally pushed, mostly due to stack alignment requirements. pub rsp: usize, - pub ss: usize + pub ss: usize, } impl IretRegisters { @@ -77,10 +76,9 @@ impl IretRegisters { println!("CS: {:016x}", { self.cs }); println!("RIP: {:016x}", { self.rip }); - if self.cs & 0b11 != 0b00 { - println!("RSP: {:016x}", { self.rsp }); - println!("SS: {:016x}", { self.ss }); - } + println!("RSP: {:016x}", { self.rsp }); + println!("SS: {:016x}", { self.ss }); + unsafe { let fsbase = x86::msr::rdmsr(x86::msr::IA32_FS_BASE); let gsbase = x86::msr::rdmsr(x86::msr::IA32_KERNEL_GSBASE); @@ -190,20 +188,6 @@ impl InterruptStack { } } -#[derive(Default)] -#[repr(packed)] -pub struct InterruptErrorStack { - pub code: usize, - pub inner: InterruptStack, -} - -impl InterruptErrorStack { - pub fn dump(&self) { - println!("CODE: {:016x}", { self.code }); - self.inner.dump(); - } -} - #[macro_export] macro_rules! push_scratch { () => { " @@ -482,10 +466,10 @@ macro_rules! interrupt { #[macro_export] macro_rules! interrupt_error { - ($name:ident, |$stack:ident| $code:block) => { + ($name:ident, |$stack:ident, $error_code:ident| $code:block) => { #[naked] pub unsafe extern "C" fn $name() { - unsafe extern "C" fn inner($stack: &mut $crate::arch::x86_64::interrupt::handler::InterruptErrorStack) { + unsafe extern "C" fn inner($stack: &mut $crate::arch::x86_64::interrupt::handler::InterruptStack, $error_code: usize) { let _guard; // Only set_ptrace_process_regs if this error occured from userspace. If this fault @@ -495,8 +479,8 @@ macro_rules! interrupt_error { // anyway). // // Check the privilege level of CS against ring 3. - if $stack.inner.iret.cs & 0b11 == 0b11 { - _guard = $crate::ptrace::set_process_regs(&mut $stack.inner); + if $stack.iret.cs & 0b11 == 0b11 { + _guard = $crate::ptrace::set_process_regs($stack); } #[allow(unused_unsafe)] @@ -510,42 +494,40 @@ macro_rules! interrupt_error { "cld;", swapgs_iff_ring3_fast_errorcode!(), - // Move rax into code's place, put code in last instead (to be - // compatible with InterruptStack) - "xchg [rsp], rax\n", + + // Don't push RAX yet, as the error code is already stored in RAX's position. // Push all userspace registers push_scratch!(), push_preserved!(), - // Put code in, it's now in rax - "push rax\n", + // Now that we have a couple of usable registers, put the error code in the second + // argument register for the inner function, and save RAX where it would normally + // be. + "mov rsi, [rsp + {rax_offset}];", + "mov [rsp + {rax_offset}], rax;", // TODO: Map PTI // $crate::arch::x86_64::pti::map(); - // Call inner function with pointer to stack - " - mov rdi, rsp - call {inner} - ", + // Call inner function with pointer to stack, and error code. + "mov rdi, rsp;", + "call {inner};", // TODO: Unmap PTI // $crate::arch::x86_64::pti::unmap(); - // Pop code - "add rsp, 8\n", - // Restore all userspace registers pop_preserved!(), pop_scratch!(), // The error code has already been popped, so use the regular macro. swapgs_iff_ring3_fast!(), - "iretq\n", + "iretq;", ), inner = sym inner, + rax_offset = const(::core::mem::size_of::<$crate::interrupt::handler::PreservedRegisters>() + ::core::mem::size_of::<$crate::interrupt::handler::ScratchRegisters>() - 8), options(noreturn)); } -- GitLab