[pvmfw] Extract EL1 exception register read into a function
This cl extracts the EL1 exception register reading code into
a separate function for better readability and maintainability.
The extracted function will be moved to vmbase for reuse in
rialto and pvmfw in a subsequent cl.
Test: m pvmfw_img
Change-Id: I492c3f0006fa67e794fb3ba1a103adc5635cf56d
diff --git a/pvmfw/src/exceptions.rs b/pvmfw/src/exceptions.rs
index 797138c..09994ba 100644
--- a/pvmfw/src/exceptions.rs
+++ b/pvmfw/src/exceptions.rs
@@ -103,32 +103,53 @@
Ok(memory.handle_permission_fault(far)?)
}
-fn handle_exception(esr: Esr, far: usize) -> Result<(), HandleExceptionError> {
+fn handle_exception(exception: &ArmException) -> Result<(), HandleExceptionError> {
// Handle all translation faults on both read and write, and MMIO guard map
// flagged invalid pages or blocks that caused the exception.
// Handle permission faults for DBM flagged entries, and flag them as dirty on write.
- match esr {
- Esr::DataAbortTranslationFault => handle_translation_fault(far),
- Esr::DataAbortPermissionFault => handle_permission_fault(far),
+ match exception.esr {
+ Esr::DataAbortTranslationFault => handle_translation_fault(exception.far),
+ Esr::DataAbortPermissionFault => handle_permission_fault(exception.far),
_ => Err(HandleExceptionError::UnknownException),
}
}
-/// Prints the details of an exception failure, excluding UART exceptions.
-#[inline]
-fn print_exception_failure(
+/// A struct representing an Armv8 exception.
+struct ArmException {
+ /// The value of the exception syndrome register.
esr: Esr,
+ /// The value of the fault address register.
far: usize,
- elr: u64,
- e: HandleExceptionError,
- exception_name: &str,
-) {
- let is_uart_exception = esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE;
- // Don't print to the UART if we are handling an exception it could raise.
- if !is_uart_exception {
- eprintln!("{exception_name}");
- eprintln!("{e}");
- eprintln!("{esr}, far={far:#08x}, elr={elr:#08x}");
+}
+
+impl fmt::Display for ArmException {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ArmException: esr={}, far={:#08x}", self.esr, self.far)
+ }
+}
+
+impl ArmException {
+ /// Reads the values of the EL1 exception syndrome register (`esr_el1`)
+ /// and fault address register (`far_el1`) and returns a new instance of
+ /// `ArmException` with these values.
+ fn from_el1_regs() -> Self {
+ let esr: Esr = read_sysreg!("esr_el1").into();
+ let far = read_sysreg!("far_el1");
+ Self { esr, far }
+ }
+
+ /// Prints the details of an obj and the exception, excluding UART exceptions.
+ fn print<T: fmt::Display>(&self, exception_name: &str, obj: T, elr: u64) {
+ // Don't print to the UART if we are handling an exception it could raise.
+ if !self.is_uart_exception() {
+ eprintln!("{exception_name}");
+ eprintln!("{obj}");
+ eprintln!("{}, elr={:#08x}", self, elr);
+ }
+ }
+
+ fn is_uart_exception(&self) -> bool {
+ self.esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(self.far) == UART_PAGE
}
}
@@ -136,11 +157,10 @@
extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
// Disable logging in exception handler to prevent unsafe writes to UART.
let _guard = logger::suppress();
- let esr: Esr = read_sysreg!("esr_el1").into();
- let far = read_sysreg!("far_el1");
- if let Err(e) = handle_exception(esr, far) {
- print_exception_failure(esr, far, elr, e, "sync_exception_current");
+ let exception = ArmException::from_el1_regs();
+ if let Err(e) = handle_exception(&exception) {
+ exception.print("sync_exception_current", e, elr);
reboot()
}
}