pvmfw: Issue MMIO_GUARD_MAP for UART

Share the MMIO page containing the UART with the VMM.

When handling a synchronous exception, don't print to the UART if it
would cause re-entering the handler.

Bug: 237371962
Test: m pvmfw_img && flash pvmfw.img && access UART
Change-Id: Ia384f2e3a15b40b5e67cfafd50e571848fd5a126
diff --git a/pvmfw/src/exceptions.rs b/pvmfw/src/exceptions.rs
index 596ecc7..0fb2911 100644
--- a/pvmfw/src/exceptions.rs
+++ b/pvmfw/src/exceptions.rs
@@ -14,14 +14,23 @@
 
 //! Exception handlers.
 
+use crate::helpers::page_4kb_of;
 use core::arch::asm;
+use vmbase::console;
 use vmbase::{console::emergency_write_str, eprintln, power::reboot};
 
+const ESR_32BIT_EXT_DABT: u64 = 0x96000010;
+const UART_PAGE: u64 = page_4kb_of(console::BASE_ADDRESS as u64);
+
 #[no_mangle]
 extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
     let esr = read_esr();
-    emergency_write_str("sync_exception_current\n");
-    print_esr(esr);
+    let far = read_far();
+    // Don't print to the UART if we're handling the exception it could raise.
+    if esr != ESR_32BIT_EXT_DABT || page_4kb_of(far) != UART_PAGE {
+        emergency_write_str("sync_exception_current\n");
+        print_esr(esr);
+    }
     reboot();
 }
 
@@ -86,3 +95,12 @@
 fn print_esr(esr: u64) {
     eprintln!("esr={:#08x}", esr);
 }
+
+#[inline]
+fn read_far() -> u64 {
+    let mut far: u64;
+    unsafe {
+        asm!("mrs {far}, far_el1", far = out(reg) far);
+    }
+    far
+}