hyp: Refactor HypervisorCap to harden backends

The Hypervisor trait previously required backends to implement all of
its functions, even when they related to features that their underlying
hypervisor did not implement. To deal with this, capabilities were
introduced so that client code would conditionally call those functions
based on the availability of the feature (discovered through the
capabilities). This resulted in useless boiler-plate code in the
backends (either using unimplemented()! or returning placeholders to
please the caller) and a high risk of making use of unavailable features
in hypervisor-agnostic client code.

Instead, rework Hypervisor as an Inlineable Dyn Extension Trait [1],
making it programmatically impossible to call a function for a feature
that the running hypervisor doesn't provide. This also removes the need
for any boilerplate code in the backends.

Introduce the accessors get_mmio_guard() and get_mem_sharer().

No functional change intended.

[1]: https://github.com/daniel5151/inlinable-dyn-extension-traits/blob/master/writeup.md

Test: atest DebugPolicyHostTests#testNoAdbInDebugPolicy_withDebugLevelNone_boots
Test: atest rialto_test vmbase_example.integration_test
Change-Id: I6404fa141f53d074c9529403c4606ab90867cf6c
diff --git a/libs/hyp/Android.bp b/libs/hyp/Android.bp
index 1bb8722..8baf9dd 100644
--- a/libs/hyp/Android.bp
+++ b/libs/hyp/Android.bp
@@ -8,7 +8,6 @@
     srcs: ["src/lib.rs"],
     prefer_rlib: true,
     rustlibs: [
-        "libbitflags",
         "libonce_cell_nostd",
         "libsmccc",
         "libuuid_nostd",
diff --git a/libs/hyp/src/hypervisor/common.rs b/libs/hyp/src/hypervisor/common.rs
index 0982183..7c030a1 100644
--- a/libs/hyp/src/hypervisor/common.rs
+++ b/libs/hyp/src/hypervisor/common.rs
@@ -16,49 +16,49 @@
 
 use crate::error::Result;
 use crate::util::SIZE_4KB;
-use bitflags::bitflags;
 
 /// Expected MMIO guard granule size, validated during MMIO guard initialization.
 pub const MMIO_GUARD_GRANULE_SIZE: usize = SIZE_4KB;
 
-bitflags! {
-    /// Capabilities that Hypervisor backends can declare support for.
-    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;
+/// Trait for the hypervisor.
+pub trait Hypervisor {
+    /// Returns the hypervisor's MMIO_GUARD implementation, if any.
+    fn as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor> {
+        None
+    }
+
+    /// Returns the hypervisor's dynamic memory sharing implementation, if any.
+    fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
+        None
     }
 }
 
-/// Trait for the hypervisor.
-pub trait Hypervisor {
+pub trait MmioGuardedHypervisor {
     /// Initializes the hypervisor by enrolling a MMIO guard and checking the memory granule size.
     /// By enrolling, all MMIO will be blocked unless allow-listed with `mmio_guard_map`.
     /// Protected VMs are auto-enrolled.
-    fn mmio_guard_init(&self) -> Result<()>;
+    fn init(&self) -> Result<()>;
 
     /// Maps a page containing the given memory address to the hypervisor MMIO guard.
     /// The page size corresponds to the MMIO guard granule size.
-    fn mmio_guard_map(&self, addr: usize) -> Result<()>;
+    fn map(&self, addr: usize) -> Result<()>;
 
     /// Unmaps a page containing the given memory address from the hypervisor MMIO guard.
     /// The page size corresponds to the MMIO guard granule size.
-    fn mmio_guard_unmap(&self, addr: usize) -> Result<()>;
+    fn unmap(&self, addr: usize) -> Result<()>;
+}
 
+pub trait MemSharingHypervisor {
     /// Shares a region of memory with host, granting it read, write and execute permissions.
     /// The size of the region is equal to the memory protection granule returned by
     /// [`hyp_meminfo`].
-    fn mem_share(&self, base_ipa: u64) -> Result<()>;
+    fn share(&self, base_ipa: u64) -> Result<()>;
 
     /// Revokes access permission from host to a memory region previously shared with
     /// [`mem_share`]. The size of the region is equal to the memory protection granule returned by
     /// [`hyp_meminfo`].
-    fn mem_unshare(&self, base_ipa: u64) -> Result<()>;
+    fn unshare(&self, base_ipa: u64) -> Result<()>;
 
     /// Returns the memory protection granule size in bytes.
-    fn memory_protection_granule(&self) -> Result<usize>;
-
-    /// Check if required capabilities are supported.
-    fn has_cap(&self, cap: HypervisorCap) -> bool;
+    fn granule(&self) -> Result<usize>;
 }
diff --git a/libs/hyp/src/hypervisor/geniezone.rs b/libs/hyp/src/hypervisor/geniezone.rs
index c69c258..24eb89e 100644
--- a/libs/hyp/src/hypervisor/geniezone.rs
+++ b/libs/hyp/src/hypervisor/geniezone.rs
@@ -14,7 +14,9 @@
 
 //! Wrappers around calls to the GenieZone hypervisor.
 
-use super::common::{Hypervisor, HypervisorCap, MMIO_GUARD_GRANULE_SIZE};
+use super::common::{
+    Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE,
+};
 use crate::error::{Error, Result};
 use crate::util::page_address;
 use core::fmt::{self, Display, Formatter};
@@ -40,8 +42,6 @@
     // 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.union(HypervisorCap::MMIO_GUARD);
 }
 
 /// Error from a GenieZone HVC call.
@@ -86,7 +86,17 @@
 }
 
 impl Hypervisor for GeniezoneHypervisor {
-    fn mmio_guard_init(&self) -> Result<()> {
+    fn as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor> {
+        Some(self)
+    }
+
+    fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
+        Some(self)
+    }
+}
+
+impl MmioGuardedHypervisor for GeniezoneHypervisor {
+    fn init(&self) -> Result<()> {
         mmio_guard_enroll()?;
         let mmio_granule = mmio_guard_granule()?;
         if mmio_granule != MMIO_GUARD_GRANULE_SIZE {
@@ -95,43 +105,41 @@
         Ok(())
     }
 
-    fn mmio_guard_map(&self, addr: usize) -> Result<()> {
+    fn map(&self, addr: usize) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = page_address(addr);
 
         checked_hvc64_expect_zero(VENDOR_HYP_GZVM_MMIO_GUARD_MAP_FUNC_ID, args)
     }
 
-    fn mmio_guard_unmap(&self, addr: usize) -> Result<()> {
+    fn unmap(&self, addr: usize) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = page_address(addr);
 
         checked_hvc64_expect_zero(VENDOR_HYP_GZVM_MMIO_GUARD_UNMAP_FUNC_ID, args)
     }
+}
 
-    fn mem_share(&self, base_ipa: u64) -> Result<()> {
+impl MemSharingHypervisor for GeniezoneHypervisor {
+    fn share(&self, base_ipa: u64) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = base_ipa;
 
         checked_hvc64_expect_zero(ARM_SMCCC_GZVM_FUNC_MEM_SHARE, args)
     }
 
-    fn mem_unshare(&self, base_ipa: u64) -> Result<()> {
+    fn unshare(&self, base_ipa: u64) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = base_ipa;
 
         checked_hvc64_expect_zero(ARM_SMCCC_GZVM_FUNC_MEM_UNSHARE, args)
     }
 
-    fn memory_protection_granule(&self) -> Result<usize> {
+    fn granule(&self) -> Result<usize> {
         let args = [0u64; 17];
         let granule = checked_hvc64(ARM_SMCCC_GZVM_FUNC_HYP_MEMINFO, args)?;
         Ok(granule.try_into().unwrap())
     }
-
-    fn has_cap(&self, cap: HypervisorCap) -> bool {
-        Self::CAPABILITIES.contains(cap)
-    }
 }
 
 fn mmio_guard_granule() -> Result<usize> {
diff --git a/libs/hyp/src/hypervisor/gunyah.rs b/libs/hyp/src/hypervisor/gunyah.rs
index 252430f..45c01bf 100644
--- a/libs/hyp/src/hypervisor/gunyah.rs
+++ b/libs/hyp/src/hypervisor/gunyah.rs
@@ -1,5 +1,4 @@
-use super::common::{Hypervisor, HypervisorCap, MMIO_GUARD_GRANULE_SIZE};
-use crate::error::Result;
+use super::common::Hypervisor;
 use uuid::{uuid, Uuid};
 
 pub(super) struct GunyahHypervisor;
@@ -8,32 +7,4 @@
     pub const UUID: Uuid = uuid!("c1d58fcd-a453-5fdb-9265-ce36673d5f14");
 }
 
-impl Hypervisor for GunyahHypervisor {
-    fn mmio_guard_init(&self) -> Result<()> {
-        Ok(())
-    }
-
-    fn mmio_guard_map(&self, _addr: usize) -> Result<()> {
-        Ok(())
-    }
-
-    fn mmio_guard_unmap(&self, _addr: usize) -> Result<()> {
-        Ok(())
-    }
-
-    fn mem_share(&self, _base_ipa: u64) -> Result<()> {
-        unimplemented!();
-    }
-
-    fn mem_unshare(&self, _base_ipa: u64) -> Result<()> {
-        unimplemented!();
-    }
-
-    fn memory_protection_granule(&self) -> Result<usize> {
-        Ok(MMIO_GUARD_GRANULE_SIZE)
-    }
-
-    fn has_cap(&self, _cap: HypervisorCap) -> bool {
-        false
-    }
-}
+impl Hypervisor for GunyahHypervisor {}
diff --git a/libs/hyp/src/hypervisor/kvm.rs b/libs/hyp/src/hypervisor/kvm.rs
index 4243b5a..ab0aa6c 100644
--- a/libs/hyp/src/hypervisor/kvm.rs
+++ b/libs/hyp/src/hypervisor/kvm.rs
@@ -14,7 +14,9 @@
 
 //! Wrappers around calls to the KVM hypervisor.
 
-use super::common::{Hypervisor, HypervisorCap, MMIO_GUARD_GRANULE_SIZE};
+use super::common::{
+    Hypervisor, MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE,
+};
 use crate::error::{Error, Result};
 use crate::util::page_address;
 use core::fmt::{self, Display, Formatter};
@@ -76,12 +78,20 @@
     // 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.union(HypervisorCap::MMIO_GUARD);
 }
 
 impl Hypervisor for KvmHypervisor {
-    fn mmio_guard_init(&self) -> Result<()> {
+    fn as_mmio_guard(&self) -> Option<&dyn MmioGuardedHypervisor> {
+        Some(self)
+    }
+
+    fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
+        Some(self)
+    }
+}
+
+impl MmioGuardedHypervisor for KvmHypervisor {
+    fn init(&self) -> Result<()> {
         mmio_guard_enroll()?;
         let mmio_granule = mmio_guard_granule()?;
         if mmio_granule != MMIO_GUARD_GRANULE_SIZE {
@@ -90,7 +100,7 @@
         Ok(())
     }
 
-    fn mmio_guard_map(&self, addr: usize) -> Result<()> {
+    fn map(&self, addr: usize) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = page_address(addr);
 
@@ -100,7 +110,7 @@
             .map_err(|e| Error::KvmError(e, VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID))
     }
 
-    fn mmio_guard_unmap(&self, addr: usize) -> Result<()> {
+    fn unmap(&self, addr: usize) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = page_address(addr);
 
@@ -111,30 +121,28 @@
             Err(e) => Err(Error::KvmError(e, VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID)),
         }
     }
+}
 
-    fn mem_share(&self, base_ipa: u64) -> Result<()> {
+impl MemSharingHypervisor for KvmHypervisor {
+    fn share(&self, base_ipa: u64) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = base_ipa;
 
         checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_SHARE, args)
     }
 
-    fn mem_unshare(&self, base_ipa: u64) -> Result<()> {
+    fn unshare(&self, base_ipa: u64) -> Result<()> {
         let mut args = [0u64; 17];
         args[0] = base_ipa;
 
         checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, args)
     }
 
-    fn memory_protection_granule(&self) -> Result<usize> {
+    fn granule(&self) -> Result<usize> {
         let args = [0u64; 17];
         let granule = checked_hvc64(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, args)?;
         Ok(granule.try_into().unwrap())
     }
-
-    fn has_cap(&self, cap: HypervisorCap) -> bool {
-        Self::CAPABILITIES.contains(cap)
-    }
 }
 
 fn mmio_guard_granule() -> Result<usize> {
diff --git a/libs/hyp/src/hypervisor/mod.rs b/libs/hyp/src/hypervisor/mod.rs
index 93d53fe..2c82fc1 100644
--- a/libs/hyp/src/hypervisor/mod.rs
+++ b/libs/hyp/src/hypervisor/mod.rs
@@ -23,9 +23,8 @@
 
 use crate::error::{Error, Result};
 use alloc::boxed::Box;
-pub use common::Hypervisor;
-pub use common::HypervisorCap;
-pub use common::MMIO_GUARD_GRANULE_SIZE;
+use common::Hypervisor;
+pub use common::{MemSharingHypervisor, MmioGuardedHypervisor, MMIO_GUARD_GRANULE_SIZE};
 pub use geniezone::GeniezoneError;
 use geniezone::GeniezoneHypervisor;
 use gunyah::GunyahHypervisor;
@@ -95,8 +94,18 @@
 }
 
 /// Gets the hypervisor singleton.
-pub fn get_hypervisor() -> &'static dyn Hypervisor {
+fn get_hypervisor() -> &'static dyn Hypervisor {
     static HYPERVISOR: OnceBox<HypervisorBackend> = OnceBox::new();
 
     HYPERVISOR.get_or_init(|| Box::new(detect_hypervisor())).get_hypervisor()
 }
