Unify Interrupt{,Error}Stack.
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user