Merge "Restart shutdown_runner in Linux VM on failure" into main
diff --git a/android/virtmgr/fsfdt/Android.bp b/android/virtmgr/fsfdt/Android.bp
index 1d03522..64a253d 100644
--- a/android/virtmgr/fsfdt/Android.bp
+++ b/android/virtmgr/fsfdt/Android.bp
@@ -28,12 +28,12 @@
"liblibfdt",
"libanyhow",
],
- apex_available: ["com.android.virt"],
}
rust_library_rlib {
name: "libfsfdt",
defaults: ["libfsfdt_default"],
+ apex_available: ["com.android.virt"],
}
rust_test {
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 0c5480b..6aecc75 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -425,6 +425,11 @@
Some(path) => path,
None => return Ok("system".to_owned()),
};
+ if path.starts_with("/system/system_ext/") {
+ return Ok("system_ext".to_owned());
+ } else if path.starts_with("/system/product/") {
+ return Ok("product".to_owned());
+ }
let mut components = path.components();
match components.nth(1) {
Some(std::path::Component::Normal(partition)) => {
@@ -482,7 +487,10 @@
.or_service_specific_exception(-1)
}
};
- if Path::new(&early_vm.path) != calling_exe_path {
+ let expected_exe_path = Path::new(&early_vm.path);
+ if expected_exe_path != calling_exe_path
+ && Path::new("/system").join(expected_exe_path) != calling_exe_path
+ {
return Err(anyhow!(
"VM '{name}' in partition '{calling_partition}' must be created with '{}', not '{}'",
&early_vm.path,
@@ -802,6 +810,25 @@
let detect_hangup = is_app_config && gdb_port.is_none();
+ let custom_memory_backing_files = config
+ .customMemoryBackingFiles
+ .iter()
+ .map(|memory_backing_file| {
+ Ok((
+ clone_file(
+ memory_backing_file
+ .file
+ .as_ref()
+ .context("missing CustomMemoryBackingFile FD")
+ .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?,
+ )?
+ .into(),
+ memory_backing_file.rangeStart as u64,
+ memory_backing_file.size as u64,
+ ))
+ })
+ .collect::<binder::Result<_>>()?;
+
// Actually start the VM.
let crosvm_config = CrosvmConfig {
cid,
@@ -846,6 +873,7 @@
dump_dt_fd,
enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
instance_id,
+ custom_memory_backing_files,
};
let instance = Arc::new(
VmInstance::new(
@@ -2635,6 +2663,22 @@
}
#[test]
+ fn test_symlink_to_system_ext_supported() -> Result<()> {
+ let link_path = Path::new("/system/system_ext/file");
+ let partition = find_partition(Some(link_path)).unwrap();
+ assert_eq!("system_ext", partition);
+ Ok(())
+ }
+
+ #[test]
+ fn test_symlink_to_product_supported() -> Result<()> {
+ let link_path = Path::new("/system/product/file");
+ let partition = find_partition(Some(link_path)).unwrap();
+ assert_eq!("product", partition);
+ Ok(())
+ }
+
+ #[test]
fn test_duplicated_early_vms() -> Result<()> {
let tmp_dir = tempfile::TempDir::new()?;
let tmp_dir_path = tmp_dir.path().to_owned();
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index bb7712e..8500421 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -140,6 +140,8 @@
pub dump_dt_fd: Option<File>,
pub enable_hypervisor_specific_auth_method: bool,
pub instance_id: [u8; 64],
+ // (memfd, guest address, size)
+ pub custom_memory_backing_files: Vec<(OwnedFd, u64, u64)>,
}
#[derive(Debug)]
@@ -1042,8 +1044,8 @@
// When this mode is enabled, two hypervisor specific IDs are expected to be packed
// into the instance ID. We extract them here and pass along to crosvm so they can be
// given to the hypervisor driver via an ioctl.
- let vm_id = u32::from_le_bytes(config.instance_id[60..64].try_into().unwrap());
- let pas_id = u16::from_le_bytes(config.instance_id[58..60].try_into().unwrap());
+ let pas_id = u32::from_le_bytes(config.instance_id[60..64].try_into().unwrap());
+ let vm_id = u16::from_le_bytes(config.instance_id[58..60].try_into().unwrap());
command.arg("--hypervisor").arg(
format!("gunyah[device=/dev/gunyah,qcom_trusted_vm_id={vm_id},qcom_trusted_vm_pas_id={pas_id}]"),
);
@@ -1370,6 +1372,13 @@
}
}
+ for (fd, addr, size) in config.custom_memory_backing_files {
+ command.arg("--file-backed-mapping").arg(format!(
+ "{},addr={addr:#0x},size={size:#0x},rw,ram",
+ add_preserved_fd(&mut preserved_fds, fd)
+ ));
+ }
+
debug!("Preserving FDs {:?}", preserved_fds);
command.preserved_fds(preserved_fds);
diff --git a/android/virtualizationservice/Android.bp b/android/virtualizationservice/Android.bp
index fb6e39a..6f76510 100644
--- a/android/virtualizationservice/Android.bp
+++ b/android/virtualizationservice/Android.bp
@@ -55,12 +55,12 @@
"libservice_vm_comm",
"libservice_vm_manager",
],
- apex_available: ["com.android.virt"],
}
rust_binary {
name: "virtualizationservice",
defaults: ["virtualizationservice_defaults"],
+ apex_available: ["com.android.virt"],
}
xsd_config {
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/CustomMemoryBackingFile.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/CustomMemoryBackingFile.aidl
new file mode 100644
index 0000000..721ad26
--- /dev/null
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/CustomMemoryBackingFile.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 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.
+ */
+package android.system.virtualizationservice;
+
+/** Custom memfd for a subset of guest memory. */
+parcelable CustomMemoryBackingFile {
+ /** The memfd. */
+ ParcelFileDescriptor file;
+
+ /**
+ * Start of range in guest physical address space.
+ *
+ * The value should be interpreted as an unsigned 64 bit integer.
+ */
+ long rangeStart;
+
+ /**
+ * Size of range in bytes.
+ *
+ * The value should be interpreted as an unsigned 64 bit integer.
+ */
+ long size;
+}
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index a822423..c5fe982 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -18,6 +18,7 @@
import android.system.virtualizationservice.AssignedDevices;
import android.system.virtualizationservice.AudioConfig;
import android.system.virtualizationservice.CpuOptions;
+import android.system.virtualizationservice.CustomMemoryBackingFile;
import android.system.virtualizationservice.DiskImage;
import android.system.virtualizationservice.DisplayConfig;
import android.system.virtualizationservice.GpuConfig;
@@ -123,4 +124,7 @@
* VMs.
*/
boolean enableHypervisorSpecificAuthMethod;
+
+ /** Custom memfds for a subset of guest memory */
+ CustomMemoryBackingFile[] customMemoryBackingFiles;
}
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index eaf2522..a362b8e 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -341,11 +341,10 @@
} else {
None
};
+ let vm = VmInstance::create(service, config, console_out, console_in, log, dump_dt)
+ .context("Failed to create VM")?;
let callback = Box::new(Callback {});
- let vm =
- VmInstance::create(service, config, console_out, console_in, log, dump_dt, Some(callback))
- .context("Failed to create VM")?;
- vm.start().context("Failed to start VM")?;
+ vm.start(Some(callback)).context("Failed to start VM")?;
let debug_level = get_debug_level(config).unwrap_or(DebugLevel::NONE);
diff --git a/guest/authfs/Android.bp b/guest/authfs/Android.bp
index 28e0f4a..6c229b6 100644
--- a/guest/authfs/Android.bp
+++ b/guest/authfs/Android.bp
@@ -26,13 +26,12 @@
"libthiserror",
],
prefer_rlib: true,
- target: {
- darwin: {
+ multilib: {
+ lib32: {
enabled: false,
},
},
defaults: [
- "crosvm_defaults",
"avf_build_flags_rust",
],
}
@@ -47,8 +46,4 @@
rust_binary {
name: "authfs",
defaults: ["authfs_defaults"],
- // //apex_available:platform is necessary here to counteract the
- // com.android.virt in crosvm_defaults and make authfs available
- // to the platform so it can be embedded in the microdroid image.
- apex_available: ["//apex_available:platform"],
}
diff --git a/guest/compos_key_helper/Android.bp b/guest/compos_key_helper/Android.bp
index 4d86780..0cd4c33 100644
--- a/guest/compos_key_helper/Android.bp
+++ b/guest/compos_key_helper/Android.bp
@@ -5,7 +5,6 @@
cc_defaults {
name: "compos_key_defaults",
defaults: ["avf_build_flags_cc"],
- apex_available: ["com.android.compos"],
shared_libs: [
"libbase",
@@ -18,6 +17,7 @@
defaults: ["compos_key_defaults"],
srcs: ["compos_key.cpp"],
export_include_dirs: ["."],
+ apex_available: ["com.android.compos"],
}
cc_binary {
@@ -33,6 +33,7 @@
"libvm_payload#current",
"libbinder_ndk",
],
+ apex_available: ["com.android.compos"],
}
cc_test {
diff --git a/guest/pvmfw/avb/Android.bp b/guest/pvmfw/avb/Android.bp
index 0294322..141c1d2 100644
--- a/guest/pvmfw/avb/Android.bp
+++ b/guest/pvmfw/avb/Android.bp
@@ -33,7 +33,7 @@
":microdroid_kernel_signed",
":microdroid_initrd_normal",
":microdroid_initrd_debuggable",
- ":trusty_security_vm_signed",
+ ":trusty_test_vm_signed_bin",
":test_image_with_one_hashdesc",
":test_image_with_non_initrd_hashdesc",
":test_image_with_initrd_and_non_initrd_desc",
diff --git a/guest/pvmfw/avb/tests/api_test.rs b/guest/pvmfw/avb/tests/api_test.rs
index df33830..3027c47 100644
--- a/guest/pvmfw/avb/tests/api_test.rs
+++ b/guest/pvmfw/avb/tests/api_test.rs
@@ -61,11 +61,11 @@
}
#[test]
-fn latest_trusty_security_vm_kernel_passes_verification() -> Result<()> {
- let salt = b"trusty_security_vm_salt";
+fn latest_trusty_test_vm_kernel_passes_verification() -> Result<()> {
+ let salt = b"trusty_test_vm_salt";
let expected_rollback_index = 1;
assert_payload_without_initrd_passes_verification(
- &load_latest_trusty_security_vm_signed_kernel()?,
+ &load_latest_trusty_test_vm_signed_kernel()?,
salt,
expected_rollback_index,
vec![Capability::TrustySecurityVm],
diff --git a/guest/pvmfw/avb/tests/utils.rs b/guest/pvmfw/avb/tests/utils.rs
index e8590ac..7282f3e 100644
--- a/guest/pvmfw/avb/tests/utils.rs
+++ b/guest/pvmfw/avb/tests/utils.rs
@@ -33,7 +33,7 @@
const MICRODROID_KERNEL_IMG_PATH: &str = "microdroid_kernel";
const INITRD_NORMAL_IMG_PATH: &str = "microdroid_initrd_normal.img";
const INITRD_DEBUG_IMG_PATH: &str = "microdroid_initrd_debuggable.img";
-const TRUSTY_SECURITY_VM_KERNEL_IMG_PATH: &str = "trusty_security_vm_signed";
+const TRUSTY_TEST_VM_KERNEL_IMG_PATH: &str = "trusty_test_vm_signed.bin";
const PUBLIC_KEY_RSA4096_PATH: &str = "data/testkey_rsa4096_pub.bin";
pub const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
@@ -61,8 +61,8 @@
Ok(fs::read(MICRODROID_KERNEL_IMG_PATH)?)
}
-pub fn load_latest_trusty_security_vm_signed_kernel() -> Result<Vec<u8>> {
- Ok(fs::read(TRUSTY_SECURITY_VM_KERNEL_IMG_PATH)?)
+pub fn load_latest_trusty_test_vm_signed_kernel() -> Result<Vec<u8>> {
+ Ok(fs::read(TRUSTY_TEST_VM_KERNEL_IMG_PATH)?)
}
pub fn load_latest_initrd_normal() -> Result<Vec<u8>> {
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 2e34ee8..59399b3 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -29,7 +29,6 @@
use core::mem::size_of;
use core::ops::Range;
use hypervisor_backends::get_device_assigner;
-use hypervisor_backends::get_mem_sharer;
use libfdt::AddressRange;
use libfdt::CellIterator;
use libfdt::Fdt;
@@ -79,48 +78,99 @@
}
}
+/// For non-standardly sized integer properties, not following <#size-cells> or <#address-cells>.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+enum DeviceTreeInteger {
+ SingleCell(u32),
+ DoubleCell(u64),
+}
+
+impl DeviceTreeInteger {
+ fn read_from(node: &FdtNode, name: &CStr) -> libfdt::Result<Option<Self>> {
+ if let Some(bytes) = node.getprop(name)? {
+ Ok(Some(Self::from_bytes(bytes).ok_or(FdtError::BadValue)?))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn from_bytes(bytes: &[u8]) -> Option<Self> {
+ if let Some(val) = bytes.try_into().ok().map(u32::from_be_bytes) {
+ return Some(Self::SingleCell(val));
+ } else if let Some(val) = bytes.try_into().ok().map(u64::from_be_bytes) {
+ return Some(Self::DoubleCell(val));
+ }
+ None
+ }
+
+ fn write_to(&self, node: &mut FdtNodeMut, name: &CStr) -> libfdt::Result<()> {
+ match self {
+ Self::SingleCell(value) => node.setprop(name, &value.to_be_bytes()),
+ Self::DoubleCell(value) => node.setprop(name, &value.to_be_bytes()),
+ }
+ }
+}
+
+impl From<DeviceTreeInteger> for usize {
+ fn from(i: DeviceTreeInteger) -> Self {
+ match i {
+ DeviceTreeInteger::SingleCell(v) => v.try_into().unwrap(),
+ DeviceTreeInteger::DoubleCell(v) => v.try_into().unwrap(),
+ }
+ }
+}
+
+/// Returns the pair or integers or an error if only one value is present.
+fn read_two_ints(
+ node: &FdtNode,
+ name_a: &CStr,
+ name_b: &CStr,
+) -> libfdt::Result<Option<(DeviceTreeInteger, DeviceTreeInteger)>> {
+ let a = DeviceTreeInteger::read_from(node, name_a)?;
+ let b = DeviceTreeInteger::read_from(node, name_b)?;
+
+ match (a, b) {
+ (Some(a), Some(b)) => Ok(Some((a, b))),
+ (None, None) => Ok(None),
+ _ => Err(FdtError::NotFound),
+ }
+}
+
/// Extract from /config the address range containing the pre-loaded kernel.
///
/// Absence of /config is not an error. However, an error is returned if only one of the two
/// properties is present.
pub fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
- let addr = c"kernel-address";
- let size = c"kernel-size";
-
- if let Some(config) = fdt.node(c"/config")? {
- match (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
- (None, None) => {}
- (Some(addr), Some(size)) => {
- let addr = addr as usize;
- let size = size as usize;
- return Ok(Some(addr..(addr + size)));
- }
- _ => return Err(FdtError::NotFound),
+ if let Some(ref config) = fdt.node(c"/config")? {
+ if let Some((addr, size)) = read_two_ints(config, c"kernel-address", c"kernel-size")? {
+ let addr = usize::from(addr);
+ let size = usize::from(size);
+ return Ok(Some(addr..(addr + size)));
}
}
-
Ok(None)
}
+fn read_initrd_range_props(
+ fdt: &Fdt,
+) -> libfdt::Result<Option<(DeviceTreeInteger, DeviceTreeInteger)>> {
+ if let Some(ref chosen) = fdt.chosen()? {
+ read_two_ints(chosen, c"linux,initrd-start", c"linux,initrd-end")
+ } else {
+ Ok(None)
+ }
+}
+
/// Extract from /chosen the address range containing the pre-loaded ramdisk.
///
/// Absence is not an error as there can be initrd-less VM. However, an error is returned if only
/// one of the two properties is present.
pub fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
- let start = c"linux,initrd-start";
- let end = c"linux,initrd-end";
-
- if let Some(chosen) = fdt.chosen()? {
- match (chosen.getprop_u32(start)?, chosen.getprop_u32(end)?) {
- (None, None) => {}
- (Some(start), Some(end)) => {
- return Ok(Some((start as usize)..(end as usize)));
- }
- _ => return Err(FdtError::NotFound),
- }
+ if let Some((start, end)) = read_initrd_range_props(fdt)? {
+ Ok(Some(usize::from(start)..usize::from(end)))
+ } else {
+ Ok(None)
}
-
- Ok(None)
}
/// Read /avf/untrusted/instance-id, if present.
@@ -141,13 +191,14 @@
}
}
-fn patch_initrd_range(fdt: &mut Fdt, initrd_range: &Range<usize>) -> libfdt::Result<()> {
- let start = u32::try_from(initrd_range.start).unwrap();
- let end = u32::try_from(initrd_range.end).unwrap();
-
+fn patch_initrd_range(
+ fdt: &mut Fdt,
+ start: &DeviceTreeInteger,
+ end: &DeviceTreeInteger,
+) -> libfdt::Result<()> {
let mut node = fdt.chosen_mut()?.ok_or(FdtError::NotFound)?;
- node.setprop(c"linux,initrd-start", &start.to_be_bytes())?;
- node.setprop(c"linux,initrd-end", &end.to_be_bytes())?;
+ start.write_to(&mut node, c"linux,initrd-start")?;
+ end.write_to(&mut node, c"linux,initrd-end")?;
Ok(())
}
@@ -193,6 +244,11 @@
);
}
let base = range.start;
+ if base % alignment != 0 {
+ error!("Memory base address {:#x} is not aligned to {:#x}", base, alignment);
+ return Err(RebootReason::InvalidFdt);
+ }
+ // For simplicity, force a hardcoded memory base, for now.
if base != MEM_START {
error!("Memory base address {:#x} is not {:#x}", base, MEM_START);
return Err(RebootReason::InvalidFdt);
@@ -902,6 +958,10 @@
error!("Invalid swiotlb range: addr:{addr:#x} size:{size:#x}");
return Err(RebootReason::InvalidFdt);
}
+ if (addr % alignment) != 0 {
+ error!("Swiotlb address {:#x} not aligned to {:#x}", addr, alignment);
+ return Err(RebootReason::InvalidFdt);
+ }
}
if let Some(range) = swiotlb_info.fixed_range() {
if !range.is_within(memory) {
@@ -1016,7 +1076,7 @@
#[derive(Debug)]
pub struct DeviceTreeInfo {
- pub initrd_range: Option<Range<usize>>,
+ initrd_range: Option<(DeviceTreeInteger, DeviceTreeInteger)>,
pub memory_range: Range<usize>,
bootargs: Option<CString>,
cpus: ArrayVec<[CpuInfo; DeviceTreeInfo::MAX_CPUS]>,
@@ -1045,6 +1105,7 @@
vm_dtbo: Option<&mut [u8]>,
vm_ref_dt: Option<&[u8]>,
guest_page_size: usize,
+ hyp_page_size: Option<usize>,
) -> Result<DeviceTreeInfo, RebootReason> {
let vm_dtbo = match vm_dtbo {
Some(vm_dtbo) => Some(VmDtbo::from_mut_slice(vm_dtbo).map_err(|e| {
@@ -1054,7 +1115,7 @@
None => None,
};
- let info = parse_device_tree(fdt, vm_dtbo.as_deref(), guest_page_size)?;
+ let info = parse_device_tree(fdt, vm_dtbo.as_deref(), guest_page_size, hyp_page_size)?;
fdt.clone_from(FDT_TEMPLATE).map_err(|e| {
error!("Failed to instantiate FDT from the template DT: {e}");
@@ -1111,13 +1172,15 @@
fdt: &Fdt,
vm_dtbo: Option<&VmDtbo>,
guest_page_size: usize,
+ hyp_page_size: Option<usize>,
) -> Result<DeviceTreeInfo, RebootReason> {
- let initrd_range = read_initrd_range_from(fdt).map_err(|e| {
+ let initrd_range = read_initrd_range_props(fdt).map_err(|e| {
error!("Failed to read initrd range from DT: {e}");
RebootReason::InvalidFdt
})?;
- let memory_alignment = guest_page_size;
+ // Ensure that MMIO_GUARD can't be used to inadvertently map some memory as MMIO.
+ let memory_alignment = max(hyp_page_size, Some(guest_page_size)).unwrap();
let memory_range = read_and_validate_memory_range(fdt, memory_alignment)?;
let bootargs = read_bootargs_from(fdt).map_err(|e| {
@@ -1171,22 +1234,17 @@
error!("Swiotlb info missing from DT");
RebootReason::InvalidFdt
})?;
- let swiotlb_alignment = guest_page_size;
+ // Ensure that MEM_SHARE won't inadvertently map beyond the shared region.
+ let swiotlb_alignment = max(hyp_page_size, Some(guest_page_size)).unwrap();
validate_swiotlb_info(&swiotlb_info, &memory_range, swiotlb_alignment)?;
let device_assignment = if let Some(vm_dtbo) = vm_dtbo {
if let Some(hypervisor) = get_device_assigner() {
- // TODO(ptosi): Cache the (single?) granule once, in vmbase.
- let granule = get_mem_sharer()
- .ok_or_else(|| {
- error!("No MEM_SHARE found during device assignment validation");
- RebootReason::InternalError
- })?
- .granule()
- .map_err(|e| {
- error!("Failed to get granule for device assignment validation: {e}");
- RebootReason::InternalError
- })?;
+ let granule = hyp_page_size.ok_or_else(|| {
+ error!("No granule found during device assignment validation");
+ RebootReason::InternalError
+ })?;
+
DeviceAssignmentInfo::parse(fdt, vm_dtbo, hypervisor, granule).map_err(|e| {
error!("Failed to parse device assignment from DT and VM DTBO: {e}");
RebootReason::InvalidFdt
@@ -1230,8 +1288,8 @@
}
fn patch_device_tree(fdt: &mut Fdt, info: &DeviceTreeInfo) -> Result<(), RebootReason> {
- if let Some(initrd_range) = &info.initrd_range {
- patch_initrd_range(fdt, initrd_range).map_err(|e| {
+ if let Some((start, end)) = &info.initrd_range {
+ patch_initrd_range(fdt, start, end).map_err(|e| {
error!("Failed to patch initrd range to DT: {e}");
RebootReason::InvalidFdt
})?;
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index 9c67be8..9afbcc3 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -41,6 +41,7 @@
use alloc::boxed::Box;
use bssl_avf::Digester;
use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
+use hypervisor_backends::get_mem_sharer;
use libfdt::Fdt;
use log::{debug, error, info, trace, warn};
use pvmfw_avb::verify_payload;
@@ -98,7 +99,17 @@
}
let guest_page_size = verified_boot_data.page_size.unwrap_or(SIZE_4KB);
- let _ = sanitize_device_tree(untrusted_fdt, vm_dtbo, vm_ref_dt, guest_page_size)?;
+ // TODO(ptosi): Cache the (single?) granule once, in vmbase.
+ let hyp_page_size = if let Some(mem_sharer) = get_mem_sharer() {
+ Some(mem_sharer.granule().map_err(|e| {
+ error!("Failed to get granule size: {e}");
+ RebootReason::InternalError
+ })?)
+ } else {
+ None
+ };
+ let _ =
+ sanitize_device_tree(untrusted_fdt, vm_dtbo, vm_ref_dt, guest_page_size, hyp_page_size)?;
let fdt = untrusted_fdt; // DT has now been sanitized.
let next_bcc_size = guest_page_size;
diff --git a/guest/rialto/tests/test.rs b/guest/rialto/tests/test.rs
index d68c568..c650046 100644
--- a/guest/rialto/tests/test.rs
+++ b/guest/rialto/tests/test.rs
@@ -338,7 +338,6 @@
/* consoleIn */ None,
log,
/* dump_dt */ None,
- None,
)
.context("Failed to create VM")
}
diff --git a/guest/trusty/common/Android.bp b/guest/trusty/common/Android.bp
index 0541ed5..d6c524f 100644
--- a/guest/trusty/common/Android.bp
+++ b/guest/trusty/common/Android.bp
@@ -1,7 +1,33 @@
+soong_config_module_type {
+ name: "trusty_vm_prebuilt_etc",
+ module_type: "prebuilt_etc",
+ config_namespace: "trusty_system_vm",
+ bool_variables: [
+ "enabled",
+ "placeholder_trusted_hal",
+ ],
+ properties: ["src"],
+}
+
+soong_config_module_type {
+ name: "trusty_vm_avb_add_hash_footer",
+ module_type: "avb_add_hash_footer",
+ config_namespace: "trusty_system_vm",
+ bool_variables: ["enabled"],
+ properties: ["src"],
+}
+
prebuilt_etc {
name: "early_vms.xml",
- src: "early_vms.xml",
filename: "early_vms.xml",
relative_install_path: "avf",
system_ext_specific: true,
+ enabled: select(soong_config_variable("trusty_system_vm", "enabled"), {
+ true: true,
+ default: false,
+ }),
+ src: select(soong_config_variable("trusty_system_vm", "enabled"), {
+ true: "early_vms.xml",
+ default: ":empty_file",
+ }),
}
diff --git a/guest/trusty/security_vm/TEST_MAPPING b/guest/trusty/security_vm/TEST_MAPPING
index ad7b899..b4d2622 100644
--- a/guest/trusty/security_vm/TEST_MAPPING
+++ b/guest/trusty/security_vm/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "trusty-security_vm-presubmit": [
+ "trusty_security_vm_presubmit": [
],
- "trusty-security_vm-postsubmit": [
+ "trusty_security_vm_postsubmit": [
{
"name": "VtsAidlKeyMintTargetTest"
},
diff --git a/guest/trusty/security_vm/launcher/Android.bp b/guest/trusty/security_vm/launcher/Android.bp
index ff628fd..c70de24 100644
--- a/guest/trusty/security_vm/launcher/Android.bp
+++ b/guest/trusty/security_vm/launcher/Android.bp
@@ -1,3 +1,19 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+prebuilt_etc {
+ name: "trusty_security_vm_launcher.rc",
+ src: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): "security_vm_launcher-arm64.rc",
+ ("android", "x86_64", true): "security_vm_launcher-x86_64.rc",
+ (default, default, default): ":empty_file",
+ }),
+ filename: "trusty_security_vm_launcher.rc",
+ relative_install_path: "init",
+ system_ext_specific: true,
+}
+
rust_binary {
name: "trusty_security_vm_launcher",
crate_name: "trusty_security_vm_launcher",
@@ -13,8 +29,8 @@
bootstrap: true,
apex_available: ["//apex_available:platform"],
system_ext_specific: true,
- enabled: select(release_flag("RELEASE_AVF_ENABLE_EARLY_VM"), {
+ enabled: select(soong_config_variable("trusty_system_vm", "enabled"), {
true: true,
- false: false,
+ default: false,
}),
}
diff --git a/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc b/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc
new file mode 100644
index 0000000..c0e0537
--- /dev/null
+++ b/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc
@@ -0,0 +1,20 @@
+# TODO(b/393848713): use --protected for the vm launcher when issues are fixed
+# TODO(b/393848753): determine whether task_profiles shall be defined
+service trusty_security_vm_launcher /system_ext/bin/trusty_security_vm_launcher \
+--name trusty_security_vm_launcher \
+--kernel /system_ext/etc/vm/trusty_vm/trusty_security_vm.elf \
+--memory-size-mib 32
+ disabled
+ user system
+ group system virtualmachine
+ capabilities IPC_LOCK NET_BIND_SERVICE SYS_RESOURCE SYS_NICE
+ stdio_to_kmsg
+ oneshot
+ # task_profiles MaxPerformance
+
+# Starts the non-secure Trusty VM in /system_ext when the feature is enabled through
+# the system property set in vendor init.
+on init && property:trusty.security_vm.enabled=1
+ setprop trusty.security_vm.nonsecure_vm_ready 1
+ setprop trusty.security_vm.vm_cid 200
+ start trusty_security_vm_launcher
diff --git a/guest/trusty/security_vm/launcher/security_vm_launcher-x86_64.rc b/guest/trusty/security_vm/launcher/security_vm_launcher-x86_64.rc
new file mode 100644
index 0000000..b435309
--- /dev/null
+++ b/guest/trusty/security_vm/launcher/security_vm_launcher-x86_64.rc
@@ -0,0 +1,15 @@
+service trusty_security_vm_launcher /system_ext/bin/trusty_security_vm_launcher \
+--kernel /system_ext/etc/vm/trusty_vm/trusty_security_vm.elf \
+--memory-size-mib 16
+ disabled
+ user system
+ group system virtualmachine
+ capabilities IPC_LOCK NET_BIND_SERVICE SYS_RESOURCE SYS_NICE
+ stdio_to_kmsg
+
+# Starts the non-secure Trusty VM in /system_ext when the feature is enabled through
+# the system property set in vendor init.
+on init && property:trusty.security_vm.enabled=1
+ setprop trusty.security_vm.nonsecure_vm_ready 1
+ setprop trusty.security_vm.vm_cid 200
+ start trusty_security_vm_launcher
diff --git a/guest/trusty/security_vm/launcher/src/main.rs b/guest/trusty/security_vm/launcher/src/main.rs
index 3c8d599..933e4b3 100644
--- a/guest/trusty/security_vm/launcher/src/main.rs
+++ b/guest/trusty/security_vm/launcher/src/main.rs
@@ -102,14 +102,13 @@
None, // console_out
None, // log
None, // dump_dt
- None, // callback
)
.context("Failed to create VM")?;
- vm.start().context("Failed to start VM")?;
+ vm.start(None /* callback */).context("Failed to start VM")?;
- println!("started trusty_security_vm_launcher VM");
+ println!("started {} VM", args.name.to_owned());
let death_reason = vm.wait_for_death();
- eprintln!("trusty_security_vm_launcher ended: {:?}", death_reason);
+ eprintln!("{} ended: {:?}", args.name.to_owned(), death_reason);
// TODO(b/331320802): we may want to use android logger instead of stdio_to_kmsg?
diff --git a/guest/trusty/security_vm/security_vm.mk b/guest/trusty/security_vm/security_vm.mk
new file mode 100644
index 0000000..89c9cdc
--- /dev/null
+++ b/guest/trusty/security_vm/security_vm.mk
@@ -0,0 +1,23 @@
+# Copyright (C) 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.
+
+
+ifeq ($(findstring enabled, $(TRUSTY_SYSTEM_VM)),enabled)
+PRODUCT_PACKAGES += \
+ trusty_security_vm.elf \
+ trusty_security_vm_launcher \
+ trusty_security_vm_launcher.rc \
+ early_vms.xml \
+
+endif
diff --git a/guest/trusty/security_vm/vm/Android.bp b/guest/trusty/security_vm/vm/Android.bp
index ee64095..d823448 100644
--- a/guest/trusty/security_vm/vm/Android.bp
+++ b/guest/trusty/security_vm/vm/Android.bp
@@ -2,32 +2,51 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+soong_config_module_type_import {
+ from: "packages/modules/Virtualization/guest/trusty/common/Android.bp",
+ module_types: ["trusty_vm_avb_add_hash_footer"],
+}
+
+// - Trusty VM payloads on arm64 are pvmfw enabled
+// AVF VM build system uses the raw binary image (:trusty_security_vm_unsigned),
+// adds pvmfw footer and generates a pvmfw-compliant signed elf file)
+// - Trusty VM payload on x86 are for now loaded in Cuttlefish unsigned
+// the unsigned generated elf is used directly by AV
+//
+// see packages/modules/Virtualization/guest/trusty
+
prebuilt_etc {
- name: "lk_trusty.elf",
+ name: "trusty_security_vm.elf",
+ src: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): ":trusty_security_vm_signed",
+ ("android", "x86_64", true): ":trusty_security_vm_unsigned",
+ (default, default, default): ":empty_file",
+ }),
system_ext_specific: true,
relative_install_path: "vm/trusty_vm",
- filename: "lk_trusty.elf",
- arch: {
- x86_64: {
- src: ":trusty_security_vm_signed",
- },
- arm64: {
- src: ":security_vm_elf",
- },
- },
- src: ":empty_file",
+ filename: "trusty_security_vm.elf",
+}
+
+filegroup {
+ name: "trusty_vm_sections.ld",
+ srcs: [
+ "trusty_vm_sections.ld",
+ ],
+ visibility: [
+ "//packages/modules/Virtualization/guest/trusty/test_vm/vm",
+ ],
}
cc_binary {
- name: "security_vm_elf",
+ name: "trusty_security_vm_signed",
srcs: [
- ":security_vm_signed_obj",
+ ":trusty_security_vm_signed_bin_obj",
],
linker_scripts: [
- "security_vm_sections.ld",
+ ":trusty_vm_sections.ld",
],
ldflags: [
- // Prevent the `trusty_security_vm_signed` segment from being garbage collected.
+ // Prevent the `trusty_security_vm_signed_bin_obj` segment from being garbage collected.
"-Wl,--no-gc-sections",
// Prevent the build ID segments from being added, as it would corrupt the integrity
// of the original signed image.
@@ -40,49 +59,48 @@
no_libcrt: true,
static_executable: true,
system_shared_libs: [],
- enabled: false,
- target: {
- android_arm64: {
- enabled: true,
- },
- },
strip: {
none: true,
},
+ enabled: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): true,
+ (default, default, default): false,
+ }),
}
cc_genrule {
name: "security_vm.S",
arch: {
arm64: {
- srcs: [":trusty_security_vm_signed"],
+ srcs: [":trusty_security_vm_signed_bin"],
},
},
out: ["security_vm.S"],
cmd: "(" +
- " echo '.section .security_vm_signed.bin';" +
- " echo '.globl security_vm_signed';" +
- " echo 'security_vm_signed:';" +
+ " echo '.section .vm_payload_signed.bin';" +
+ " echo '.globl vm_payload_signed';" +
+ " echo 'vm_payload_signed:';" +
" echo '.incbin \"'$(in)'\"';" +
") > $(out)",
visibility: ["//visibility:private"],
+ enabled: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): true,
+ (default, default, default): false,
+ }),
}
cc_object {
- name: "security_vm_signed_obj",
+ name: "trusty_security_vm_signed_bin_obj",
srcs: [
":security_vm.S",
],
- static_libs: ["trusty_security_vm_signed"],
crt: false,
system_shared_libs: [],
- enabled: false,
- target: {
- android_arm64: {
- enabled: true,
- },
- },
visibility: ["//visibility:private"],
+ enabled: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): true,
+ (default, default, default): false,
+ }),
}
filegroup {
@@ -95,9 +113,9 @@
TRUSTY_SECURITY_VM_VERSION = 1
-avb_add_hash_footer {
- name: "trusty_security_vm_signed",
- filename: "trusty_security_vm_signed",
+trusty_vm_avb_add_hash_footer {
+ name: "trusty_security_vm_signed_bin",
+ filename: "trusty_security_vm_signed.bin",
partition_name: "boot",
private_key: ":trusty_vm_sign_key",
salt: trusty_security_vm_salt,
@@ -108,29 +126,12 @@
value: "trusty_security_vm",
},
],
- src: ":empty_file",
- enabled: false,
- arch: {
- x86_64: {
- src: ":trusty-lk.elf",
- enabled: true,
- },
- arm64: {
- src: ":trusty_security_vm_unsigned",
- enabled: true,
- },
- },
-}
-
-// TODO(b/379646659): Take the binary generated by trusty instead of extracting
-// it from ELF here.
-raw_binary {
- name: "trusty_security_vm_unsigned",
- src: ":trusty-test-lk.elf",
- enabled: false,
- arch: {
- arm64: {
- enabled: true,
- },
- },
+ src: select(soong_config_variable("trusty_system_vm", "enabled"), {
+ true: ":trusty_security_vm_unsigned",
+ default: ":empty_file",
+ }),
+ enabled: select((os(), arch(), soong_config_variable("trusty_system_vm", "enabled")), {
+ ("android", "arm64", true): true,
+ (default, default, default): false,
+ }),
}
diff --git a/guest/trusty/security_vm/vm/security_vm_sections.ld b/guest/trusty/security_vm/vm/trusty_vm_sections.ld
similarity index 91%
rename from guest/trusty/security_vm/vm/security_vm_sections.ld
rename to guest/trusty/security_vm/vm/trusty_vm_sections.ld
index 63e5f5d..42627da 100644
--- a/guest/trusty/security_vm/vm/security_vm_sections.ld
+++ b/guest/trusty/security_vm/vm/trusty_vm_sections.ld
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-ENTRY(security_vm_signed)
+ENTRY(vm_payload_signed)
SECTIONS
{
. = 0x0;
.text : {
- *(.security_vm_signed.bin)
+ *(.vm_payload_signed.bin)
}
}
diff --git a/guest/trusty/test_vm/Android.bp b/guest/trusty/test_vm/Android.bp
index 498028d..699b673 100644
--- a/guest/trusty/test_vm/Android.bp
+++ b/guest/trusty/test_vm/Android.bp
@@ -17,34 +17,16 @@
default_team: "trendy_team_trusty",
}
-// python -c "import hashlib; print(hashlib.sha256(b'trusty_test_vm_salt').hexdigest())"
-trusty_test_vm_salt = "5ce3eab1a08540e1334c83f54b8608aa6c23feee6939693cac41441449c5a51f"
-
-TRUSTY_TEST_VM_VERSION = 1
-
-avb_add_hash_footer {
- name: "trusty_test_vm_signed",
- filename: "trusty_test_vm_signed",
- partition_name: "boot",
- private_key: ":trusty_vm_sign_key",
- salt: trusty_test_vm_salt,
- rollback_index: TRUSTY_TEST_VM_VERSION,
- src: ":empty_file",
- enabled: false,
- arch: {
- x86_64: {
- src: ":trusty-test-lk.elf",
- enabled: true,
- },
- },
-}
-
prebuilt_etc {
name: "trusty_test_vm_config",
enabled: false,
arch: {
+ arm64: {
+ src: "trusty-test_vm-config-arm64.json",
+ enabled: true,
+ },
x86_64: {
- src: "vm_config_lk_x86_64.json",
+ src: "trusty-test_vm-config-x86_64.json",
enabled: true,
},
},
@@ -55,11 +37,14 @@
name: "trusty_vm_launcher_sh",
enabled: false,
arch: {
+ arm64: {
+ enabled: true,
+ },
x86_64: {
- src: "trusty-vm-launcher.sh",
enabled: true,
},
},
+ src: "trusty-vm-launcher.sh",
filename: "trusty-vm-launcher.sh",
}
@@ -67,20 +52,32 @@
name: "trusty_wait_ready_sh",
enabled: false,
arch: {
+ arm64: {
+ enabled: true,
+ },
x86_64: {
- src: "trusty-wait-ready.sh",
enabled: true,
},
},
+ src: "trusty-wait-ready.sh",
filename: "trusty-wait-ready.sh",
}
sh_test {
name: "TrustyTestVM_UnitTests",
src: "trusty-ut-ctrl.sh",
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ },
+ x86_64: {
+ enabled: true,
+ },
+ },
filename_from_src: true,
data: [
- ":trusty_test_vm_signed",
+ ":trusty_test_vm_elf",
":trusty_test_vm_config",
"trusty-vm-launcher.sh",
"trusty-wait-ready.sh",
@@ -91,10 +88,4 @@
test_suites: [
"general-tests",
],
- enabled: false,
- arch: {
- x86_64: {
- enabled: true,
- },
- },
}
diff --git a/guest/trusty/test_vm/AndroidTest.xml b/guest/trusty/test_vm/AndroidTest.xml
index d8710ab..6fb0879 100644
--- a/guest/trusty/test_vm/AndroidTest.xml
+++ b/guest/trusty/test_vm/AndroidTest.xml
@@ -27,7 +27,7 @@
<option name="push-file" key="trusty-vm-launcher.sh" value="/data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
<option name="push-file" key="trusty-wait-ready.sh" value="/data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
<option name="push-file" key="trusty-test_vm-config.json" value="/data/local/tmp/trusty_test_vm/trusty-test_vm-config.json" />
- <option name="push-file" key="trusty_test_vm_signed" value="/data/local/tmp/trusty_test_vm/trusty_test_vm_signed" />
+ <option name="push-file" key="trusty_test_vm.elf" value="/data/local/tmp/trusty_test_vm/trusty_test_vm.elf" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="throw-if-cmd-fail" value="true" />
diff --git a/guest/trusty/test_vm/TEST_MAPPING b/guest/trusty/test_vm/TEST_MAPPING
index 6f2b56e..aa9d65d 100644
--- a/guest/trusty/test_vm/TEST_MAPPING
+++ b/guest/trusty/test_vm/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "trusty-test_vm-presubmit": [
+ "trusty_test_vm_presubmit": [
],
- "trusty-test_vm-postsubmit": [
+ "trusty_test_vm_postsubmit": [
{
"name": "TrustyTestVM_UnitTests"
}
diff --git a/guest/trusty/test_vm/trusty-test_vm-config-arm64.json b/guest/trusty/test_vm/trusty-test_vm-config-arm64.json
new file mode 100644
index 0000000..18b275e
--- /dev/null
+++ b/guest/trusty/test_vm/trusty-test_vm-config-arm64.json
@@ -0,0 +1,7 @@
+{
+ "name": "trusty_test_vm",
+ "kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm_.elf",
+ "platform_version": "1.0",
+ "memory_mib": 112,
+ "protected": true
+}
diff --git a/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json b/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json
new file mode 100644
index 0000000..d491c3a
--- /dev/null
+++ b/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json
@@ -0,0 +1,6 @@
+{
+ "name": "trusty_test_vm",
+ "kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm.elf",
+ "platform_version": "1.0",
+ "memory_mib": 112
+}
diff --git a/guest/trusty/test_vm/vm/Android.bp b/guest/trusty/test_vm/vm/Android.bp
new file mode 100644
index 0000000..1db9078
--- /dev/null
+++ b/guest/trusty/test_vm/vm/Android.bp
@@ -0,0 +1,119 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+soong_config_module_type_import {
+ from: "packages/modules/Virtualization/guest/trusty/common/Android.bp",
+ module_types: ["trusty_vm_avb_add_hash_footer"],
+}
+
+prebuilt_etc {
+ name: "trusty_test_vm_elf",
+ system_ext_specific: true,
+ relative_install_path: "vm/trusty_vm",
+ filename: "trusty_test_vm.elf",
+ src: select((os(), arch()), {
+ ("android", "arm64"): ":trusty_test_vm_signed",
+ ("android", "x86_64"): ":trusty_test_vm_unsigned",
+ (default, default): ":empty_file",
+ }),
+}
+
+cc_binary {
+ name: "trusty_test_vm_signed",
+ srcs: [
+ ":trusty_test_vm_signed_bin_obj",
+ ],
+ // reuse the common trusty_vm_sections linker script
+ linker_scripts: [
+ ":trusty_vm_sections.ld",
+ ],
+ ldflags: [
+ // Prevent the `trusty_test_vm_signed_bin_obj` segment from being garbage collected.
+ "-Wl,--no-gc-sections",
+ // Prevent the build ID segments from being added, as it would corrupt the integrity
+ // of the original signed image.
+ "-Wl,--build-id=none",
+ // Use a standard page size of 4096, smaller than the default 16384, to avoid padding
+ // with extra bytes.
+ "-Wl,-z,max-page-size=4096",
+ ],
+ nocrt: true,
+ no_libcrt: true,
+ static_executable: true,
+ system_shared_libs: [],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+ strip: {
+ none: true,
+ },
+}
+
+cc_genrule {
+ name: "test_vm.S",
+ enabled: false,
+ arch: {
+ arm64: {
+ srcs: [":trusty_test_vm_signed_bin"],
+ enabled: true,
+ },
+ },
+ out: ["test_vm.S"],
+ cmd: "(" +
+ " echo '.section .vm_payload_signed.bin';" +
+ " echo '.globl vm_payload_signed';" +
+ " echo 'vm_payload_signed:';" +
+ " echo '.incbin \"'$(in)'\"';" +
+ ") > $(out)",
+ visibility: ["//visibility:private"],
+}
+
+cc_object {
+ name: "trusty_test_vm_signed_bin_obj",
+ srcs: [
+ ":test_vm.S",
+ ],
+ crt: false,
+ system_shared_libs: [],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+ visibility: ["//visibility:private"],
+}
+
+// python -c "import hashlib; print(hashlib.sha256(b'trusty_test_vm_salt').hexdigest())"
+trusty_test_vm_salt = "5ce3eab1a08540e1334c83f54b8608aa6c23feee6939693cac41441449c5a51f"
+
+TRUSTY_TEST_VM_VERSION = 1
+
+trusty_vm_avb_add_hash_footer {
+ name: "trusty_test_vm_signed_bin",
+ filename: "trusty_test_vm_signed.bin",
+ partition_name: "boot",
+ private_key: ":trusty_vm_sign_key",
+ salt: trusty_test_vm_salt,
+ rollback_index: TRUSTY_TEST_VM_VERSION,
+ props: [
+ {
+ name: "com.android.virt.cap",
+ value: "trusty_security_vm",
+ },
+ ],
+ src: ":trusty_test_vm_unsigned",
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ },
+ x86_64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/guest/trusty/test_vm/vm_config_lk_x86_64.json b/guest/trusty/test_vm/vm_config_lk_x86_64.json
deleted file mode 100644
index 5effca5..0000000
--- a/guest/trusty/test_vm/vm_config_lk_x86_64.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "trusty_test_vm",
- "kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm_signed",
- "platform_version": "1.0",
- "memory_mib": 112
-}
diff --git a/libs/libavf/include/android/virtualization.h b/libs/libavf/include/android/virtualization.h
index 8d96fac..4bfe47a 100644
--- a/libs/libavf/include/android/virtualization.h
+++ b/libs/libavf/include/android/virtualization.h
@@ -189,7 +189,7 @@
* physical memory.
*
* \param config a virtual machine config object.
- * \param fd a memfd
+ * \param fd a memfd. Ownership is transferred, even if the function is not successful.
* \param rangeStart range start of guest memory addresses
* \param rangeEnd range end of guest memory addresses
*
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 3fa1b75..33bd2d7 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -24,8 +24,9 @@
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
AssignedDevices::AssignedDevices, CpuOptions::CpuOptions,
- CpuOptions::CpuTopology::CpuTopology, DiskImage::DiskImage,
- IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
+ CpuOptions::CpuTopology::CpuTopology, CustomMemoryBackingFile::CustomMemoryBackingFile,
+ DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
+ VirtualMachineConfig::VirtualMachineConfig,
VirtualMachineRawConfig::VirtualMachineRawConfig,
},
binder::{ParcelFileDescriptor, Strong},
@@ -254,18 +255,35 @@
0
}
-/// NOT IMPLEMENTED.
+/// Use the specified fd as the backing memfd for a range of the guest physical memory.
///
-/// # Returns
-/// It always returns `-ENOTSUP`.
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
#[no_mangle]
-pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
- _config: *mut VirtualMachineRawConfig,
- _fd: c_int,
- _range_start: u64,
- _range_end: u64,
+pub unsafe extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
+ config: *mut VirtualMachineRawConfig,
+ fd: c_int,
+ range_start: u64,
+ range_end: u64,
) -> c_int {
- -libc::ENOTSUP
+ // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+ // AVirtualMachineRawConfig_create. It's the only reference to the object.
+ let config = unsafe { &mut *config };
+
+ let Some(file) = get_file_from_fd(fd) else {
+ return -libc::EINVAL;
+ };
+ let Some(size) = range_end.checked_sub(range_start) else {
+ return -libc::EINVAL;
+ };
+ config.customMemoryBackingFiles.push(CustomMemoryBackingFile {
+ file: Some(ParcelFileDescriptor::new(file)),
+ // AIDL doesn't support unsigned ints, so we've got to reinterpret the bytes into a signed
+ // int.
+ rangeStart: range_start as i64,
+ size: size as i64,
+ });
+ 0
}
/// Add device tree overlay blob
@@ -373,7 +391,7 @@
let console_in = get_file_from_fd(console_in_fd);
let log = get_file_from_fd(log_fd);
- match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
+ match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None) {
Ok(vm) => {
// SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
// `vm` is the only reference here and `vm_ptr` takes ownership.
@@ -398,7 +416,7 @@
// SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
// `AVirtualMachine_createRaw`. It's the only reference to the object.
let vm = unsafe { &*vm };
- match vm.start() {
+ match vm.start(None) {
Ok(_) => 0,
Err(e) => {
error!("AVirtualMachine_start failed: {e:?}");
diff --git a/libs/libcompos_common/compos_client.rs b/libs/libcompos_common/compos_client.rs
index a52104d..c48c9f6 100644
--- a/libs/libcompos_common/compos_client.rs
+++ b/libs/libcompos_common/compos_client.rs
@@ -150,19 +150,14 @@
// Let logs go to logcat.
let (console_fd, log_fd) = (None, None);
- let callback = Box::new(Callback {});
let instance = VmInstance::create(
- service,
- &config,
- console_fd,
- /* console_in_fd */ None,
- log_fd,
+ service, &config, console_fd, /* console_in_fd */ None, log_fd,
/* dump_dt */ None,
- Some(callback),
)
.context("Failed to create VM")?;
- instance.start()?;
+ let callback = Box::new(Callback {});
+ instance.start(Some(callback))?;
let ready = instance.wait_until_ready(TIMEOUTS.vm_max_time_to_ready);
if ready == Err(VmWaitError::Finished) && debug_level != DebugLevel::NONE {
diff --git a/libs/libservice_vm_manager/src/lib.rs b/libs/libservice_vm_manager/src/lib.rs
index 667731f..0681a6f 100644
--- a/libs/libservice_vm_manager/src/lib.rs
+++ b/libs/libservice_vm_manager/src/lib.rs
@@ -152,7 +152,7 @@
let vsock_listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, vm_type.port())?;
// Starts the service VM.
- vm.start().context("Failed to start service VM")?;
+ vm.start(None).context("Failed to start service VM")?;
info!("Service VM started");
// Accepts the connection from the service VM.
@@ -246,8 +246,7 @@
let console_in = None;
let log = Some(android_log_fd()?);
let dump_dt = None;
- let callback = None;
- VmInstance::create(service.as_ref(), &config, console_out, console_in, log, dump_dt, callback)
+ VmInstance::create(service.as_ref(), &config, console_out, console_in, log, dump_dt)
.context("Failed to create service VM")
}
diff --git a/libs/libservice_vm_requests/Android.bp b/libs/libservice_vm_requests/Android.bp
index d87b087..4a575b2 100644
--- a/libs/libservice_vm_requests/Android.bp
+++ b/libs/libservice_vm_requests/Android.bp
@@ -9,9 +9,6 @@
defaults: ["avf_build_flags_rust"],
srcs: ["src/lib.rs"],
prefer_rlib: true,
- apex_available: [
- "com.android.virt",
- ],
no_stdlibs: true,
stdlibs: [
"libcore.rust_sysroot",
@@ -37,6 +34,9 @@
rust_library_rlib {
name: "libservice_vm_requests_nostd",
defaults: ["libservice_vm_requests_nostd_defaults"],
+ apex_available: [
+ "com.android.virt",
+ ],
}
rust_test {
diff --git a/libs/libvmclient/src/lib.rs b/libs/libvmclient/src/lib.rs
index 8dd3cd3..2c6abb5 100644
--- a/libs/libvmclient/src/lib.rs
+++ b/libs/libvmclient/src/lib.rs
@@ -209,7 +209,6 @@
console_in: Option<File>,
log: Option<File>,
dump_dt: Option<File>,
- callback: Option<Box<dyn VmCallback + Send + Sync>>,
) -> BinderResult<Self> {
let console_out = console_out.map(ParcelFileDescriptor::new);
let console_in = console_in.map(ParcelFileDescriptor::new);
@@ -226,20 +225,19 @@
let cid = vm.getCid()?;
- // Register callback before starting VM, in case it dies immediately.
let state = Arc::new(Monitor::new(VmState::default()));
- let callback = BnVirtualMachineCallback::new_binder(
- VirtualMachineCallback { state: state.clone(), client_callback: callback },
- BinderFeatures::default(),
- );
- vm.registerCallback(&callback)?;
let death_recipient = wait_for_binder_death(&mut vm.as_binder(), state.clone())?;
Ok(Self { vm, cid, state, _death_recipient: death_recipient })
}
/// Starts the VM.
- pub fn start(&self) -> BinderResult<()> {
+ pub fn start(&self, callback: Option<Box<dyn VmCallback + Send + Sync>>) -> BinderResult<()> {
+ let callback = BnVirtualMachineCallback::new_binder(
+ VirtualMachineCallback { state: self.state.clone(), client_callback: callback },
+ BinderFeatures::default(),
+ );
+ self.vm.registerCallback(&callback)?;
self.vm.start()
}
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index 55c946e..f58a379 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -97,7 +97,6 @@
console_in,
/* log= */ None,
/* dump_dt= */ None,
- None,
)
.context("Failed to create VM")?;
if let Some(pty) = &pty {
@@ -106,7 +105,7 @@
.setHostConsoleName(&pty.follower_name)
.context("Setting host console name")?;
}
- vm_instance.start().context("Starting VM")?;
+ vm_instance.start(None).context("Starting VM")?;
Ok(MicrofuchsiaInstance {
_vm_instance: vm_instance,
diff --git a/tests/authfs/Android.bp b/tests/authfs/Android.bp
index aa814eb..4c44bb3 100644
--- a/tests/authfs/Android.bp
+++ b/tests/authfs/Android.bp
@@ -3,6 +3,7 @@
defaults: ["authfs_defaults"],
test_suites: ["general-tests"],
data: [":authfs_test_files"],
+ apex_available: ["//apex_available:platform"],
}
filegroup {
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index b0cd042..4d09a89 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -118,10 +118,9 @@
/* consoleIn */ None,
None,
Some(dump_dt),
- None,
)
.context("Failed to create VM")?;
- vm.start().context("Failed to start VM")?;
+ vm.start(None).context("Failed to start VM")?;
info!("Started example VM.");
// Wait for VM to finish
diff --git a/tests/early_vm_test/src/main.rs b/tests/early_vm_test/src/main.rs
index a3c80ca..7d630f8 100644
--- a/tests/early_vm_test/src/main.rs
+++ b/tests/early_vm_test/src/main.rs
@@ -96,7 +96,6 @@
None, // console_out
None, // log
None, // dump_dt
- None, // callback
)
.context("Failed to create VM")?;
diff --git a/tests/vm_accessor/accessor/src/run.rs b/tests/vm_accessor/accessor/src/run.rs
index 6dcc507..5bdb8f1 100644
--- a/tests/vm_accessor/accessor/src/run.rs
+++ b/tests/vm_accessor/accessor/src/run.rs
@@ -129,10 +129,9 @@
None, /* console_in */
Some(android_log_fd()?), /* log */
None, /* dump_dt */
- Some(Box::new(Callback {})),
)
.context("Failed to create VM")?;
- vm.start().context("Failed to start VM")?;
+ vm.start(Some(Box::new(Callback {}))).context("Failed to start VM")?;
info!("started IAccessor VM with CID {}", vm.cid());
diff --git a/tests/vmbase_example/src/main.rs b/tests/vmbase_example/src/main.rs
index 81812cd..0eda90e 100644
--- a/tests/vmbase_example/src/main.rs
+++ b/tests/vmbase_example/src/main.rs
@@ -116,10 +116,9 @@
/* consoleIn */ None,
Some(log_writer),
/* dump_dt */ None,
- None,
)
.context("Failed to create VM")?;
- vm.start().context("Failed to start VM")?;
+ vm.start(None).context("Failed to start VM")?;
info!("Started example VM.");
// Wait for VM to finish, and check that it shut down cleanly.