+
+/// Gets the MMIO_GUARD hypervisor singleton, if any.
+pub fn get_mmio_guard() -> Option<&'static dyn MmioGuardedHypervisor> {
+    get_hypervisor().as_mmio_guard()
+}
+
+/// Gets the dynamic memory sharing hypervisor singleton, if any.
+pub fn get_mem_sharer() -> Option<&'static dyn MemSharingHypervisor> {
+    get_hypervisor().as_mem_sharer()
+}
diff --git a/libs/hyp/src/lib.rs b/libs/hyp/src/lib.rs
index 3b3b30a..486a181 100644
--- a/libs/hyp/src/lib.rs
+++ b/libs/hyp/src/lib.rs
@@ -21,8 +21,6 @@
 mod util;
 
 pub use error::{Error, Result};
-pub use hypervisor::{
-    get_hypervisor, Hypervisor, HypervisorCap, KvmError, MMIO_GUARD_GRANULE_SIZE,
-};
+pub use hypervisor::{get_mem_sharer, get_mmio_guard, KvmError, MMIO_GUARD_GRANULE_SIZE};
 
 use hypervisor::GeniezoneError;
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index a35e945..7727970 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -23,7 +23,7 @@
 use core::num::NonZeroUsize;
 use core::ops::Range;
 use core::slice;
