Unify Interrupt{,Error}Stack.

This commit is contained in:
4lDO2
2023-05-20 11:31:16 +02:00
parent c4a5abb34a
commit eeb0d8c1e6
2 changed files with 33 additions and 51 deletions
+10 -10
View File
@@ -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();
+23 -41
View File
@@ -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));
}