hyp: Introduce HypervisorCap::MMIO_GUARD

Similarly to DYNAMIC_MEM_SHARE, introduce a capability that client code
can check before calling MMIO_GUARD functions. This will remove the need
to implement stubs in the backends due to client code unconditionally
calling the functions.

Note that KvmHypervisor currently covers both pKVM and non-protected KVM
and will therefore have HypervisorCap::MMIO_GUARD, for now. As the only
client code that makes use of MMIO_GUARD and is intended to run on both
pKVM and regular KVM, Rialto, already deals with the distinction, this
patch doesn't deal with differentiating between the two modes, which is
done in a following patch.

No functional change intended.

Test: atest DebugPolicyHostTests#testNoAdbInDebugPolicy_withDebugLevelNone_boots
Test: atest rialto_test vmbase_example.integration_test
Change-Id: If45d31e65b2407deaf4df16cd4d354ccd6bf4506
diff --git a/libs/hyp/src/hypervisor/common.rs b/libs/hyp/src/hypervisor/common.rs
index ec7d168..0982183 100644
--- a/libs/hyp/src/hypervisor/common.rs
+++ b/libs/hyp/src/hypervisor/common.rs
@@ -26,6 +26,8 @@
     pub struct HypervisorCap: u32 {
         /// Capability for guest to share its memory with host at runtime.
         const DYNAMIC_MEM_SHARE = 0b1;
+        /// The hypervisor expects MMIO ranges to be "mapped" by the guest before being accessed.
+        const MMIO_GUARD = 0b10;
     }
 }
 
diff --git a/libs/hyp/src/hypervisor/geniezone.rs b/libs/hyp/src/hypervisor/geniezone.rs
index 0741978..c69c258 100644
--- a/libs/hyp/src/hypervisor/geniezone.rs
+++ b/libs/hyp/src/hypervisor/geniezone.rs
@@ -40,7 +40,8 @@
     // and share the same identification along with guest VMs.
     // The previous uuid was removed due to duplication elsewhere.
     pub const UUID: Uuid = uuid!("7e134ed0-3b82-488d-8cee-69c19211dbe7");
-    const CAPABILITIES: HypervisorCap = HypervisorCap::DYNAMIC_MEM_SHARE;
+    const CAPABILITIES: HypervisorCap =
+        HypervisorCap::DYNAMIC_MEM_SHARE.union(HypervisorCap::MMIO_GUARD);
 }
 
 /// Error from a GenieZone HVC call.
diff --git a/libs/hyp/src/hypervisor/kvm.rs b/libs/hyp/src/hypervisor/kvm.rs
index a89f9b8..4243b5a 100644
--- a/libs/hyp/src/hypervisor/kvm.rs
+++ b/libs/hyp/src/hypervisor/kvm.rs
@@ -76,7 +76,8 @@
     // Based on ARM_SMCCC_VENDOR_HYP_UID_KVM_REG values listed in Linux kernel source:
     // https://github.com/torvalds/linux/blob/master/include/linux/arm-smccc.h
     pub(super) const UUID: Uuid = uuid!("28b46fb6-2ec5-11e9-a9ca-4b564d003a74");
-    const CAPABILITIES: HypervisorCap = HypervisorCap::DYNAMIC_MEM_SHARE;
+    const CAPABILITIES: HypervisorCap =
+        HypervisorCap::DYNAMIC_MEM_SHARE.union(HypervisorCap::MMIO_GUARD);
 }
 
 impl Hypervisor for KvmHypervisor {
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 3d2fea8..a35e945 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -197,15 +197,17 @@
     // Use debug!() to avoid printing to the UART if we failed to configure it as only local
     // builds that have tweaked the logger::init() call will actually attempt to log the message.
 
-    get_hypervisor().mmio_guard_init().map_err(|e| {
-        debug!("{e}");
-        RebootReason::InternalError
-    })?;
+    if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
+        get_hypervisor().mmio_guard_init().map_err(|e| {
+            debug!("{e}");
+            RebootReason::InternalError
+        })?;
 
-    get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
-        debug!("Failed to configure the UART: {e}");
-        RebootReason::InternalError
-    })?;
+        get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
+            debug!("Failed to configure the UART: {e}");
+            RebootReason::InternalError
+        })?;
+    }
 
     crypto::init();
 
@@ -253,10 +255,12 @@
     })?;
     // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
     MEMORY.lock().as_mut().unwrap().unshare_all_memory();
-    get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
-        error!("Failed to unshare the UART: {e}");
-        RebootReason::InternalError
-    })?;
+    if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
+        get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
+            error!("Failed to unshare the UART: {e}");
+            RebootReason::InternalError
+        })?;
+    }
 
     // Drop MemoryTracker and deactivate page table.
     drop(MEMORY.lock().take());
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index e7b6386..496e95a 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -53,15 +53,19 @@
 }
 
 fn try_init_logger() -> Result<bool> {
-    let mmio_guard_supported = match get_hypervisor().mmio_guard_init() {
-        // pKVM blocks MMIO by default, we need to enable MMIO guard to support logging.
-        Ok(()) => {
-            get_hypervisor().mmio_guard_map(vmbase::console::BASE_ADDRESS)?;
-            true
+    let mmio_guard_supported = if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
+        match get_hypervisor().mmio_guard_init() {
+            // pKVM blocks MMIO by default, we need to enable MMIO guard to support logging.
+            Ok(()) => {
+                get_hypervisor().mmio_guard_map(vmbase::console::BASE_ADDRESS)?;
+                true
+            }
+            // MMIO guard enroll is not supported in unprotected VM.
+            Err(hyp::Error::MmioGuardNotsupported) => false,
+            Err(e) => return Err(e.into()),
         }
-        // MMIO guard enroll is not supported in unprotected VM.
-        Err(hyp::Error::MmioGuardNotsupported) => false,
-        Err(e) => return Err(e.into()),
+    } else {
+        false
     };
     vmbase::logger::init(log::LevelFilter::Debug).map_err(|_| Error::LoggerInit)?;
     Ok(mmio_guard_supported)