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/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
})?;