-use hyp::{get_hypervisor, HypervisorCap};
+use hyp::{get_mem_sharer, get_mmio_guard};
 use log::debug;
 use log::error;
 use log::info;
@@ -112,8 +112,8 @@
             RebootReason::InvalidFdt
         })?;
 
-        if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
-            let granule = get_hypervisor().memory_protection_granule().map_err(|e| {
+        if let Some(mem_sharer) = get_mem_sharer() {
+            let granule = mem_sharer.granule().map_err(|e| {
                 error!("Failed to get memory protection granule: {e}");
                 RebootReason::InternalError
             })?;
@@ -197,13 +197,13 @@
     // 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.
 
-    if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
-        get_hypervisor().mmio_guard_init().map_err(|e| {
+    if let Some(mmio_guard) = get_mmio_guard() {
+        mmio_guard.init().map_err(|e| {
             debug!("{e}");
             RebootReason::InternalError
         })?;
 
-        get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
+        mmio_guard.map(console::BASE_ADDRESS).map_err(|e| {
             debug!("Failed to configure the UART: {e}");
             RebootReason::InternalError
         })?;
@@ -255,8 +255,8 @@
     })?;
     // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
     MEMORY.lock().as_mut().unwrap().unshare_all_memory();
-    if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
-        get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
+    if let Some(mmio_guard) = get_mmio_guard() {
+        mmio_guard.unmap(console::BASE_ADDRESS).map_err(|e| {
             error!("Failed to unshare the UART: {e}");
             RebootReason::InternalError
         })?;
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index 496e95a..df3c844 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -27,7 +27,7 @@
 use core::result;
 use core::slice;
 use fdtpci::PciInfo;
-use hyp::{get_hypervisor, HypervisorCap, KvmError};
+use hyp::{get_mem_sharer, get_mmio_guard, KvmError};
 use libfdt::FdtError;
 use log::{debug, error, info};
 use vmbase::{
@@ -53,11 +53,11 @@
 }
 
 fn try_init_logger() -> Result<bool> {
-    let mmio_guard_supported = if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
-        match get_hypervisor().mmio_guard_init() {
+    let mmio_guard_supported = if let Some(mmio_guard) = get_mmio_guard() {
+        match 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)?;
+                mmio_guard.map(vmbase::console::BASE_ADDRESS)?;
                 true
             }
             // MMIO guard enroll is not supported in unprotected VM.
@@ -102,7 +102,7 @@
         e
     })?;
 
-    if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
+    if get_mem_sharer().is_some() {
         let granule = memory_protection_granule()?;
         MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
             error!("Failed to initialize dynamically shared pool.");
@@ -134,7 +134,10 @@
 }
 
 fn memory_protection_granule() -> result::Result<usize, hyp::Error> {
-    match get_hypervisor().memory_protection_granule() {
+    let Some(mem_sharer) = get_mem_sharer() else {
+        return Ok(PAGE_SIZE);
+    };
+    match mem_sharer.granule() {
         Ok(granule) => Ok(granule),
         // Take the default page size when KVM call is not supported in non-protected VMs.
         Err(hyp::Error::KvmError(KvmError::NotSupported, _)) => Ok(PAGE_SIZE),
@@ -147,7 +150,7 @@
 
     // No logging after unmapping UART.
     if mmio_guard_supported {
-        get_hypervisor().mmio_guard_unmap(vmbase::console::BASE_ADDRESS)?;
+        get_mmio_guard().unwrap().unmap(vmbase::console::BASE_ADDRESS)?;
     }
     // Unshares all memory and deactivates page table.
     drop(MEMORY.lock().take());
diff --git a/vmbase/src/memory/shared.rs b/vmbase/src/memory/shared.rs
index 8c80618..8935934 100644
--- a/vmbase/src/memory/shared.rs
+++ b/vmbase/src/memory/shared.rs
@@ -31,7 +31,7 @@
 use core::ops::Range;
 use core::ptr::NonNull;
 use core::result;
-use hyp::{get_hypervisor, HypervisorCap, MMIO_GUARD_GRANULE_SIZE};
+use hyp::{get_mem_sharer, get_mmio_guard, MMIO_GUARD_GRANULE_SIZE};
 use log::{debug, error, trace};
 use once_cell::race::OnceBox;
 use spin::mutex::SpinMutex;
@@ -179,7 +179,7 @@
             return Err(MemoryTrackerError::Full);
         }
 
-        if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
+        if get_mmio_guard().is_some() {
             self.page_table.map_device_lazy(&get_va_range(&range)).map_err(|e| {
                 error!("Error during lazy MMIO device mapping: {e}");
                 MemoryTrackerError::FailedToMap
@@ -226,7 +226,7 @@
     ///
     /// Note that they are not unmapped from the page table.
     pub fn mmio_unmap_all(&mut self) -> Result<()> {
-        if get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD) {
+        if get_mmio_guard().is_some() {
             for range in &self.mmio_regions {
                 self.page_table
                     .modify_range(&get_va_range(range), &mmio_guard_unmap_page)
@@ -296,11 +296,11 @@
     pub fn handle_mmio_fault(&mut self, addr: VirtualAddress) -> Result<()> {
         let page_start = VirtualAddress(page_4kb_of(addr.0));
         let page_range: VaRange = (page_start..page_start + MMIO_GUARD_GRANULE_SIZE).into();
-        assert!(get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD));
+        let mmio_guard = get_mmio_guard().unwrap();
         self.page_table
             .modify_range(&page_range, &verify_lazy_mapped_block)
             .map_err(|_| MemoryTrackerError::InvalidPte)?;
-        get_hypervisor().mmio_guard_map(page_start.0)?;
+        mmio_guard.map(page_start.0)?;
         // Maps a single device page, breaking up block mappings if necessary.
         self.page_table.map_device(&page_range).map_err(|_| MemoryTrackerError::FailedToMap)
     }
@@ -408,11 +408,11 @@
         let base = shared.as_ptr() as usize;
         let end = base.checked_add(layout.size()).unwrap();
 
-        if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
+        if let Some(mem_sharer) = get_mem_sharer() {
             trace!("Sharing memory region {:#x?}", base..end);
             for vaddr in (base..end).step_by(self.granule) {
                 let vaddr = NonNull::new(vaddr as *mut _).unwrap();
-                get_hypervisor().mem_share(virt_to_phys(vaddr).try_into().unwrap()).unwrap();
+                mem_sharer.share(virt_to_phys(vaddr).try_into().unwrap()).unwrap();
             }
         }
 
@@ -424,12 +424,12 @@
 impl Drop for MemorySharer {
     fn drop(&mut self) {
         while let Some((base, layout)) = self.frames.pop() {
-            if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
+            if let Some(mem_sharer) = get_mem_sharer() {
                 let end = base.checked_add(layout.size()).unwrap();
                 trace!("Unsharing memory region {:#x?}", base..end);
                 for vaddr in (base..end).step_by(self.granule) {
                     let vaddr = NonNull::new(vaddr as *mut _).unwrap();
-                    get_hypervisor().mem_unshare(virt_to_phys(vaddr).try_into().unwrap()).unwrap();
+                    mem_sharer.unshare(virt_to_phys(vaddr).try_into().unwrap()).unwrap();
                 }
             }
 
@@ -485,8 +485,7 @@
         // Since mmio_guard_map takes IPAs, if pvmfw moves non-ID address mapping, page_base
         // should be converted to IPA. However, since 0x0 is a valid MMIO address, we don't use
         // virt_to_phys here, and just pass page_base instead.
-        assert!(get_hypervisor().has_cap(HypervisorCap::MMIO_GUARD));
-        get_hypervisor().mmio_guard_unmap(page_base).map_err(|e| {
+        get_mmio_guard().unwrap().unmap(page_base).map_err(|e| {
             error!("Error MMIO guard unmapping: {e}");
         })?;
     }