pvmfw: Optimize MMIO guard map

Optimize MMIO guard mapping device pages by mapping the pages as invalid
in order to produce translation faults. When a translation fault
happens, re-enable the pages and only then MMIO guard map the pages.

Bug: 245267332
Test: atest MicrodroidTestApp

Change-Id: I81128d7efec1249a9a7da988ec098b29936338ef
diff --git a/pvmfw/src/exceptions.rs b/pvmfw/src/exceptions.rs
index a6ac4fe..39641b0 100644
--- a/pvmfw/src/exceptions.rs
+++ b/pvmfw/src/exceptions.rs
@@ -14,6 +14,7 @@
 
 //! Exception handlers.
 
+use crate::memory::{MemoryTrackerError, MEMORY};
 use crate::{helpers::page_4kb_of, read_sysreg};
 use core::fmt;
 use vmbase::console;
@@ -24,12 +25,24 @@
 
 #[derive(Debug)]
 enum HandleExceptionError {
+    PageTableUnavailable,
+    PageTableNotInitialized,
+    InternalError(MemoryTrackerError),
     UnknownException,
 }
 
+impl From<MemoryTrackerError> for HandleExceptionError {
+    fn from(other: MemoryTrackerError) -> Self {
+        Self::InternalError(other)
+    }
+}
+
 impl fmt::Display for HandleExceptionError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
+            Self::PageTableUnavailable => write!(f, "Page table is not available."),
+            Self::PageTableNotInitialized => write!(f, "Page table is not initialized."),
+            Self::InternalError(e) => write!(f, "Error while updating page table: {e}"),
             Self::UnknownException => write!(f, "An unknown exception occurred, not handled."),
         }
     }
@@ -76,8 +89,17 @@
     }
 }
 
-fn handle_exception(_esr: Esr, _far: usize) -> Result<(), HandleExceptionError> {
-    Err(HandleExceptionError::UnknownException)
+fn handle_exception(esr: Esr, far: usize) -> Result<(), HandleExceptionError> {
+    // Handle all translation faults on both read and write, and MMIO guard map
+    // flagged invalid pages or blocks that caused the exception.
+    match esr {
+        Esr::DataAbortTranslationFault => {
+            let mut locked = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
+            let memory = locked.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
+            Ok(memory.handle_mmio_fault(far)?)
+        }
+        _ => Err(HandleExceptionError::UnknownException),
+    }
 }
 
 #[inline]