From 0226390b212defdd352ae0aa093e7bbd5c878b78 Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Tue, 20 Dec 2022 19:03:10 +0100 Subject: [PATCH] Kernel/aarch64: Add Fault Address Register (FAR_EL1) And use it for printing the virtual address when an exception has happened that set the register, such as data aborts and instruction aborts. --- Kernel/Arch/aarch64/Registers.h | 37 +++++++++++++++++++++++++++++++++ Kernel/Arch/aarch64/init.cpp | 2 ++ 2 files changed, 39 insertions(+) diff --git a/Kernel/Arch/aarch64/Registers.h b/Kernel/Arch/aarch64/Registers.h index ab8ffca43c..84337b62fe 100644 --- a/Kernel/Arch/aarch64/Registers.h +++ b/Kernel/Arch/aarch64/Registers.h @@ -488,6 +488,22 @@ struct ESR_EL1 { }; static_assert(sizeof(ESR_EL1) == 8); +// D17.2.40 FAR_EL1, Fault Address Register (EL1) +struct FAR_EL1 { + u64 virtual_address; + + static inline FAR_EL1 read() + { + FAR_EL1 far_el1; + + asm("mrs %[value], far_el1" + : [value] "=r"(far_el1)); + + return far_el1; + } +}; +static_assert(sizeof(FAR_EL1) == 8); + // D17.2.37 ESR_EL1, Exception Syndrome Register (EL1) static inline StringView exception_class_to_string(u8 exception_class) { @@ -571,6 +587,27 @@ static inline StringView exception_class_to_string(u8 exception_class) } } +// D17.2.40 FAR_EL1, Fault Address Register (EL1) +static inline bool exception_class_has_set_far(u8 exception_class) +{ + // Faulting Virtual Address for synchronous exceptions taken to EL1. Exceptions that set the + // FAR_EL1 are Instruction Aborts (EC 0x20 or 0x21), Data Aborts (EC 0x24 or 0x25), PC alignment + // faults (EC 0x22), and Watchpoints (EC 0x34 or 0x35). ESR_EL1.EC holds the EC value for the + // exception. + switch (exception_class) { + case 0x20: + case 0x21: + case 0x22: + case 0x24: + case 0x25: + case 0x34: + case 0x35: + return true; + default: + return false; + } +} + // https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/DAIF--Interrupt-Mask-Bits?lang=en // DAIF, Interrupt Mask Bits struct DAIF { diff --git a/Kernel/Arch/aarch64/init.cpp b/Kernel/Arch/aarch64/init.cpp index f5c16a30b7..a7a477c50c 100644 --- a/Kernel/Arch/aarch64/init.cpp +++ b/Kernel/Arch/aarch64/init.cpp @@ -52,6 +52,8 @@ extern "C" void exception_common(Kernel::TrapFrame const* const trap_frame) auto esr_el1 = Kernel::Aarch64::ESR_EL1::read(); dbgln("esr_el1: EC({:#b}) IL({:#b}) ISS({:#b}) ISS2({:#b})", esr_el1.EC, esr_el1.IL, esr_el1.ISS, esr_el1.ISS2); dbgln("Exception Class: {}", Aarch64::exception_class_to_string(esr_el1.EC)); + if (Aarch64::exception_class_has_set_far(esr_el1.EC)) + dbgln("Faulting Virtual Address: 0x{:x}", Aarch64::FAR_EL1::read().virtual_address); dump_backtrace_from_base_pointer(regs->x[29]); }