[hypervisor] Detect hypervisor
Detect underlying hypervisor as a first step for being able to do
hypervisor-specific operations.
Test: m pvmfw_img
Bug: 271493784
Change-Id: I82cc31f3b852bd295eedd492a20e4ead5d128bf0
diff --git a/libs/hyp/Android.bp b/libs/hyp/Android.bp
index e4353c8..0f125fc 100644
--- a/libs/hyp/Android.bp
+++ b/libs/hyp/Android.bp
@@ -8,7 +8,9 @@
srcs: ["src/lib.rs"],
prefer_rlib: true,
rustlibs: [
+ "libonce_cell_nostd",
"libpsci",
+ "libuuid_nostd",
],
no_stdlibs: true,
stdlibs: [
diff --git a/libs/hyp/src/error.rs b/libs/hyp/src/error.rs
index 4e25e7f..408150e 100644
--- a/libs/hyp/src/error.rs
+++ b/libs/hyp/src/error.rs
@@ -16,6 +16,7 @@
use crate::KvmError;
use core::{fmt, result};
+use uuid::Uuid;
/// Result type with hypervisor error.
pub type Result<T> = result::Result<T, Error>;
@@ -27,6 +28,8 @@
MmioGuardNotsupported,
/// Failed to invoke a certain KVM HVC function.
KvmError(KvmError, u32),
+ /// Unsupported Hypervisor.
+ UnsupportedHypervisorUuid(Uuid),
/// The MMIO_GUARD granule used by the hypervisor is not supported.
UnsupportedMmioGuardGranule(usize),
}
@@ -38,6 +41,9 @@
Self::KvmError(e, function_id) => {
write!(f, "Failed to invoke the HVC function with function ID {function_id}: {e}")
}
+ Self::UnsupportedHypervisorUuid(u) => {
+ write!(f, "Unsupported Hypervisor UUID {u}")
+ }
Self::UnsupportedMmioGuardGranule(g) => {
write!(f, "Unsupported MMIO guard granule: {g}")
}
diff --git a/libs/hyp/src/hypervisor/kvm.rs b/libs/hyp/src/hypervisor/kvm.rs
index c0c1ac9..00efde4 100644
--- a/libs/hyp/src/hypervisor/kvm.rs
+++ b/libs/hyp/src/hypervisor/kvm.rs
@@ -22,6 +22,7 @@
error::{positive_or_error_64, success_or_error_32, success_or_error_64},
hvc64,
};
+use uuid::{uuid, Uuid};
/// Error from a KVM HVC call.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -71,6 +72,12 @@
pub(super) struct KvmHypervisor;
+impl KvmHypervisor {
+ // 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");
+}
+
impl Hypervisor for KvmHypervisor {
fn mmio_guard_init(&self) -> Result<()> {
mmio_guard_enroll()?;
diff --git a/libs/hyp/src/hypervisor/mod.rs b/libs/hyp/src/hypervisor/mod.rs
index a694029..dc9e7c3 100644
--- a/libs/hyp/src/hypervisor/mod.rs
+++ b/libs/hyp/src/hypervisor/mod.rs
@@ -14,14 +14,19 @@
//! Wrappers around hypervisor back-ends.
+extern crate alloc;
+
mod common;
mod kvm;
+use crate::error::{Error, Result};
+use alloc::boxed::Box;
pub use common::Hypervisor;
pub use kvm::KvmError;
use kvm::KvmHypervisor;
-
-static HYPERVISOR: HypervisorBackend = HypervisorBackend::Kvm;
+use once_cell::race::OnceBox;
+use psci::smccc::hvc64;
+use uuid::Uuid;
enum HypervisorBackend {
Kvm,
@@ -35,7 +40,50 @@
}
}
+impl TryFrom<Uuid> for HypervisorBackend {
+ type Error = Error;
+
+ fn try_from(uuid: Uuid) -> Result<HypervisorBackend> {
+ match uuid {
+ KvmHypervisor::UUID => Ok(HypervisorBackend::Kvm),
+ u => Err(Error::UnsupportedHypervisorUuid(u)),
+ }
+ }
+}
+
+const ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: u32 = 0x8600ff01;
+
+fn query_vendor_hyp_call_uid() -> Uuid {
+ let args = [0u64; 17];
+ let res = hvc64(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, args);
+
+ // KVM's UUID of "28b46fb6-2ec5-11e9-a9ca-4b564d003a74" is generated by
+ // Uuid::from_u128() from an input value of
+ // 0x28b46fb6_2ec511e9_a9ca4b56_4d003a74. ARM's SMC calling convention
+ // (Document number ARM DEN 0028E) describes the UUID register mapping such
+ // that W0 contains bytes 0..3 of UUID, with byte 0 in lower order bits. In
+ // the KVM example, byte 0 of KVM's UUID (0x28) will be returned in the low
+ // 8-bits of W0, while byte 15 (0x74) will be returned in bits 31-24 of W3.
+ //
+ // `uuid` value derived below thus need to be byte-reversed before
+ // being used in Uuid::from_u128(). Alternately use Uuid::from_u128_le()
+ // to achieve the same.
+
+ let uuid = ((res[3] as u32 as u128) << 96)
+ | ((res[2] as u32 as u128) << 64)
+ | ((res[1] as u32 as u128) << 32)
+ | (res[0] as u32 as u128);
+
+ Uuid::from_u128_le(uuid)
+}
+
+fn detect_hypervisor() -> HypervisorBackend {
+ query_vendor_hyp_call_uid().try_into().expect("Unknown hypervisor")
+}
+
/// Gets the hypervisor singleton.
pub fn get_hypervisor() -> &'static dyn Hypervisor {
- HYPERVISOR.get_hypervisor()
+ static HYPERVISOR: OnceBox<HypervisorBackend> = OnceBox::new();
+
+ HYPERVISOR.get_or_init(|| Box::new(detect_hypervisor())).get_hypervisor()
}