Merge "pvmfw: avb: Add API tests for tampered initrd" into main
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index bb2e6ce..fb485fe 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -166,7 +166,7 @@
tokens: Vec<&'a [u8]>,
}
-impl<'a> fmt::Debug for DtPathTokens<'a> {
+impl fmt::Debug for DtPathTokens<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for token in &self.tokens {
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 818d342..fac9a9a 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -554,7 +554,7 @@
}
}
-impl<'a, const N: usize> Iterator for CellChunkIterator<'a, N> {
+impl<const N: usize> Iterator for CellChunkIterator<'_, N> {
type Item = [u32; N];
fn next(&mut self) -> Option<Self::Item> {
let mut ret: Self::Item = [0; N];
diff --git a/guest/pvmfw/src/instance.rs b/guest/pvmfw/src/instance.rs
index bb07f74..bbc58ed 100644
--- a/guest/pvmfw/src/instance.rs
+++ b/guest/pvmfw/src/instance.rs
@@ -26,7 +26,10 @@
use diced_open_dice::Hidden;
use log::trace;
use uuid::Uuid;
-use virtio_drivers::transport::{pci::bus::PciRoot, DeviceType, Transport};
+use virtio_drivers::transport::{
+ pci::bus::{ConfigurationAccess, PciRoot},
+ DeviceType, Transport,
+};
use vmbase::util::ceiling_div;
use vmbase::virtio::pci::{PciTransportIterator, VirtIOBlk};
use vmbase::virtio::HalImpl;
@@ -99,7 +102,7 @@
/// pvmfw in the instance.img as well as index corresponding to empty header which can be used to
/// record instance data with `record_instance_entry`.
pub(crate) fn get_recorded_entry(
- pci_root: &mut PciRoot,
+ pci_root: &mut PciRoot<impl ConfigurationAccess>,
secret: &[u8],
) -> Result<(Option<EntryBody>, Partition, usize)> {
let mut instance_img = find_instance_img(pci_root)?;
@@ -175,8 +178,8 @@
}
}
-fn find_instance_img(pci_root: &mut PciRoot) -> Result<Partition> {
- for transport in PciTransportIterator::<HalImpl>::new(pci_root)
+fn find_instance_img(pci_root: &mut PciRoot<impl ConfigurationAccess>) -> Result<Partition> {
+ for transport in PciTransportIterator::<HalImpl, _>::new(pci_root)
.filter(|t| DeviceType::Block == t.device_type())
{
let device =
diff --git a/guest/pvmfw/src/rollback.rs b/guest/pvmfw/src/rollback.rs
index 74b2cd8..e51b6d5 100644
--- a/guest/pvmfw/src/rollback.rs
+++ b/guest/pvmfw/src/rollback.rs
@@ -25,7 +25,7 @@
use log::{error, info};
use pvmfw_avb::Capability;
use pvmfw_avb::VerifiedBootData;
-use virtio_drivers::transport::pci::bus::PciRoot;
+use virtio_drivers::transport::pci::bus::{ConfigurationAccess, PciRoot};
use vmbase::fdt::{pci::PciInfo, SwiotlbInfo};
use vmbase::memory::init_shared_pool;
use vmbase::rand;
@@ -44,17 +44,16 @@
cdi_seal: &[u8],
instance_hash: Option<Hidden>,
) -> Result<(bool, Hidden, bool), RebootReason> {
- if should_defer_rollback_protection(fdt)?
- && verified_boot_data.has_capability(Capability::SecretkeeperProtection)
+ if let Some(fixed) = get_fixed_rollback_protection(verified_boot_data) {
+ // Prevent attackers from impersonating well-known images.
+ perform_fixed_index_rollback_protection(verified_boot_data, fixed)?;
+ Ok((false, instance_hash.unwrap(), false))
+ } else if (should_defer_rollback_protection(fdt)?
+ && verified_boot_data.has_capability(Capability::SecretkeeperProtection))
+ || verified_boot_data.has_capability(Capability::TrustySecurityVm)
{
perform_deferred_rollback_protection(verified_boot_data)?;
Ok((false, instance_hash.unwrap(), true))
- } else if verified_boot_data.has_capability(Capability::RemoteAttest) {
- perform_fixed_index_rollback_protection(verified_boot_data)?;
- Ok((false, instance_hash.unwrap(), false))
- } else if verified_boot_data.has_capability(Capability::TrustySecurityVm) {
- skip_rollback_protection()?;
- Ok((false, instance_hash.unwrap(), false))
} else {
perform_legacy_rollback_protection(fdt, dice_inputs, cdi_seal, instance_hash)
}
@@ -74,11 +73,19 @@
}
}
+fn get_fixed_rollback_protection(verified_boot_data: &VerifiedBootData) -> Option<u64> {
+ if verified_boot_data.has_capability(Capability::RemoteAttest) {
+ Some(service_vm_version::VERSION)
+ } else {
+ None
+ }
+}
+
fn perform_fixed_index_rollback_protection(
verified_boot_data: &VerifiedBootData,
+ fixed_index: u64,
) -> Result<(), RebootReason> {
info!("Performing fixed-index rollback protection");
- let fixed_index = service_vm_version::VERSION;
let index = verified_boot_data.rollback_index;
if index != fixed_index {
error!("Rollback index mismatch: expected {fixed_index}, found {index}");
@@ -88,11 +95,6 @@
}
}
-fn skip_rollback_protection() -> Result<(), RebootReason> {
- info!("Skipping rollback protection");
- Ok(())
-}
-
/// Performs RBP using instance.img where updates require clearing old entries, causing new CDIs.
fn perform_legacy_rollback_protection(
fdt: &Fdt,
@@ -167,7 +169,9 @@
}
/// Set up PCI bus and VirtIO-blk device containing the instance.img partition.
-fn initialize_instance_img_device(fdt: &Fdt) -> Result<PciRoot, RebootReason> {
+fn initialize_instance_img_device(
+ fdt: &Fdt,
+) -> Result<PciRoot<impl ConfigurationAccess>, RebootReason> {
let pci_info = PciInfo::from_fdt(fdt).map_err(|e| {
error!("Failed to detect PCI from DT: {e}");
RebootReason::InvalidFdt
diff --git a/guest/rialto/src/communication.rs b/guest/rialto/src/communication.rs
index 1b94912..6f5a59e 100644
--- a/guest/rialto/src/communication.rs
+++ b/guest/rialto/src/communication.rs
@@ -67,7 +67,7 @@
match event {
VsockEventType::Connected => return Ok(()),
VsockEventType::Disconnected { .. } => {
- return Err(SocketError::ConnectionFailed.into())
+ return Err(SocketError::NotConnected.into())
}
// We shouldn't receive the following event before the connection is
// established.
@@ -141,7 +141,7 @@
fn poll(&mut self) -> virtio_drivers::Result<Option<VsockEventType>> {
if let Some(event) = self.poll_event_from_peer()? {
match event {
- VsockEventType::Disconnected { .. } => Err(SocketError::ConnectionFailed.into()),
+ VsockEventType::Disconnected { .. } => Err(SocketError::NotConnected.into()),
VsockEventType::Connected | VsockEventType::ConnectionRequest => {
Err(SocketError::InvalidOperation.into())
}
diff --git a/guest/rialto/src/main.rs b/guest/rialto/src/main.rs
index 04d18be..c3d3604 100644
--- a/guest/rialto/src/main.rs
+++ b/guest/rialto/src/main.rs
@@ -38,7 +38,10 @@
use service_vm_requests::{process_request, RequestContext};
use virtio_drivers::{
device::socket::{VsockAddr, VMADDR_CID_HOST},
- transport::{pci::bus::PciRoot, DeviceType, Transport},
+ transport::{
+ pci::bus::{ConfigurationAccess, PciRoot},
+ DeviceType, Transport,
+ },
Hal,
};
use vmbase::{
@@ -123,7 +126,6 @@
let pci_info = PciInfo::from_fdt(fdt)?;
debug!("PCI: {pci_info:#x?}");
let mut pci_root = pci::initialize(pci_info).map_err(Error::PciInitializationFailed)?;
- debug!("PCI root: {pci_root:#x?}");
let socket_device = find_socket_device::<HalImpl>(&mut pci_root)?;
debug!("Found socket device: guest cid = {:?}", socket_device.guest_cid());
let vendor_hashtree_root_digest = read_vendor_hashtree_root_digest(fdt)?;
@@ -143,8 +145,10 @@
Ok(())
}
-fn find_socket_device<T: Hal>(pci_root: &mut PciRoot) -> Result<VirtIOSocket<T>> {
- PciTransportIterator::<T>::new(pci_root)
+fn find_socket_device<T: Hal>(
+ pci_root: &mut PciRoot<impl ConfigurationAccess>,
+) -> Result<VirtIOSocket<T>> {
+ PciTransportIterator::<T, _>::new(pci_root)
.find(|t| DeviceType::Socket == t.device_type())
.map(VirtIOSocket::<T>::new)
.transpose()
diff --git a/guest/vmbase_example/src/pci.rs b/guest/vmbase_example/src/pci.rs
index 32ab9f6..1e87682 100644
--- a/guest/vmbase_example/src/pci.rs
+++ b/guest/vmbase_example/src/pci.rs
@@ -20,7 +20,10 @@
use virtio_drivers::{
device::console::VirtIOConsole,
transport::{
- pci::{bus::PciRoot, PciTransport},
+ pci::{
+ bus::{ConfigurationAccess, PciRoot},
+ PciTransport,
+ },
DeviceType, Transport,
},
BufferDirection, Error, Hal, PhysAddr, PAGE_SIZE,
@@ -33,11 +36,11 @@
/// The size in sectors of the test block device we expect.
const EXPECTED_SECTOR_COUNT: usize = 4;
-pub fn check_pci(pci_root: &mut PciRoot) {
+pub fn check_pci(pci_root: &mut PciRoot<impl ConfigurationAccess>) {
let mut checked_virtio_device_count = 0;
let mut block_device_count = 0;
let mut socket_device_count = 0;
- for mut transport in PciTransportIterator::<HalImpl>::new(pci_root) {
+ for mut transport in PciTransportIterator::<HalImpl, _>::new(pci_root) {
info!(
"Detected virtio PCI device with device type {:?}, features {:#018x}",
transport.device_type(),
@@ -104,7 +107,10 @@
fn check_virtio_console_device(transport: PciTransport) {
let mut console = VirtIOConsole::<HalImpl, PciTransport>::new(transport)
.expect("Failed to create VirtIO console driver");
- info!("Found console device: {:?}", console.info());
+ info!(
+ "Found console device with size {:?}",
+ console.size().expect("Failed to get size of VirtIO console device")
+ );
for &c in b"Hello VirtIO console\n" {
console.send(c).expect("Failed to send character to VirtIO console device");
}
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index 1870ab6..75f70c3 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -75,6 +75,7 @@
defaults: ["libdiced_open_dice_test_defaults"],
rustlibs: [
"libdiced_open_dice",
+ "libcoset",
],
}
@@ -83,6 +84,7 @@
defaults: ["libdiced_open_dice_test_defaults"],
rustlibs: [
"libdiced_open_dice_nostd",
+ "libcoset_nostd",
],
}
@@ -146,6 +148,7 @@
"--allowlist-function=DiceKdf",
"--allowlist-function=DiceKeypairFromSeed",
"--allowlist-function=DiceSign",
+ "--allowlist-function=DiceCoseSignAndEncodeSign1",
"--allowlist-function=DiceVerify",
"--allowlist-function=DiceGenerateCertificate",
diff --git a/libs/dice/open_dice/bindgen/dice/dice.h b/libs/dice/open_dice/bindgen/dice/dice.h
index 47fe911..e6d5131 100644
--- a/libs/dice/open_dice/bindgen/dice/dice.h
+++ b/libs/dice/open_dice/bindgen/dice/dice.h
@@ -16,3 +16,4 @@
#include <dice/dice.h>
#include <dice/ops.h>
+#include <dice/ops/trait/cose.h>
diff --git a/libs/dice/open_dice/bindgen/dice/rules.mk b/libs/dice/open_dice/bindgen/dice/rules.mk
index 0ea5c7c..e9c4b81 100644
--- a/libs/dice/open_dice/bindgen/dice/rules.mk
+++ b/libs/dice/open_dice/bindgen/dice/rules.mk
@@ -39,6 +39,7 @@
DiceKdf \
DiceKeypairFromSeed \
DiceSign \
+ DiceCoseSignAndEncodeSign1 \
DiceVerify \
DiceGenerateCertificate \
diff --git a/libs/dice/open_dice/src/lib.rs b/libs/dice/open_dice/src/lib.rs
index 4d05255..33fb65c 100644
--- a/libs/dice/open_dice/src/lib.rs
+++ b/libs/dice/open_dice/src/lib.rs
@@ -43,9 +43,11 @@
};
pub use error::{DiceError, Result};
pub use ops::{
- derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign, verify,
+ derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign,
+ sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv, verify,
};
pub use retry::{
retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow,
- retry_generate_certificate, OwnedDiceArtifacts,
+ retry_generate_certificate, retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv,
+ OwnedDiceArtifacts,
};
diff --git a/libs/dice/open_dice/src/ops.rs b/libs/dice/open_dice/src/ops.rs
index 41951bf..2014118 100644
--- a/libs/dice/open_dice/src/ops.rs
+++ b/libs/dice/open_dice/src/ops.rs
@@ -23,8 +23,8 @@
use crate::error::{check_result, DiceError, Result};
use alloc::{vec, vec::Vec};
use open_dice_cbor_bindgen::{
- DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed, DicePrincipal, DiceSign,
- DiceVerify,
+ DiceCoseSignAndEncodeSign1, DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed,
+ DicePrincipal, DiceSign, DiceVerify,
};
use std::ptr;
@@ -114,7 +114,7 @@
Ok(private_key)
}
-/// Signs the `message` with the give `private_key` using `DiceSign`.
+/// Signs the `message` with the given `private_key` using `DiceSign`.
pub fn sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>> {
let mut signature = vec![0u8; VM_KEY_ALGORITHM.signature_size()];
check_result(
@@ -136,6 +136,58 @@
Ok(signature)
}
+/// Signs the `message` with the given `private_key` and places a `CoseSign1` encoded
+/// object in `encoded_signature`. Uses `DiceCoseSignAndEncodeSign1`.
+///
+/// Returns the actual size of encoded_signature on success.
+pub fn sign_cose_sign1(
+ message: &[u8],
+ aad: &[u8],
+ private_key: &[u8; PRIVATE_KEY_SIZE],
+ encoded_signature: &mut [u8],
+) -> Result<usize> {
+ let mut encoded_signature_actual_size = 0;
+
+ check_result(
+ // SAFETY: The function writes to `encoded_signature` and `encoded_signature_actual_size`
+ // within the given bounds. It only reads `message`, `aad`, and `private_key` within their
+ // given bounds.
+ //
+ // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
+ // and a null pointer otherwise.
+ unsafe {
+ DiceCoseSignAndEncodeSign1(
+ context(),
+ message.as_ptr(),
+ message.len(),
+ aad.as_ptr(),
+ aad.len(),
+ private_key.as_ptr(),
+ encoded_signature.len(),
+ encoded_signature.as_mut_ptr(),
+ &mut encoded_signature_actual_size,
+ )
+ },
+ encoded_signature_actual_size,
+ )?;
+ Ok(encoded_signature_actual_size)
+}
+
+/// Signs the `message` with a private key derived from the given `dice_artifacts`
+/// CDI Attest. On success, places a `CoseSign1` encoded object in `encoded_signature`.
+/// Uses `DiceCoseSignAndEncodeSign1`.
+///
+/// Returns the actual size of encoded_signature on success.
+pub fn sign_cose_sign1_with_cdi_leaf_priv(
+ message: &[u8],
+ aad: &[u8],
+ dice_artifacts: &dyn DiceArtifacts,
+ encoded_signature: &mut [u8],
+) -> Result<usize> {
+ let private_key = derive_cdi_leaf_priv(dice_artifacts)?;
+ sign_cose_sign1(message, aad, private_key.as_array(), encoded_signature)
+}
+
/// Verifies the `signature` of the `message` with the given `public_key` using `DiceVerify`.
pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<()> {
if signature.len() != VM_KEY_ALGORITHM.signature_size()
diff --git a/libs/dice/open_dice/src/retry.rs b/libs/dice/open_dice/src/retry.rs
index 803673d..cf36bc0 100644
--- a/libs/dice/open_dice/src/retry.rs
+++ b/libs/dice/open_dice/src/retry.rs
@@ -20,9 +20,10 @@
use crate::bcc::{bcc_format_config_descriptor, bcc_main_flow, DiceConfigValues};
use crate::dice::{
dice_main_flow, Cdi, CdiValues, DiceArtifacts, InputValues, CDI_SIZE, PRIVATE_KEY_SEED_SIZE,
+ PRIVATE_KEY_SIZE,
};
use crate::error::{DiceError, Result};
-use crate::ops::generate_certificate;
+use crate::ops::{generate_certificate, sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv};
use alloc::vec::Vec;
#[cfg(feature = "serde_derive")]
use serde_derive::{Deserialize, Serialize};
@@ -144,3 +145,28 @@
)
})
}
+
+/// Signs a message with the given private key and returns the signature
+/// as an encoded CoseSign1 object.
+pub fn retry_sign_cose_sign1(
+ message: &[u8],
+ aad: &[u8],
+ private_key: &[u8; PRIVATE_KEY_SIZE],
+) -> Result<Vec<u8>> {
+ retry_with_measured_buffer(|encoded_signature| {
+ sign_cose_sign1(message, aad, private_key, encoded_signature)
+ })
+}
+
+/// Signs a message with the given the private key derived from the
+/// CDI Attest of the given `dice_artifacts` and returns the signature
+/// as an encoded CoseSign1 object.
+pub fn retry_sign_cose_sign1_with_cdi_leaf_priv(
+ message: &[u8],
+ aad: &[u8],
+ dice_artifacts: &dyn DiceArtifacts,
+) -> Result<Vec<u8>> {
+ retry_with_measured_buffer(|encoded_signature| {
+ sign_cose_sign1_with_cdi_leaf_priv(message, aad, dice_artifacts, encoded_signature)
+ })
+}
diff --git a/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
index d3a91ff..b0c2ca7 100644
--- a/libs/dice/open_dice/tests/api_test.rs
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -17,10 +17,13 @@
#[cfg(test)]
mod tests {
use diced_open_dice::{
- derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed, sign,
- verify, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
+ derive_cdi_certificate_id, derive_cdi_private_key_seed, hash, kdf, keypair_from_seed,
+ retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv, sign, verify,
+ DiceArtifacts, PrivateKey, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
};
+ use coset::{CborSerializable, CoseSign1};
+
// This test initialization is only required for the trusty test harness.
#[cfg(feature = "trusty")]
test::init!();
@@ -66,7 +69,7 @@
0x94, 0xd8, 0x8c, 0xa8,
];
- const EXPECTED_CDI_ATTEST: &[u8] = &[
+ const EXPECTED_CDI_ATTEST: &[u8; CDI_SIZE] = &[
0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
0x3a, 0x08,
@@ -101,6 +104,85 @@
#[test]
fn hash_derive_sign_verify() {
+ let (pub_key, priv_key) = get_test_key_pair();
+
+ let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
+ assert_eq!(&signature, EXPECTED_SIGNATURE);
+ assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
+ assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
+ signature[0] += 1;
+ assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+ }
+
+ #[test]
+ fn sign_cose_sign1_verify() {
+ let (pub_key, priv_key) = get_test_key_pair();
+
+ let signature_res = retry_sign_cose_sign1(b"MyMessage", b"MyAad", priv_key.as_array());
+ assert!(signature_res.is_ok());
+ let signature = signature_res.unwrap();
+ let cose_sign1_res = CoseSign1::from_slice(&signature);
+ assert!(cose_sign1_res.is_ok());
+ let mut cose_sign1 = cose_sign1_res.unwrap();
+
+ let mut verify_result =
+ cose_sign1.verify_signature(b"MyAad", |sign, data| verify(data, sign, &pub_key));
+ assert!(verify_result.is_ok());
+
+ verify_result =
+ cose_sign1.verify_signature(b"BadAad", |sign, data| verify(data, sign, &pub_key));
+ assert!(verify_result.is_err());
+
+ // if we modify the signature, the payload should no longer verify
+ cose_sign1.signature.push(0xAA);
+ verify_result =
+ cose_sign1.verify_signature(b"MyAad", |sign, data| verify(data, sign, &pub_key));
+ assert!(verify_result.is_err());
+ }
+
+ struct TestArtifactsForSigning {}
+
+ impl DiceArtifacts for TestArtifactsForSigning {
+ fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
+ EXPECTED_CDI_ATTEST
+ }
+
+ fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
+ unimplemented!("no test functionality depends on this")
+ }
+
+ fn bcc(&self) -> Option<&[u8]> {
+ unimplemented!("no test functionality depends on this")
+ }
+ }
+
+ #[test]
+ fn sign_cose_sign1_with_cdi_leaf_priv_verify() {
+ let dice = TestArtifactsForSigning {};
+
+ let signature_res = retry_sign_cose_sign1_with_cdi_leaf_priv(b"MyMessage", b"MyAad", &dice);
+ assert!(signature_res.is_ok());
+ let signature = signature_res.unwrap();
+ let cose_sign1_res = CoseSign1::from_slice(&signature);
+ assert!(cose_sign1_res.is_ok());
+ let mut cose_sign1 = cose_sign1_res.unwrap();
+
+ let mut verify_result = cose_sign1
+ .verify_signature(b"MyAad", |sign, data| verify(data, sign, EXPECTED_PUB_KEY));
+ assert!(verify_result.is_ok());
+
+ verify_result = cose_sign1
+ .verify_signature(b"BadAad", |sign, data| verify(data, sign, EXPECTED_PUB_KEY));
+ assert!(verify_result.is_err());
+
+ // if we modify the signature, the payload should no longer verify
+ cose_sign1.signature.push(0xAA);
+ verify_result = cose_sign1
+ .verify_signature(b"MyAad", |sign, data| verify(data, sign, EXPECTED_PUB_KEY));
+ assert!(verify_result.is_err());
+ }
+
+ fn get_test_key_pair() -> (Vec<u8>, PrivateKey) {
let seed = hash(b"MySeedString").unwrap();
assert_eq!(seed, EXPECTED_SEED);
let cdi_attest = &seed[..CDI_SIZE];
@@ -111,11 +193,7 @@
let (pub_key, priv_key) = keypair_from_seed(cdi_private_key_seed.as_array()).unwrap();
assert_eq!(&pub_key, EXPECTED_PUB_KEY);
assert_eq!(priv_key.as_array(), EXPECTED_PRIV_KEY);
- let mut signature = sign(b"MyMessage", priv_key.as_array()).unwrap();
- assert_eq!(&signature, EXPECTED_SIGNATURE);
- assert!(verify(b"MyMessage", &signature, &pub_key).is_ok());
- assert!(verify(b"MyMessage_fail", &signature, &pub_key).is_err());
- signature[0] += 1;
- assert!(verify(b"MyMessage", &signature, &pub_key).is_err());
+
+ (pub_key, priv_key)
}
}
diff --git a/libs/dice/open_dice/tests/rules.mk b/libs/dice/open_dice/tests/rules.mk
index a9d332c..83a6bff 100644
--- a/libs/dice/open_dice/tests/rules.mk
+++ b/libs/dice/open_dice/tests/rules.mk
@@ -23,6 +23,7 @@
MODULE_LIBRARY_DEPS += \
packages/modules/Virtualization/libs/dice/open_dice \
+ $(call FIND_CRATE,coset) \
MODULE_RUST_TESTS := true
diff --git a/libs/libhypervisor_backends/Android.bp b/libs/libhypervisor_backends/Android.bp
index 27e3fe5..e9e8915 100644
--- a/libs/libhypervisor_backends/Android.bp
+++ b/libs/libhypervisor_backends/Android.bp
@@ -11,20 +11,27 @@
host_supported: false,
no_stdlibs: true,
srcs: ["src/lib.rs"],
- rustlibs: [
- "libonce_cell_nostd",
- "libsmccc",
- "libthiserror_nostd",
- "libuuid_nostd",
- ],
enabled: false,
+ stdlibs: [
+ "libcompiler_builtins.rust_sysroot",
+ "libcore.rust_sysroot",
+ ],
target: {
android_arm64: {
- enabled: true,
- stdlibs: [
- "libcompiler_builtins.rust_sysroot",
- "libcore.rust_sysroot",
+ rustlibs: [
+ "libonce_cell_nostd",
+ "libsmccc",
+ "libthiserror_nostd",
+ "libuuid_nostd",
],
+ enabled: true,
+ },
+ android_x86_64: {
+ rustlibs: [
+ "libonce_cell_nostd",
+ "libthiserror_nostd",
+ ],
+ enabled: true,
},
},
}
diff --git a/libs/libhypervisor_backends/src/error.rs b/libs/libhypervisor_backends/src/error.rs
index e9c37e1..3046b0c 100644
--- a/libs/libhypervisor_backends/src/error.rs
+++ b/libs/libhypervisor_backends/src/error.rs
@@ -16,7 +16,10 @@
use core::{fmt, result};
-use super::hypervisor::{GeniezoneError, KvmError};
+#[cfg(target_arch = "aarch64")]
+use super::hypervisor::GeniezoneError;
+use super::hypervisor::KvmError;
+#[cfg(target_arch = "aarch64")]
use uuid::Uuid;
/// Result type with hypervisor error.
@@ -29,10 +32,15 @@
MmioGuardNotSupported,
/// Failed to invoke a certain KVM HVC function.
KvmError(KvmError, u32),
+ #[cfg(target_arch = "aarch64")]
/// Failed to invoke GenieZone HVC function.
GeniezoneError(GeniezoneError, u32),
+ #[cfg(target_arch = "aarch64")]
/// Unsupported Hypervisor
UnsupportedHypervisorUuid(Uuid),
+ #[cfg(target_arch = "x86_64")]
+ /// Unsupported x86_64 Hypervisor
+ UnsupportedHypervisor(u128),
}
impl fmt::Display for Error {
@@ -42,15 +50,21 @@
Self::KvmError(e, function_id) => {
write!(f, "Failed to invoke the HVC function with function ID {function_id}: {e}")
}
+ #[cfg(target_arch = "aarch64")]
Self::GeniezoneError(e, function_id) => {
write!(
f,
"Failed to invoke GenieZone HVC function with function ID {function_id}: {e}"
)
}
+ #[cfg(target_arch = "aarch64")]
Self::UnsupportedHypervisorUuid(u) => {
write!(f, "Unsupported Hypervisor UUID {u}")
}
+ #[cfg(target_arch = "x86_64")]
+ Self::UnsupportedHypervisor(c) => {
+ write!(f, "Unsupported x86_64 Hypervisor {c}")
+ }
}
}
}
diff --git a/libs/libhypervisor_backends/src/hypervisor.rs b/libs/libhypervisor_backends/src/hypervisor.rs
index 1b45f38..aa65133 100644
--- a/libs/libhypervisor_backends/src/hypervisor.rs
+++ b/libs/libhypervisor_backends/src/hypervisor.rs
@@ -15,26 +15,42 @@
//! Wrappers around hypervisor back-ends.
mod common;
+#[cfg(target_arch = "aarch64")]
mod geniezone;
+#[cfg(target_arch = "aarch64")]
mod gunyah;
+#[cfg(target_arch = "aarch64")]
+#[path = "hypervisor/kvm_aarch64.rs"]
mod kvm;
-use super::{Error, Result};
+#[cfg(target_arch = "x86_64")]
+#[path = "hypervisor/kvm_x86.rs"]
+mod kvm;
+
+#[cfg(target_arch = "aarch64")]
+use {
+ super::{Error, Result},
+ geniezone::GeniezoneHypervisor,
+ gunyah::GunyahHypervisor,
+ smccc::hvc64,
+ uuid::Uuid,
+};
+
+#[cfg(target_arch = "aarch64")]
+pub use geniezone::GeniezoneError;
+
use alloc::boxed::Box;
use common::Hypervisor;
pub use common::{DeviceAssigningHypervisor, MemSharingHypervisor, MmioGuardedHypervisor};
-pub use geniezone::GeniezoneError;
-use geniezone::GeniezoneHypervisor;
-use gunyah::GunyahHypervisor;
pub use kvm::KvmError;
use kvm::{ProtectedKvmHypervisor, RegularKvmHypervisor};
use once_cell::race::OnceBox;
-use smccc::hvc64;
-use uuid::Uuid;
enum HypervisorBackend {
RegularKvm,
+ #[cfg(target_arch = "aarch64")]
Gunyah,
+ #[cfg(target_arch = "aarch64")]
Geniezone,
ProtectedKvm,
}
@@ -43,13 +59,16 @@
fn get_hypervisor(&self) -> &'static dyn Hypervisor {
match self {
Self::RegularKvm => &RegularKvmHypervisor,
+ #[cfg(target_arch = "aarch64")]
Self::Gunyah => &GunyahHypervisor,
+ #[cfg(target_arch = "aarch64")]
Self::Geniezone => &GeniezoneHypervisor,
Self::ProtectedKvm => &ProtectedKvmHypervisor,
}
}
}
+#[cfg(target_arch = "aarch64")]
impl TryFrom<Uuid> for HypervisorBackend {
type Error = Error;
@@ -74,8 +93,10 @@
}
}
+#[cfg(target_arch = "aarch64")]
const ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: u32 = 0x8600ff01;
+#[cfg(target_arch = "aarch64")]
fn query_vendor_hyp_call_uid() -> Uuid {
let args = [0u64; 17];
let res = hvc64(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, args);
@@ -101,7 +122,13 @@
}
fn detect_hypervisor() -> HypervisorBackend {
- query_vendor_hyp_call_uid().try_into().expect("Failed to detect hypervisor")
+ #[cfg(target_arch = "aarch64")]
+ {
+ query_vendor_hyp_call_uid().try_into().expect("Failed to detect hypervisor")
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ kvm::determine_hyp_type().expect("Failed to detect hypervisor")
}
/// Gets the hypervisor singleton.
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
similarity index 100%
rename from libs/libhypervisor_backends/src/hypervisor/kvm.rs
rename to libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
new file mode 100644
index 0000000..7f9ea4d
--- /dev/null
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
@@ -0,0 +1,172 @@
+// Copyright 2025, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Wrappers around calls to the KVM hypervisor.
+
+use super::{Hypervisor, MemSharingHypervisor};
+use crate::{mem::SIZE_4KB, Error, Result};
+use core::fmt::{self, Display, Formatter};
+
+const KVM_HC_PKVM_OP: u32 = 20;
+const PKVM_GHC_SHARE_MEM: u32 = KVM_HC_PKVM_OP + 1;
+const PKVM_GHC_UNSHARE_MEM: u32 = KVM_HC_PKVM_OP + 2;
+
+const KVM_ENOSYS: i64 = -1000;
+const KVM_EINVAL: i64 = -22;
+
+/// This CPUID returns the signature and can be used to determine if VM is running under pKVM, KVM
+/// or not.
+pub const KVM_CPUID_SIGNATURE: u32 = 0x40000000;
+
+/// Error from a KVM HVC call.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum KvmError {
+ /// The call is not supported by the implementation.
+ NotSupported,
+ /// One of the call parameters has a non-supported value.
+ InvalidParameter,
+ /// There was an unexpected return value.
+ Unknown(i64),
+}
+
+impl From<i64> for KvmError {
+ fn from(value: i64) -> Self {
+ match value {
+ KVM_ENOSYS => KvmError::NotSupported,
+ KVM_EINVAL => KvmError::InvalidParameter,
+ _ => KvmError::Unknown(value),
+ }
+ }
+}
+
+impl From<i32> for KvmError {
+ fn from(value: i32) -> Self {
+ i64::from(value).into()
+ }
+}
+
+impl Display for KvmError {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ match self {
+ Self::NotSupported => write!(f, "KVM call not supported"),
+ Self::InvalidParameter => write!(f, "KVM call received non-supported value"),
+ Self::Unknown(e) => write!(f, "Unknown return value from KVM {} ({0:#x})", e),
+ }
+ }
+}
+
+pub(super) struct RegularKvmHypervisor;
+
+impl RegularKvmHypervisor {
+ pub(super) const CPUID: u128 = u128::from_le_bytes(*b"KVMKVMKVM\0\0\0\0\0\0\0");
+}
+
+impl Hypervisor for RegularKvmHypervisor {}
+
+pub(super) struct ProtectedKvmHypervisor;
+
+impl ProtectedKvmHypervisor {
+ pub(super) const CPUID: u128 = u128::from_le_bytes(*b"PKVMPKVMPKVM\0\0\0\0");
+}
+
+impl Hypervisor for ProtectedKvmHypervisor {
+ fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
+ Some(self)
+ }
+}
+
+macro_rules! vmcall {
+ ($hypcall:expr, $base:expr, $size:expr) => {{
+ let ret;
+ // SAFETY:
+ // Any undeclared register aren't clobbered except rbx but rbx value is restored at the end
+ // of the asm block.
+ unsafe {
+ core::arch::asm!(
+ "xchg %rbx, {0:r}",
+ "vmcall",
+ "xchg %rbx, {0:r}",
+ in(reg) $base,
+ inout("rax") $hypcall => ret,
+ in("rcx") $size,
+ options(att_syntax, nomem));
+ };
+ ret
+ }};
+}
+
+macro_rules! cpuid {
+ ($hypcall:expr) => {{
+ let ret_1: u32;
+ let ret_2: u32;
+ let ret_3: u32;
+ // SAFETY:
+ // Any undeclared register aren't clobbered except rbx but rbx value is restored at the end
+ // of the asm block.
+ unsafe {
+ // The argument for cpuid is passed via rax and in case of KVM_CPUID_SIGNATURE returned
+ // via rbx, rcx and rdx. Ideally using named arguments in inline asm for rbx would be
+ // much more straightforward but when rbx is directly used LLVM complains that: error:
+ // cannot use register `bx`: rbx is used internally by LLVM and cannot be used as an
+ // operand for inline asm
+ //
+ // Therefore use temp register to store rbx content and restore it back after cpuid
+ // call.
+ core::arch::asm!(
+ "xchg %rbx, {0:r}",
+ "cpuid",
+ "xchg %rbx, {0:r}",
+ out(reg) ret_1, in("eax") $hypcall, out("rcx") ret_2, out ("rdx") ret_3,
+ options(att_syntax, nomem));
+ };
+ ((ret_3 as u128) << 64) | ((ret_2 as u128) << 32) | (ret_1 as u128)
+ }};
+}
+
+impl MemSharingHypervisor for ProtectedKvmHypervisor {
+ fn share(&self, base_ipa: u64) -> Result<()> {
+ let ret: u32 = vmcall!(PKVM_GHC_SHARE_MEM, base_ipa, SIZE_4KB);
+
+ if ret != 0 {
+ return Err(Error::KvmError(KvmError::from(ret as i32), PKVM_GHC_SHARE_MEM));
+ }
+
+ Ok(())
+ }
+
+ fn unshare(&self, base_ipa: u64) -> Result<()> {
+ let ret: u32 = vmcall!(PKVM_GHC_UNSHARE_MEM, base_ipa, SIZE_4KB);
+ if ret != 0 {
+ return Err(Error::KvmError(KvmError::from(ret as i32), PKVM_GHC_UNSHARE_MEM));
+ }
+
+ Ok(())
+ }
+
+ fn granule(&self) -> Result<usize> {
+ Ok(SIZE_4KB)
+ }
+}
+
+use crate::hypervisor::HypervisorBackend;
+
+pub(crate) fn determine_hyp_type() -> Result<HypervisorBackend> {
+ let cpuid: u128 = cpuid!(KVM_CPUID_SIGNATURE);
+
+ match cpuid {
+ RegularKvmHypervisor::CPUID => Ok(HypervisorBackend::RegularKvm),
+ ProtectedKvmHypervisor::CPUID => Ok(HypervisorBackend::ProtectedKvm),
+ c => Err(Error::UnsupportedHypervisor(c)),
+ }
+}
diff --git a/libs/libhypervisor_backends/src/mem.rs b/libs/libhypervisor_backends/src/mem.rs
index ff65c49..9f7eafc 100644
--- a/libs/libhypervisor_backends/src/mem.rs
+++ b/libs/libhypervisor_backends/src/mem.rs
@@ -15,6 +15,7 @@
/// The size of a 4KB memory in bytes.
pub const SIZE_4KB: usize = 4 << 10;
+#[cfg(target_arch = "aarch64")]
/// Computes the largest multiple of the provided alignment smaller or equal to the address.
///
/// Note: the result is undefined if alignment isn't a power of two.
@@ -22,6 +23,7 @@
addr & !(alignment - 1)
}
+#[cfg(target_arch = "aarch64")]
/// Computes the address of the 4KiB page containing a given address.
pub const fn page_4kb_of(addr: usize) -> usize {
unchecked_align_down(addr, SIZE_4KB)
diff --git a/libs/libvmbase/src/fdt/pci.rs b/libs/libvmbase/src/fdt/pci.rs
index 44ad455..fcaa806 100644
--- a/libs/libvmbase/src/fdt/pci.rs
+++ b/libs/libvmbase/src/fdt/pci.rs
@@ -14,11 +14,11 @@
//! Library for working with (VirtIO) PCI devices discovered from a device tree.
-use core::{ffi::CStr, ops::Range};
+use core::ops::Range;
use libfdt::{AddressRange, Fdt, FdtError, FdtNode};
use log::debug;
use thiserror::Error;
-use virtio_drivers::transport::pci::bus::{Cam, PciRoot};
+use virtio_drivers::transport::pci::bus::{Cam, ConfigurationAccess, MmioCam, PciRoot};
/// PCI MMIO configuration region size.
const PCI_CFG_SIZE: usize = 0x100_0000;
@@ -94,16 +94,16 @@
/// To prevent concurrent access, only one `PciRoot` should exist in the program. Thus this
/// method must only be called once, and there must be no other `PciRoot` constructed using the
/// same CAM.
- pub unsafe fn make_pci_root(&self) -> PciRoot {
+ pub unsafe fn make_pci_root(&self) -> PciRoot<impl ConfigurationAccess> {
// SAFETY: We trust that the FDT gave us a valid MMIO base address for the CAM. The caller
// guarantees to only call us once, so there are no other references to it.
- unsafe { PciRoot::new(self.cam_range.start as *mut u8, Cam::MmioCam) }
+ PciRoot::new(unsafe { MmioCam::new(self.cam_range.start as *mut u8, Cam::MmioCam) })
}
}
/// Finds an FDT node with compatible=pci-host-cam-generic.
fn pci_node(fdt: &Fdt) -> Result<FdtNode, PciError> {
- fdt.compatible_nodes(CStr::from_bytes_with_nul(b"pci-host-cam-generic\0").unwrap())
+ fdt.compatible_nodes(c"pci-host-cam-generic")
.map_err(PciError::FdtErrorPci)?
.next()
.ok_or(PciError::FdtNoPci)
diff --git a/libs/libvmbase/src/virtio/pci.rs b/libs/libvmbase/src/virtio/pci.rs
index ec89b6b..c2e3301 100644
--- a/libs/libvmbase/src/virtio/pci.rs
+++ b/libs/libvmbase/src/virtio/pci.rs
@@ -26,7 +26,7 @@
use virtio_drivers::{
device::{blk, socket},
transport::pci::{
- bus::{BusDeviceIterator, PciRoot},
+ bus::{BusDeviceIterator, ConfigurationAccess, PciRoot},
virtio_device_type, PciTransport,
},
Hal,
@@ -66,7 +66,7 @@
/// 3. Creates and returns a `PciRoot`.
///
/// This must only be called once and after having switched to the dynamic page tables.
-pub fn initialize(pci_info: PciInfo) -> Result<PciRoot, PciError> {
+pub fn initialize(pci_info: PciInfo) -> Result<PciRoot<impl ConfigurationAccess>, PciError> {
PCI_INFO.set(Box::new(pci_info.clone())).map_err(|_| PciError::DuplicateInitialization)?;
let cam_start = pci_info.cam_range.start;
@@ -90,21 +90,21 @@
pub type VirtIOSocket<T> = socket::VirtIOSocket<T, PciTransport>;
/// An iterator that iterates over the PCI transport for each device.
-pub struct PciTransportIterator<'a, T: Hal> {
- pci_root: &'a mut PciRoot,
- bus: BusDeviceIterator,
+pub struct PciTransportIterator<'a, T: Hal, C: ConfigurationAccess> {
+ pci_root: &'a mut PciRoot<C>,
+ bus: BusDeviceIterator<C>,
_hal: PhantomData<T>,
}
-impl<'a, T: Hal> PciTransportIterator<'a, T> {
+impl<'a, T: Hal, C: ConfigurationAccess> PciTransportIterator<'a, T, C> {
/// Creates a new iterator.
- pub fn new(pci_root: &'a mut PciRoot) -> Self {
+ pub fn new(pci_root: &'a mut PciRoot<C>) -> Self {
let bus = pci_root.enumerate_bus(0);
Self { pci_root, bus, _hal: PhantomData }
}
}
-impl<'a, T: Hal> Iterator for PciTransportIterator<'a, T> {
+impl<T: Hal, C: ConfigurationAccess> Iterator for PciTransportIterator<'_, T, C> {
type Item = PciTransport;
fn next(&mut self) -> Option<Self::Item> {
@@ -121,7 +121,7 @@
};
debug!(" VirtIO {:?}", virtio_type);
- return PciTransport::new::<T>(self.pci_root, device_function).ok();
+ return PciTransport::new::<T, C>(self.pci_root, device_function).ok();
}
}
}
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index bf0afa6..aa69eec 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -160,9 +160,9 @@
.arg("--ignore-path-value")
.arg("/avf/untrusted/instance-id")
.arg("--ignore-path-value")
- .arg("/chosen/linuxinitrd-start")
+ .arg("/chosen/linux,initrd-start")
.arg("--ignore-path-value")
- .arg("/chosen/linuxinitrd-end")
+ .arg("/chosen/linux,initrd-end")
.arg("--ignore-path-value")
.arg("/avf/secretkeeper_public_key")
.arg("--ignore-path")
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 6d7c25e..fa2ff8e 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -39,7 +39,6 @@
":microdroid_general_sepolicy.conf",
":test.com.android.virt.pem",
":test2.com.android.virt.pem",
- "java/**/goldens/dt_dump_*",
]
BINS = [
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index e8673ce..7864f3f 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -1422,138 +1422,6 @@
}
}
- @Test
- @Parameters(method = "osVersions")
- @TestCaseName("{method}_os_{0}")
- @CddTest
- public void microdroidDeviceTreeCompat(String os) throws Exception {
- assumeArm64Supported();
- final String configPath = "assets/vm_config.json";
- // Preconditions
- assumeKernelSupported(os);
- int mem_size = 256;
- assertTrue("Memory size too small", mem_size >= minMemorySize());
-
- // Start the VM with the dump DT option.
- mMicrodroidDevice =
- MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel(DEBUG_LEVEL_FULL)
- .memoryMib(mem_size)
- .cpuTopology("one_cpu")
- .protectedVm(false)
- .os(SUPPORTED_OSES.get(os))
- .name("test_device_tree")
- .dumpDt("/data/local/tmp/dump_dt.dtb")
- .build(getAndroidDevice());
- assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT)).isTrue();
-
- File goldenDt = findTestFile("dt_dump_golden.dts");
- testGoldenDeviceTree(goldenDt.getAbsolutePath());
- }
-
- @Test
- @Parameters(method = "osVersions")
- @TestCaseName("{method}_os_{0}")
- @CddTest
- public void microdroidProtectedDeviceTreeCompat(String os) throws Exception {
- assumeArm64Supported();
- final String configPath = "assets/vm_config.json";
- // Preconditions
- assumeKernelSupported(os);
- assumeVmTypeSupported(os, true);
- int mem_size = 256;
- assertTrue("Memory size too small", mem_size >= minMemorySize());
-
- // Start the VM with the dump DT option.
- mMicrodroidDevice =
- MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel(DEBUG_LEVEL_FULL)
- .memoryMib(mem_size)
- .cpuTopology("one_cpu")
- .protectedVm(true)
- .os(SUPPORTED_OSES.get(os))
- .name("test_device_tree")
- .dumpDt("/data/local/tmp/dump_dt.dtb")
- .build(getAndroidDevice());
- assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT)).isTrue();
-
- File goldenDt = findTestFile("dt_dump_protected_golden.dts");
- testGoldenDeviceTree(goldenDt.getAbsolutePath());
- }
-
- private void testGoldenDeviceTree(String goldenDt) throws Exception {
- // Pull the device tree to host.
- TestDevice device = getAndroidDevice();
- boolean disableRoot = !device.isAdbRoot();
- device.enableAdbRoot();
- assumeTrue("adb root is not enabled", device.isAdbRoot());
-
- // Pull DT from device
- File dtb_from_device = device.pullFile("/data/local/tmp/dump_dt.dtb");
- if (disableRoot) {
- device.disableAdbRoot();
- }
-
- File dtc = findTestFile("dtc");
-
- // Create temp file for Device tree conversion
- File dt_dump_dts = File.createTempFile("dt_dump", "dts");
- dt_dump_dts.delete();
- String dt_dump_dts_path = dt_dump_dts.getAbsolutePath();
- // Convert DT to text format.
- CommandResult dtb_to_dts =
- RunUtil.getDefault()
- .runTimedCmd(
- 3000,
- dtc.getAbsolutePath(),
- "-I",
- "dtb",
- "-O",
- "dts",
- "-qqq",
- "-f",
- "-s",
- "-o",
- dt_dump_dts_path,
- dtb_from_device.getAbsolutePath());
- assertTrue(
- "result convert stderr: " + dtb_to_dts.getStderr(),
- dtb_to_dts.getStderr().trim().isEmpty());
- assertTrue(
- "result convert stdout: " + dtb_to_dts.getStdout(),
- dtb_to_dts.getStdout().trim().isEmpty());
-
- // Diff device's DT with the golden DT.
- CommandResult result_compare =
- RunUtil.getDefault()
- .runTimedCmd(
- 3000,
- "diff",
- "-u",
- "-w",
- "-I",
- "kaslr-seed",
- "-I",
- "instance-id",
- "-I",
- "rng-seed",
- "-I",
- "linux,initrd-end",
- "-I",
- "secretkeeper_public_key",
- "-I",
- "interrupt-map",
- dt_dump_dts_path,
- goldenDt);
-
- assertTrue(
- "result compare stderr: " + result_compare.getStderr(),
- result_compare.getStderr().trim().isEmpty());
- assertTrue(
- "result compare stdout: " + result_compare.getStdout(),
- result_compare.getStdout().trim().isEmpty());
- }
-
@Before
public void setUp() throws Exception {
assumeDeviceIsCapable(getDevice());
diff --git a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts
deleted file mode 100644
index de9f7c5..0000000
--- a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts
+++ /dev/null
@@ -1,145 +0,0 @@
-/dts-v1/;
-
-/ {
- #address-cells = <0x02>;
- #size-cells = <0x02>;
- compatible = "linux,dummy-virt";
- interrupt-parent = <0x01>;
- name = "reference";
-
- U6_16550A@2e8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x02 0x01>;
- reg = <0x00 0x2e8 0x00 0x08>;
- };
-
- U6_16550A@2f8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x02 0x01>;
- reg = <0x00 0x2f8 0x00 0x08>;
- };
-
- U6_16550A@3e8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x00 0x01>;
- reg = <0x00 0x3e8 0x00 0x08>;
- };
-
- U6_16550A@3f8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x00 0x01>;
- reg = <0x00 0x3f8 0x00 0x08>;
- };
-
- __symbols__ {
- intc = "/intc";
- };
-
- avf {
- secretkeeper_public_key = [];
-
- untrusted {
- defer-rollback-protection;
- instance-id = <0xf145d4f8 0x15f03952 0x5af249aa 0xfead94d8 0xb9f05746 0xd9163f48 0x7251b67b 0xe117409e 0x2b14dfa5 0xcaa8caf7 0x14176d2d 0xf88cc94b 0xeed4a59d 0x9a2d8fe5 0x5ac590f1 0xbb6c96f5>;
- };
- };
-
- chosen {
- bootargs = "panic=-1 crashkernel=17M earlycon=uart8250,mmio,0x3f8 keep_bootcon";
- kaslr-seed = <>;
- linux,initrd-end = <0x81200360>;
- linux,initrd-start = <0x81000000>;
- linux,pci-probe-only = <0x01>;
- rng-seed = <>;
- stdout-path = "/U6_16550A@3f8";
- };
-
- config {
- kernel-address = <0x80000000>;
- kernel-size = <0xc91000>;
- };
-
- cpufreq {
- compatible = "virtual,kvm-cpufreq";
- };
-
- cpus {
- #address-cells = <0x01>;
- #size-cells = <0x00>;
-
- cpu@0 {
- compatible = "arm,armv8";
- device_type = "cpu";
- phandle = <0x100>;
- reg = <0x00>;
- };
- };
-
- intc {
- #address-cells = <0x02>;
- #interrupt-cells = <0x03>;
- #size-cells = <0x02>;
- compatible = "arm,gic-v3";
- interrupt-controller;
- phandle = <0x01>;
- reg = <0x00 0x3fff0000 0x00 0x10000 0x00 0x3ffd0000 0x00 0x20000>;
- };
-
- memory {
- device_type = "memory";
- reg = <0x00 0x80000000 0x00 0x10000000>;
- };
-
- pci {
- #address-cells = <0x03>;
- #interrupt-cells = <0x01>;
- #size-cells = <0x02>;
- bus-range = <0x00 0x00>;
- compatible = "pci-host-cam-generic";
- device_type = "pci";
- dma-coherent;
- interrupt-map = <0x800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x04 0x04 0x1000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x05 0x04 0x1800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x06 0x04 0x2000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x07 0x04 0x2800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x08 0x04 0x3000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x09 0x04 0x3800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0a 0x04 0x4000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0b 0x04 0x4800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0c 0x04>;
- interrupt-map-mask = <0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07>;
- ranges = <0x3000000 0x00 0x70000000 0x00 0x70000000 0x00 0x2000000 0x43000000 0x00 0x90800000 0x00 0x90800000 0xff 0x6f800000>;
- reg = <0x00 0x72000000 0x00 0x1000000>;
- };
-
- pclk@3M {
- #clock-cells = <0x00>;
- clock-frequency = <0x2fefd8>;
- compatible = "fixed-clock";
- phandle = <0x18>;
- };
-
- psci {
- compatible = "arm,psci-1.0\0arm,psci-0.2";
- method = "hvc";
- };
-
- rtc@2000 {
- arm,primecell-periphid = <0x41030>;
- clock-names = "apb_pclk";
- clocks = <0x18>;
- compatible = "arm,primecell";
- interrupts = <0x00 0x01 0x04>;
- reg = <0x00 0x2000 0x00 0x1000>;
- };
-
- timer {
- always-on;
- compatible = "arm,armv8-timer";
- interrupts = <0x01 0x0d 0x108 0x01 0x0e 0x108 0x01 0x0b 0x108 0x01 0x0a 0x108>;
- };
-
- vmwdt@3000 {
- clock-frequency = <0x02>;
- compatible = "qemu,vcpu-stall-detector";
- interrupts = <0x01 0x0f 0x101>;
- reg = <0x00 0x3000 0x00 0x1000>;
- timeout-sec = <0x0a>;
- };
-};
diff --git a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts
deleted file mode 100644
index f09e4ff..0000000
--- a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts
+++ /dev/null
@@ -1,159 +0,0 @@
-/dts-v1/;
-
-/ {
- #address-cells = <0x02>;
- #size-cells = <0x02>;
- compatible = "linux,dummy-virt";
- interrupt-parent = <0x01>;
- name = "reference";
-
- U6_16550A@2e8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x02 0x01>;
- reg = <0x00 0x2e8 0x00 0x08>;
- };
-
- U6_16550A@2f8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x02 0x01>;
- reg = <0x00 0x2f8 0x00 0x08>;
- };
-
- U6_16550A@3e8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x00 0x01>;
- reg = <0x00 0x3e8 0x00 0x08>;
- };
-
- U6_16550A@3f8 {
- clock-frequency = <0x1c2000>;
- compatible = "ns16550a";
- interrupts = <0x00 0x00 0x01>;
- reg = <0x00 0x3f8 0x00 0x08>;
- };
-
- __symbols__ {
- intc = "/intc";
- };
-
- avf {
- secretkeeper_public_key = [];
-
- untrusted {
- defer-rollback-protection;
- instance-id = <0x4d482941 0x27228238 0x11d7b28 0xaeed3076 0x88eb3fcb 0x2b9de301 0x57ff8977 0xaf8c24b6 0x55466af4 0x23beed37 0x2f976083 0xe630eb28 0x1edbc491 0xa8300897 0xeb3e9f76 0x21ea9284>;
- };
- };
-
- chosen {
- bootargs = "panic=-1 crashkernel=31M earlycon=uart8250,mmio,0x3f8 keep_bootcon";
- kaslr-seed = <>;
- linux,initrd-end = <0x81202104>;
- linux,initrd-start = <0x81000000>;
- linux,pci-probe-only = <0x01>;
- rng-seed = <>;
- stdout-path = "/U6_16550A@3f8";
- };
-
- config {
- kernel-address = <0x80000000>;
- kernel-size = <0xc91000>;
- };
-
- cpufreq {
- compatible = "virtual,kvm-cpufreq";
- };
-
- cpus {
- #address-cells = <0x01>;
- #size-cells = <0x00>;
-
- cpu@0 {
- compatible = "arm,armv8";
- device_type = "cpu";
- phandle = <0x100>;
- reg = <0x00>;
- };
- };
-
- intc {
- #address-cells = <0x02>;
- #interrupt-cells = <0x03>;
- #size-cells = <0x02>;
- compatible = "arm,gic-v3";
- interrupt-controller;
- phandle = <0x01>;
- reg = <0x00 0x3fff0000 0x00 0x10000 0x00 0x3ffd0000 0x00 0x20000>;
- };
-
- memory {
- device_type = "memory";
- reg = <0x00 0x80000000 0x00 0x10e00000>;
- };
-
- pci {
- #address-cells = <0x03>;
- #interrupt-cells = <0x01>;
- #size-cells = <0x02>;
- bus-range = <0x00 0x00>;
- compatible = "pci-host-cam-generic";
- device_type = "pci";
- dma-coherent;
- interrupt-map = <0x800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x04 0x04 0x1000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x05 0x04 0x1800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x06 0x04 0x2000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x07 0x04 0x2800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x08 0x04 0x3000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x09 0x04 0x3800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0a 0x04 0x4000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x0b 0x04>;
- interrupt-map-mask = <0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07 0xf800 0x00 0x00 0x07>;
- memory-region = <0x02>;
- ranges = <0x3000000 0x00 0x70000000 0x00 0x70000000 0x00 0x2000000 0x43000000 0x00 0x91600000 0x00 0x91600000 0xff 0x6ea00000>;
- reg = <0x00 0x72000000 0x00 0x1000000>;
- };
-
- pclk@3M {
- #clock-cells = <0x00>;
- clock-frequency = <0x2fefd8>;
- compatible = "fixed-clock";
- phandle = <0x18>;
- };
-
- psci {
- compatible = "arm,psci-1.0\0arm,psci-0.2";
- method = "hvc";
- };
-
- reserved-memory {
- #address-cells = <0x02>;
- #size-cells = <0x02>;
- ranges;
-
- restricted_dma_reserved {
- alignment = <0x00 0x1000>;
- compatible = "restricted-dma-pool";
- phandle = <0x02>;
- size = <0x00 0xe00000>;
- };
- };
-
- rtc@2000 {
- arm,primecell-periphid = <0x41030>;
- clock-names = "apb_pclk";
- clocks = <0x18>;
- compatible = "arm,primecell";
- interrupts = <0x00 0x01 0x04>;
- reg = <0x00 0x2000 0x00 0x1000>;
- };
-
- timer {
- always-on;
- compatible = "arm,armv8-timer";
- interrupts = <0x01 0x0d 0x108 0x01 0x0e 0x108 0x01 0x0b 0x108 0x01 0x0a 0x108>;
- };
-
- vmwdt@3000 {
- clock-frequency = <0x02>;
- compatible = "qemu,vcpu-stall-detector";
- interrupts = <0x01 0x0f 0x101>;
- reg = <0x00 0x3000 0x00 0x1000>;
- timeout-sec = <0x0a>;
- };
-};