From d011cf1425bf8ea920baa48046a4397a49a92aac Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Sun, 9 Apr 2023 10:56:21 -0700 Subject: [PATCH] feat(x86_64): display page fault address in oopses (#420) Debugging page faults in Mycelium is currently a bit difficult, because the oops message doesn't display the virtual address at which the page fault occurred. We can fix this quite easily by reading the `cr2` control register, which contains the linear address of the page fault. --- hal-x86_64/src/control_regs.rs | 17 ++++++++++++++++- hal-x86_64/src/interrupt.rs | 2 +- src/arch/x86_64/interrupt.rs | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/hal-x86_64/src/control_regs.rs b/hal-x86_64/src/control_regs.rs index 6d68a208..67b200d9 100644 --- a/hal-x86_64/src/control_regs.rs +++ b/hal-x86_64/src/control_regs.rs @@ -1,4 +1,5 @@ use core::arch::asm; +use hal_core::VAddr; use mycelium_util::bits::bitfield; pub mod cr3 { @@ -15,7 +16,7 @@ pub mod cr3 { asm!("mov {0}, cr3", out(reg) val, options(readonly)); }; let addr = PAddr::from_u64(val); - tracing::debug!(?addr); + tracing::trace!(rax = ?addr, "mov rax, cr3"); let pml4_page = Page::starting_at_fixed(addr) .expect("PML4 physical addr not aligned! this is very bad"); (pml4_page, Flags(val)) @@ -236,6 +237,20 @@ impl Cr4 { } } +/// Control Register 2 (CR2) contains the Page Fault Linear Address (PFLA). +pub struct Cr2; + +impl Cr2 { + /// Returns the 32-bit Page Fault Linear Address (PFLA) stored in CR2. + pub fn read() -> VAddr { + let addr: u64; + unsafe { + asm!("mov {0}, cr2", out(reg) addr, options(readonly)); + }; + VAddr::from_u64(addr) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/hal-x86_64/src/interrupt.rs b/hal-x86_64/src/interrupt.rs index fdea4d21..876d2bec 100644 --- a/hal-x86_64/src/interrupt.rs +++ b/hal-x86_64/src/interrupt.rs @@ -269,7 +269,7 @@ impl<'a, T> hal_core::interrupt::Context for Context<'a, T> { impl<'a> ctx::PageFault for Context<'a, PageFaultCode> { fn fault_vaddr(&self) -> crate::VAddr { - unimplemented!("eliza") + crate::control_regs::Cr2::read() } fn debug_error_code(&self) -> &dyn fmt::Debug { diff --git a/src/arch/x86_64/interrupt.rs b/src/arch/x86_64/interrupt.rs index faf972a8..20f6776a 100644 --- a/src/arch/x86_64/interrupt.rs +++ b/src/arch/x86_64/interrupt.rs @@ -71,10 +71,12 @@ impl hal_core::interrupt::Handlers for InterruptHandlers { where C: interrupt::Context + hal_core::interrupt::ctx::PageFault, { + let fault_vaddr = cx.fault_vaddr(); + let code = cx.display_error_code(); oops(Oops::fault_with_details( &cx, "PAGE FAULT", - &format_args!("\n{}", cx.display_error_code()), + &format_args!("at {fault_vaddr:?}\n{code}"), )) }