Merge "Use release_avf_microdroid_kernel_version to pick Microdroid kernel" into main
diff --git a/Android.bp b/Android.bp
index 717c902..6e7c3c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -89,3 +89,19 @@
tools: ["dtc"],
cmd: "FILES=($(in)) && $(location dtc) -I dts -O dtb $${FILES[-1]} -o $(out)",
}
+
+// This is a temporary workaround until b/309090563 is implemented.
+aconfig_declarations {
+ name: "avf_aconfig_flags",
+ package: "com.android.system.virtualmachine.flags",
+ srcs: [
+ "avf_flags.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "avf_aconfig_flags_java",
+ aconfig_declarations: "avf_aconfig_flags",
+ sdk_version: "module_current",
+ apex_available: ["com.android.virt"],
+}
diff --git a/README.md b/README.md
index 3935f93..210f70e 100644
--- a/README.md
+++ b/README.md
@@ -29,3 +29,4 @@
* [Building and running a demo app in C++](demo_native/README.md)
* [Debugging](docs/debug)
* [Using custom VM](docs/custom_vm.md)
+* [Device assignment](docs/device_assignment.md)
\ No newline at end of file
diff --git a/apex/Android.bp b/apex/Android.bp
index 7cc0414..cc59b16 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -41,10 +41,12 @@
"release_avf_enable_llpvm_changes",
"release_avf_enable_remote_attestation",
"release_avf_enable_vendor_modules",
+ "release_avf_enable_virt_cpufreq",
],
properties: [
"androidManifest",
"arch",
+ "canned_fs_config",
"prebuilts",
"systemserverclasspath_fragments",
"vintf_fragments",
@@ -68,7 +70,6 @@
],
file_contexts: ":com.android.virt-file_contexts",
- canned_fs_config: "canned_fs_config",
bootclasspath_fragments: [
"com.android.virt-bootclasspath-fragment",
@@ -90,6 +91,12 @@
"com.android.virt-systemserver-fragment",
],
},
+ release_avf_enable_virt_cpufreq: {
+ canned_fs_config: "canned_fs_config_sys_nice",
+ conditions_default: {
+ canned_fs_config: "canned_fs_config",
+ },
+ },
},
}
diff --git a/apex/canned_fs_config_sys_nice b/apex/canned_fs_config_sys_nice
new file mode 100644
index 0000000..5b12eb5
--- /dev/null
+++ b/apex/canned_fs_config_sys_nice
@@ -0,0 +1,2 @@
+/bin/virtualizationservice 0 2000 0755 capabilities=0x1000001 # CAP_CHOWN, CAP_SYS_RESOURCE
+/bin/crosvm 0 3013 0755 capabilities=0x800000 # SYS_NICE
diff --git a/avf_flags.aconfig b/avf_flags.aconfig
new file mode 100644
index 0000000..8abb9ee
--- /dev/null
+++ b/avf_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.system.virtualmachine.flags"
+
+flag {
+ name: "avf_v_test_apis"
+ namespace: "virtualization"
+ description: "Only purpose of this flag is to be used in @FlaggedApi in our V test apis"
+ bug: "325441024"
+ is_fixed_read_only: true
+}
+
diff --git a/docs/device_assignment.md b/docs/device_assignment.md
new file mode 100644
index 0000000..4c5b477
--- /dev/null
+++ b/docs/device_assignment.md
@@ -0,0 +1,239 @@
+# Getting started with device assignment
+
+Device assignment allows a VM to have direct access to HW without host/hyp
+intervention. AVF uses `vfio-platform` for device assignment, and host kernel
+support is required.
+
+This document explains how to setup and launch VM with device assignments.
+
+## VM device assignment DTBO (a.k.a. VM DTBO)
+
+For device assignment, a VM device assignment DTBO (a.k.a. VM DTBO) is required.
+VM DTBO is a device tree overlay which describes all assignable devices
+information. Information includes physical reg, IOMMU, device properties, and
+dependencies.
+
+VM DTBO allows to pass extra properties of assignable platform
+devices to the VM (which can't be discovered from the HW) while keeping the VMM
+device-agnostic.
+
+When the host boots, the bootloader provides VM DTBO to both Android and pvmfw.
+
+When a VM boots, the VMM selectively applies the DTBO based from provided
+labels, describing the assigned devices.
+
+## Prepare VM DTBO
+
+VM DTBO should be included in the dtbo partition. It should be in its own
+entry, and not together with any host OS's. See [DTB/DTBO Paritions] for
+partition format.
+
+[DTB/DTBO Paritions]: https://source.android.com/docs/core/architecture/dto/partitions
+
+### Write VM DTS for VM DTBO
+
+DTBO is compiled from device tree source (DTS) with `dtc` tool. [DTBO syntax]
+explains basic syntax of DTS.
+
+[DTBO syntax]: https://source.android.com/docs/core/architecture/dto/syntax
+
+Here are details and requirements:
+
+#### Describe assignable devices
+
+VM DTBO should describe assignable devices and their labels.
+
+* VM DTBO should have assignable devices in the `&{/}`, so it can be
+ overlaid onto VM DT. Assignable devices should be backed by physical device.
+ * We only support overlaying onto root node (i.e. `&{/}`) to prevent
+ unexpected modification of VM DT.
+* VM DTBO should have labels for assignable devices, so AVF can recognize
+ assignable device list. Labels should point to valid 'overlayable' nodes.
+ * Overlayable node is a node that would be applied to the base device tree
+ when DTBO is applied.
+
+#### Describe physical devices and physical IOMMUs
+
+VM DTBO should describe a `/host` node which describes physical devices and
+physical IOMMUs. The `/host` node only describes information for verification of
+assigned devices, and wouldn't be applied to VM DT. Here are details:
+
+* Physical IOMMU nodes
+ * IOMMU nodes must have a phandle to be referenced by a physical device node.
+ * IOMMU nodes must have `<android,pvmfw,token>` property. The property
+ describes the IOMMU token. An IOMMU token is a hypervisor-specific `<u64>`
+ which uniquely identifies a physical IOMMU. IOMMU token must be constant
+ across the VM boot for provisioning by pvmfw remains valid. The token must
+ be kept up-to-date across hypervisor updates.
+ * IOMMU nodes should be multi-master IOMMUs. (i.e. `#iommu-cells = <1>`)
+ * Other `#iommu-cells` values aren't supported for now.
+ * See: [Device tree binding for IOMMUs][IOMMU]
+* Physical device nodes
+ * Physical device nodes must have a `<android,pvmfw,target>` property that
+ references an overlayable node. The overlayable node contains the properties
+ that would be included in VM DT.
+ * Physical device nodes must have `<reg>` property to provide physical
+ regions.
+ * Physical device nodes can optionally contain `<iommus>` property. The
+ property is a prop-encoded-array and contains a number of
+ (iommu phandle, SID) pairs.
+ * IOMMU can be shared among devices, but should use distinct SIDs. Sharing
+ the same IOMMU-SID pair among multiple devices isn't supported for now.
+
+[IOMMU]: https://www.kernel.org/doc/Documentation/devicetree/bindings/iommu/iommu.txt
+
+#### Describe dependencies
+
+VM DTBO may have dependencies via phandle references. When a device node is
+assigned, dependencies of the node are also applied to VM DT.
+
+When dependencies are applied, siblings or children nodes of dependencies are
+ignored unless explicitly referenced.
+
+#### VM DTBO example
+
+Here's a simple example device tree source with four assignable devices nodes.
+
+```dts
+/dts-v1/;
+/plugin/;
+
+/ {
+ // host node describes physical devices and IOMMUs, and wouldn't be applied to VM DT
+ host {
+ #address-cells = <0x2>;
+ #size-cells = <0x1>;
+ rng {
+ reg = <0x0 0x12f00000 0x1000>;
+ iommus = <&iommu0 0x3>;
+ android,pvmfw,target = <&rng>;
+ };
+ light {
+ reg = <0x0 0x00f00000 0x1000>, <0x0 0x00f10000 0x1000>;
+ iommus = <&iommu1 0x4>, <&iommu2 0x5>;
+ android,pvmfw,target = <&light>;
+ };
+ led {
+ reg = <0x0 0x12000000 0x1000>;
+ iommus = <&iommu1 0x3>;
+ android,pvmfw,target = <&led>;
+ };
+ bus0 {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ backlight {
+ reg = <0x300 0x100>;
+ android,pvmfw,target = <&backlight>;
+ };
+ };
+ iommu0: iommu0 {
+ #iommu-cells = <0x1>;
+ android,pvmfw,token = <0x0 0x12e40000>;
+ };
+ iommu1: iommu1 {
+ #iommu-cells = <0x1>;
+ android,pvmfw,token = <0x0 0x40000>;
+ };
+ iommu2: iommu2 {
+ #iommu-cells = <0x1>;
+ android,pvmfw,token = <0x0 0x50000>;
+ };
+ };
+};
+
+// Beginning of the assignable devices. Assigned devices would be applied to VM DT
+&{/} { // We only allows to overlay to root node
+ rng: rng {
+ compatible = "android,rng";
+ android,rng,ignore-gctrl-reset;
+ };
+ light: light {
+ compatible = "android,light";
+ version = <0x1 0x2>;
+ };
+ led: led {
+ compatible = "android,led";
+ prop = <0x555>;
+ };
+ bus0 {
+ backlight: backlight {
+ compatible = "android,backlight";
+ android,backlight,ignore-gctrl-reset;
+ };
+ };
+};
+```
+
+If you compile the above with `dtc -@`, then you'll get `__symbols__` for free.
+The generated `__symbols__` indicates that there are four assignable devices.
+
+```dts
+ // generated __symbols__. AVF will ignore non-overlayable nodes.
+ __symbols__ {
+ iommu0 = "/host/iommu0";
+ iommu1 = "/host/iommu1";
+ iommu2 = "/host/iommu2";
+ rng = "/fragment@rng/__overlay__/rng";
+ light = "/fragment@sensor/__overlay__/light";
+ led = "/fragment@led/__overlay__/led";
+ backlight = "/fragment@backlight/__overlay__/bus0/backlight";
+ };
+```
+
+## Prepare AVF assignable devices XML
+
+AVF requires assignable device information to unbind from the host device driver
+and bind to VFIO driver. The information should be provided in an XML file at
+`/vendor/etc/avf/assignable_devices.xml`.
+
+Here's example.
+
+```xml
+<devices>
+ <device>
+ <kind>sensor</kind>
+ <dtbo_label>light</dtbo_label>
+ <sysfs_path>/sys/bus/platform/devices/16d00000.light</sysfs_path>
+ </device>
+</devices>
+```
+
+* `<kind>`: Device kind. Currently only used for debugging purposes and not used
+ for device assignment.
+* `<dtbo_label>`: Label in the VM DTBO (i.e. symbols in `__symbols__`). Must be
+ unique.
+* `<sysfs_path>`: Sysfs path of the device in host, used to bind to the VFIO
+ driver. Must be unique in the XML.
+
+## Boot with VM DTBO
+
+Bootloader should provide VM DTBO to both Android and pvmfw.
+
+### Provide VM DTBO index in dtbo.img
+
+Bootloader should provide the VM DTBO index with sysprop
+`ro.boot.hypervisor.vm_dtbo_idx.`. DTBO index represents DTBO location in
+dtbo.img.
+
+### Provide VM DTBO in the pvmfw config
+
+For protected VM, bootloader must provide VM DTBO to the pvmfw. pvmfw sanitizes
+incoming device tree with the VM DTBO.
+
+For more detail about providing VM DTBO in pvmfw,
+see: [pvmfw/README.md](../pvmfw/README.md#configuration-data-format)
+
+
+## Launch VM with device assignment
+
+We don't support client API yet in Android V, but you can use CLI to test device
+assignment. Note that host kernel support is required.
+
+Specify `--devices ${sysfs_path}` when booting VM. The parameter can be repeated
+multiple times for specifying multiple devices.
+
+Here's an example:
+
+```sh
+adb shell /apex/com.android.virt/bin/vm run-microdroid --devices /sys/bus/platform/devices/16d00000.light
+```
\ No newline at end of file
diff --git a/javalib/Android.bp b/javalib/Android.bp
index e3cb2e3..a7c531e 100644
--- a/javalib/Android.bp
+++ b/javalib/Android.bp
@@ -33,6 +33,7 @@
srcs: ["src/**/*.java"],
static_libs: [
"android.system.virtualizationservice-java",
+ "avf_aconfig_flags_java",
// For android.sysprop.HypervisorProperties
"PlatformProperties",
],
diff --git a/javalib/api/test-current.txt b/javalib/api/test-current.txt
index 3ea50e2..0a988d8 100644
--- a/javalib/api/test-current.txt
+++ b/javalib/api/test-current.txt
@@ -2,33 +2,33 @@
package android.system.virtualmachine {
public class VirtualMachine implements java.lang.AutoCloseable {
- method @FlaggedApi("RELEASE_AVF_ENABLE_REMOTE_ATTESTATION") @RequiresPermission(android.system.virtualmachine.VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION) public void enableTestAttestation() throws android.system.virtualmachine.VirtualMachineException;
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @RequiresPermission(android.system.virtualmachine.VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION) public void enableTestAttestation() throws android.system.virtualmachine.VirtualMachineException;
method @NonNull @WorkerThread public java.io.OutputStream getConsoleInput() throws android.system.virtualmachine.VirtualMachineException;
method @NonNull public java.io.File getRootDir();
}
public final class VirtualMachineConfig {
- method @FlaggedApi("RELEASE_AVF_ENABLE_MULTI_TENANT_MICRODROID_VM") @NonNull public java.util.List<java.lang.String> getExtraApks();
- method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @Nullable public String getOs();
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public java.util.List<java.lang.String> getExtraApks();
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @Nullable public String getOs();
method @Nullable public String getPayloadConfigPath();
method public boolean isVmConsoleInputSupported();
}
public static final class VirtualMachineConfig.Builder {
- method @FlaggedApi("RELEASE_AVF_ENABLE_MULTI_TENANT_MICRODROID_VM") @NonNull public android.system.virtualmachine.VirtualMachineConfig.Builder addExtraApk(@NonNull String);
- method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @NonNull public android.system.virtualmachine.VirtualMachineConfig.Builder setOs(@NonNull String);
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public android.system.virtualmachine.VirtualMachineConfig.Builder addExtraApk(@NonNull String);
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public android.system.virtualmachine.VirtualMachineConfig.Builder setOs(@NonNull String);
method @NonNull @RequiresPermission(android.system.virtualmachine.VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION) public android.system.virtualmachine.VirtualMachineConfig.Builder setPayloadConfigPath(@NonNull String);
- method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @NonNull @RequiresPermission(android.system.virtualmachine.VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION) public android.system.virtualmachine.VirtualMachineConfig.Builder setVendorDiskImage(@NonNull java.io.File);
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull @RequiresPermission(android.system.virtualmachine.VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION) public android.system.virtualmachine.VirtualMachineConfig.Builder setVendorDiskImage(@NonNull java.io.File);
method @NonNull public android.system.virtualmachine.VirtualMachineConfig.Builder setVmConsoleInputSupported(boolean);
}
public class VirtualMachineManager {
- method @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES") @NonNull public java.util.List<java.lang.String> getSupportedOSList() throws android.system.virtualmachine.VirtualMachineException;
- method @RequiresPermission(android.system.virtualmachine.VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION) public boolean isFeatureEnabled(String) throws android.system.virtualmachine.VirtualMachineException;
- field public static final String FEATURE_DICE_CHANGES = "com.android.kvm.DICE_CHANGES";
- field public static final String FEATURE_MULTI_TENANT = "com.android.kvm.MULTI_TENANT";
- field public static final String FEATURE_REMOTE_ATTESTATION = "com.android.kvm.REMOTE_ATTESTATION";
- field public static final String FEATURE_VENDOR_MODULES = "com.android.kvm.VENDOR_MODULES";
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public java.util.List<java.lang.String> getSupportedOSList() throws android.system.virtualmachine.VirtualMachineException;
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @RequiresPermission(android.system.virtualmachine.VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION) public boolean isFeatureEnabled(String) throws android.system.virtualmachine.VirtualMachineException;
+ field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_DICE_CHANGES = "com.android.kvm.DICE_CHANGES";
+ field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_MULTI_TENANT = "com.android.kvm.MULTI_TENANT";
+ field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_REMOTE_ATTESTATION = "com.android.kvm.REMOTE_ATTESTATION";
+ field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_VENDOR_MODULES = "com.android.kvm.VENDOR_MODULES";
}
}
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index b4ba00b..6b03cfe 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -76,6 +76,7 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.system.virtualmachine.flags.Flags;
import java.io.File;
import java.io.FileInputStream;
@@ -1215,7 +1216,7 @@
*/
@TestApi
@RequiresPermission(USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION)
- @FlaggedApi("RELEASE_AVF_ENABLE_REMOTE_ATTESTATION")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
public void enableTestAttestation() throws VirtualMachineException {
try {
mVirtualizationService.getBinder().enableTestAttestation();
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 9688789..19e663f 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -40,6 +40,8 @@
import android.system.virtualizationservice.VirtualMachinePayloadConfig;
import android.util.Log;
+import com.android.system.virtualmachine.flags.Flags;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -376,7 +378,7 @@
* @hide
*/
@TestApi
- @FlaggedApi("RELEASE_AVF_ENABLE_MULTI_TENANT_MICRODROID_VM")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@NonNull
public List<String> getExtraApks() {
return mExtraApks;
@@ -502,7 +504,7 @@
* @hide
*/
@TestApi
- @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@Nullable
public String getOs() {
return mOs;
@@ -792,7 +794,7 @@
* @hide
*/
@TestApi
- @FlaggedApi("RELEASE_AVF_ENABLE_MULTI_TENANT_MICRODROID_VM")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@NonNull
public Builder addExtraApk(@NonNull String packageName) {
mExtraApks.add(requireNonNull(packageName, "extra APK package name must not be null"));
@@ -1003,8 +1005,8 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@RequiresPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION)
- @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES")
@NonNull
public Builder setVendorDiskImage(@NonNull File vendorDiskImage) {
mVendorDiskImage =
@@ -1020,7 +1022,7 @@
* @hide
*/
@TestApi
- @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@NonNull
public Builder setOs(@NonNull String os) {
mOs = requireNonNull(os, "os must not be null");
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
index 1a4b53a..f263b32 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
@@ -36,6 +36,7 @@
import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
+import com.android.system.virtualmachine.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -130,6 +131,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
public static final String FEATURE_DICE_CHANGES = IVirtualizationService.FEATURE_DICE_CHANGES;
/**
@@ -138,6 +140,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
public static final String FEATURE_MULTI_TENANT = IVirtualizationService.FEATURE_MULTI_TENANT;
/**
@@ -146,6 +149,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
public static final String FEATURE_REMOTE_ATTESTATION =
IVirtualizationService.FEATURE_REMOTE_ATTESTATION;
@@ -155,6 +159,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
public static final String FEATURE_VENDOR_MODULES =
IVirtualizationService.FEATURE_VENDOR_MODULES;
@@ -347,7 +352,7 @@
* @hide
*/
@TestApi
- @FlaggedApi("RELEASE_AVF_ENABLE_VENDOR_MODULES")
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@NonNull
public List<String> getSupportedOSList() throws VirtualMachineException {
synchronized (sCreateLock) {
@@ -366,6 +371,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@RequiresPermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION)
public boolean isFeatureEnabled(@Features String featureName) throws VirtualMachineException {
synchronized (sCreateLock) {
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index ab3c83f..d1ab24e 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -459,7 +459,7 @@
}
/// Returns the first subnode of this
- pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
+ pub fn first_subnode(self) -> Result<Option<Self>> {
let offset = self.fdt.first_subnode(self.offset)?;
Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index cafbf97..ddc4538 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -378,7 +378,7 @@
let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
- let mut root = fdt.root_mut().unwrap();
+ let root = fdt.root_mut().unwrap();
let mut subnode_iter = root.first_subnode().unwrap();
while let Some(subnode) = subnode_iter {
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 9a2b3ef..6a6d199 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -110,6 +110,7 @@
"libciborium",
"libdiced_open_dice_nostd",
"libpvmfw_avb_nostd",
+ "libzerocopy_nostd",
],
}
diff --git a/pvmfw/README.md b/pvmfw/README.md
index d7884fb..2758a5d 100644
--- a/pvmfw/README.md
+++ b/pvmfw/README.md
@@ -195,7 +195,8 @@
In version 1.1, a third blob is added.
-- entry 2 may point to a [DTBO] that describes VM DTBO for device assignment.
+- entry 2 may point to a [DTBO] that describes VM DA DTBO for
+ [device assignment][device_assignment].
pvmfw will provision assigned devices with the VM DTBO.
In version 1.2, a fourth blob is added.
@@ -225,6 +226,7 @@
[header]: src/config.rs
[DTBO]: https://android.googlesource.com/platform/external/dtc/+/refs/heads/main/Documentation/dt-object-internal.txt
[debug_policy]: ../docs/debug/README.md#debug-policy
+[device_assignment]: ../docs/device_assignment.md
[secretkeeper_key]: https://android.googlesource.com/platform/system/secretkeeper/+/refs/heads/main/README.md#secretkeeper-public-key
[vendor_hashtree_digest]: ../microdroid/README.md#verification-of-vendor-image
diff --git a/pvmfw/platform.dts b/pvmfw/platform.dts
index 9abc123..cea1c33 100644
--- a/pvmfw/platform.dts
+++ b/pvmfw/platform.dts
@@ -57,96 +57,497 @@
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <0>;
+ operating-points-v2 = <&opp_table0>;
+ opp_table0: opp-table-0 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@1 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <1>;
+ operating-points-v2 = <&opp_table1>;
+ opp_table1: opp-table-1 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@2 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <2>;
+ operating-points-v2 = <&opp_table2>;
+ opp_table2: opp-table-2 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@3 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <3>;
+ operating-points-v2 = <&opp_table3>;
+ opp_table3: opp-table-3 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@4 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <4>;
+ operating-points-v2 = <&opp_table4>;
+ opp_table4: opp-table-4 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@5 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <5>;
+ operating-points-v2 = <&opp_table5>;
+ opp_table5: opp-table-5 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@6 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <6>;
+ operating-points-v2 = <&opp_table6>;
+ opp_table6: opp-table-6 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@7 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <7>;
+ operating-points-v2 = <&opp_table7>;
+ opp_table7: opp-table-7 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@8 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <8>;
+
+ operating-points-v2 = <&opp_table8>;
+ opp_table8: opp-table-8 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@9 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <9>;
+ operating-points-v2 = <&opp_table9>;
+ opp_table9: opp-table-9 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@10 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <10>;
+ operating-points-v2 = <&opp_table10>;
+ opp_table10: opp-table-10 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@11 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <11>;
+ operating-points-v2 = <&opp_table11>;
+ opp_table11: opp-table-11 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@12 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <12>;
+ operating-points-v2 = <&opp_table12>;
+ opp_table12: opp-table-12 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@13 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <13>;
+ operating-points-v2 = <&opp_table13>;
+ opp_table13: opp-table-13 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@14 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <14>;
+ operating-points-v2 = <&opp_table14>;
+ opp_table14: opp-table-14 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
cpu@15 {
device_type = "cpu";
compatible = "arm,arm-v8";
enable-method = "psci";
reg = <15>;
+ operating-points-v2 = <&opp_table15>;
+ opp_table15: opp-table-15 {
+ compatible = "operating-points-v2";
+
+ opp1 { opp-hz = <PLACEHOLDER2>; };
+ opp2 { opp-hz = <PLACEHOLDER2>; };
+ opp3 { opp-hz = <PLACEHOLDER2>; };
+ opp4 { opp-hz = <PLACEHOLDER2>; };
+ opp5 { opp-hz = <PLACEHOLDER2>; };
+ opp6 { opp-hz = <PLACEHOLDER2>; };
+ opp7 { opp-hz = <PLACEHOLDER2>; };
+ opp8 { opp-hz = <PLACEHOLDER2>; };
+ opp9 { opp-hz = <PLACEHOLDER2>; };
+ opp10 { opp-hz = <PLACEHOLDER2>; };
+ opp11 { opp-hz = <PLACEHOLDER2>; };
+ opp12 { opp-hz = <PLACEHOLDER2>; };
+ opp13 { opp-hz = <PLACEHOLDER2>; };
+ opp14 { opp-hz = <PLACEHOLDER2>; };
+ opp15 { opp-hz = <PLACEHOLDER2>; };
+ opp16 { opp-hz = <PLACEHOLDER2>; };
+ opp17 { opp-hz = <PLACEHOLDER2>; };
+ opp18 { opp-hz = <PLACEHOLDER2>; };
+ opp19 { opp-hz = <PLACEHOLDER2>; };
+ opp20 { opp-hz = <PLACEHOLDER2>; };
+ };
};
};
@@ -321,4 +722,9 @@
id = <PLACEHOLDER>;
#iommu-cells = <1>;
};
+
+ cpufreq {
+ compatible = "virtual,android-v-only-cpufreq";
+ reg = <0x0 0x1040000 PLACEHOLDER2>;
+ };
};
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index 99bf589..540fd03 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -21,6 +21,7 @@
Hash, InputValues, HIDDEN_SIZE,
};
use pvmfw_avb::{Capability, DebugLevel, Digest, VerifiedBootData};
+use zerocopy::AsBytes;
fn to_dice_mode(debug_level: DebugLevel) -> DiceMode {
match debug_level {
@@ -72,12 +73,30 @@
Config::Descriptor(config),
self.auth_hash,
self.mode,
- *salt,
+ self.make_hidden(salt)?,
);
let _ = bcc_handover_main_flow(current_bcc_handover, &dice_inputs, next_bcc)?;
Ok(())
}
+ fn make_hidden(&self, salt: &[u8; HIDDEN_SIZE]) -> diced_open_dice::Result<[u8; HIDDEN_SIZE]> {
+ // We want to make sure we get a different sealing CDI for:
+ // - VMs with different salt values
+ // - An RKP VM and any other VM (regardless of salt)
+ // The hidden input for DICE affects the sealing CDI (but the values in the config
+ // descriptor do not).
+ // Since the hidden input has to be a fixed size, create it as a hash of the values we
+ // want included.
+ #[derive(AsBytes)]
+ #[repr(C, packed)]
+ struct HiddenInput {
+ rkp_vm_marker: bool,
+ salt: [u8; HIDDEN_SIZE],
+ }
+
+ hash(HiddenInput { rkp_vm_marker: self.rkp_vm_marker, salt: *salt }.as_bytes())
+ }
+
fn generate_config_descriptor<'a>(
&self,
config_descriptor_buffer: &'a mut [u8],
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index ac52be9..f20451a 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -35,6 +35,7 @@
use libfdt::CellIterator;
use libfdt::Fdt;
use libfdt::FdtError;
+use libfdt::FdtNode;
use libfdt::FdtNodeMut;
use log::debug;
use log::error;
@@ -54,12 +55,17 @@
pub enum FdtValidationError {
/// Invalid CPU count.
InvalidCpuCount(usize),
+ /// Invalid VCpufreq Range.
+ InvalidVcpufreq(u64, u64),
}
impl fmt::Display for FdtValidationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidCpuCount(num_cpus) => write!(f, "Invalid CPU count: {num_cpus}"),
+ Self::InvalidVcpufreq(addr, size) => {
+ write!(f, "Invalid vcpufreq region: ({addr:#x}, {size:#x})")
+ }
}
}
}
@@ -172,15 +178,41 @@
.setprop_inplace(cstr!("reg"), [addr.to_be(), size.to_be()].as_bytes())
}
+//TODO: Need to add info for cpu capacity
#[derive(Debug, Default)]
-struct CpuInfo {}
+struct CpuInfo {
+ opptable_info: Option<ArrayVec<[u64; CpuInfo::MAX_OPPTABLES]>>,
+}
+
+impl CpuInfo {
+ const MAX_OPPTABLES: usize = 20;
+}
+
+fn read_opp_info_from(
+ opp_node: FdtNode,
+) -> libfdt::Result<ArrayVec<[u64; CpuInfo::MAX_OPPTABLES]>> {
+ let mut table = ArrayVec::new();
+ for subnode in opp_node.subnodes()? {
+ let prop = subnode.getprop_u64(cstr!("opp-hz"))?.ok_or(FdtError::NotFound)?;
+ table.push(prop);
+ }
+
+ Ok(table)
+}
fn read_cpu_info_from(fdt: &Fdt) -> libfdt::Result<ArrayVec<[CpuInfo; DeviceTreeInfo::MAX_CPUS]>> {
let mut cpus = ArrayVec::new();
-
let mut cpu_nodes = fdt.compatible_nodes(cstr!("arm,arm-v8"))?;
- for _cpu in cpu_nodes.by_ref().take(cpus.capacity()) {
- let info = CpuInfo {};
+ for cpu in cpu_nodes.by_ref().take(cpus.capacity()) {
+ let opp_phandle = cpu.getprop_u32(cstr!("operating-points-v2"))?;
+ let opptable_info = if let Some(phandle) = opp_phandle {
+ let phandle = phandle.try_into()?;
+ let node = fdt.node_with_phandle(phandle)?.ok_or(FdtError::NotFound)?;
+ Some(read_opp_info_from(node)?)
+ } else {
+ None
+ };
+ let info = CpuInfo { opptable_info };
cpus.push(info);
}
if cpu_nodes.next().is_some() {
@@ -198,12 +230,87 @@
Ok(())
}
+fn read_vcpufreq_info(fdt: &Fdt) -> libfdt::Result<Option<VcpufreqInfo>> {
+ let mut nodes = fdt.compatible_nodes(cstr!("virtual,android-v-only-cpufreq"))?;
+ let Some(node) = nodes.next() else {
+ return Ok(None);
+ };
+
+ if nodes.next().is_some() {
+ warn!("DT has more than 1 cpufreq node: discarding extra nodes.");
+ }
+
+ let mut regs = node.reg()?.ok_or(FdtError::NotFound)?;
+ let reg = regs.next().ok_or(FdtError::NotFound)?;
+ let size = reg.size.ok_or(FdtError::NotFound)?;
+
+ Ok(Some(VcpufreqInfo { addr: reg.addr, size }))
+}
+
+fn validate_vcpufreq_info(
+ vcpufreq_info: &VcpufreqInfo,
+ cpus: &[CpuInfo],
+) -> Result<(), FdtValidationError> {
+ const VCPUFREQ_BASE_ADDR: u64 = 0x1040000;
+ const VCPUFREQ_SIZE_PER_CPU: u64 = 0x8;
+
+ let base = vcpufreq_info.addr;
+ let size = vcpufreq_info.size;
+ let expected_size = VCPUFREQ_SIZE_PER_CPU * cpus.len() as u64;
+
+ if (base, size) != (VCPUFREQ_BASE_ADDR, expected_size) {
+ return Err(FdtValidationError::InvalidVcpufreq(base, size));
+ }
+
+ Ok(())
+}
+
+fn patch_opptable(
+ node: FdtNodeMut,
+ opptable: Option<ArrayVec<[u64; CpuInfo::MAX_OPPTABLES]>>,
+) -> libfdt::Result<()> {
+ let oppcompat = cstr!("operating-points-v2");
+ let next = node.next_compatible(oppcompat)?.ok_or(FdtError::NoSpace)?;
+
+ let Some(opptable) = opptable else {
+ return next.nop();
+ };
+
+ let mut next_subnode = next.first_subnode()?;
+
+ for entry in opptable {
+ let mut subnode = next_subnode.ok_or(FdtError::NoSpace)?;
+ subnode.setprop_inplace(cstr!("opp-hz"), &entry.to_be_bytes())?;
+ next_subnode = subnode.next_subnode()?;
+ }
+
+ while let Some(current) = next_subnode {
+ next_subnode = current.delete_and_next_subnode()?;
+ }
+
+ Ok(())
+}
+
+// TODO(ptosi): Rework FdtNodeMut and replace this function.
+fn get_nth_compatible<'a>(
+ fdt: &'a mut Fdt,
+ n: usize,
+ compat: &CStr,
+) -> libfdt::Result<Option<FdtNodeMut<'a>>> {
+ let mut node = fdt.root_mut()?.next_compatible(compat)?;
+ for _ in 0..n {
+ node = node.ok_or(FdtError::NoSpace)?.next_compatible(compat)?;
+ }
+ Ok(node)
+}
+
fn patch_cpus(fdt: &mut Fdt, cpus: &[CpuInfo]) -> libfdt::Result<()> {
const COMPAT: &CStr = cstr!("arm,arm-v8");
- let mut next = fdt.root_mut()?.next_compatible(COMPAT)?;
- for _cpu in cpus {
- next = next.ok_or(FdtError::NoSpace)?.next_compatible(COMPAT)?;
+ for (idx, cpu) in cpus.iter().enumerate() {
+ let cur = get_nth_compatible(fdt, idx, COMPAT)?.ok_or(FdtError::NoSpace)?;
+ patch_opptable(cur, cpu.opptable_info)?;
}
+ let mut next = get_nth_compatible(fdt, cpus.len(), COMPAT)?;
while let Some(current) = next {
next = current.delete_and_next_compatible(COMPAT)?;
}
@@ -628,6 +735,21 @@
}
#[derive(Debug)]
+struct VcpufreqInfo {
+ addr: u64,
+ size: u64,
+}
+
+fn patch_vcpufreq(fdt: &mut Fdt, vcpufreq_info: &Option<VcpufreqInfo>) -> libfdt::Result<()> {
+ let mut node = fdt.node_mut(cstr!("/cpufreq"))?.unwrap();
+ if let Some(info) = vcpufreq_info {
+ node.setprop_addrrange_inplace(cstr!("reg"), info.addr, info.size)
+ } else {
+ node.nop()
+ }
+}
+
+#[derive(Debug)]
pub struct DeviceTreeInfo {
pub kernel_range: Option<Range<usize>>,
pub initrd_range: Option<Range<usize>>,
@@ -639,6 +761,7 @@
pub swiotlb_info: SwiotlbInfo,
device_assignment: Option<DeviceAssignmentInfo>,
vm_ref_dt_props_info: BTreeMap<CString, Vec<u8>>,
+ vcpufreq_info: Option<VcpufreqInfo>,
}
impl DeviceTreeInfo {
@@ -751,6 +874,17 @@
RebootReason::InvalidFdt
})?;
+ let vcpufreq_info = read_vcpufreq_info(fdt).map_err(|e| {
+ error!("Failed to read vcpufreq info from DT: {e}");
+ RebootReason::InvalidFdt
+ })?;
+ if let Some(ref info) = vcpufreq_info {
+ validate_vcpufreq_info(info, &cpus).map_err(|e| {
+ error!("Failed to validate vcpufreq info from DT: {e}");
+ RebootReason::InvalidFdt
+ })?;
+ }
+
let pci_info = read_pci_info_from(fdt).map_err(|e| {
error!("Failed to read pci info from DT: {e}");
RebootReason::InvalidFdt
@@ -801,6 +935,7 @@
swiotlb_info,
device_assignment,
vm_ref_dt_props_info,
+ vcpufreq_info,
})
}
@@ -825,6 +960,10 @@
error!("Failed to patch cpus to DT: {e}");
RebootReason::InvalidFdt
})?;
+ patch_vcpufreq(fdt, &info.vcpufreq_info).map_err(|e| {
+ error!("Failed to patch vcpufreq info to DT: {e}");
+ RebootReason::InvalidFdt
+ })?;
patch_pci_info(fdt, &info.pci_info).map_err(|e| {
error!("Failed to patch pci info to DT: {e}");
RebootReason::InvalidFdt
diff --git a/service_vm/test_apk/src/native/main.rs b/service_vm/test_apk/src/native/main.rs
index 26b8062..d5d599d 100644
--- a/service_vm/test_apk/src/native/main.rs
+++ b/service_vm/test_apk/src/native/main.rs
@@ -45,7 +45,7 @@
android_logger::init_once(
android_logger::Config::default()
.with_tag("service_vm_client")
- .with_min_level(log::Level::Debug),
+ .with_max_level(log::LevelFilter::Debug),
);
// Redirect panic messages to logcat.
panic::set_hook(Box::new(|panic_info| {
diff --git a/virtualizationmanager/fsfdt/src/lib.rs b/virtualizationmanager/fsfdt/src/lib.rs
index 549df04..84e50c1 100644
--- a/virtualizationmanager/fsfdt/src/lib.rs
+++ b/virtualizationmanager/fsfdt/src/lib.rs
@@ -26,8 +26,8 @@
/// Creates a Fdt from /proc/device-tree style directory by wrapping a mutable slice
fn from_fs(fs_path: &Path, fdt_buffer: &'a mut [u8]) -> Result<&'a mut Self>;
- /// Appends a FDT from /proc/device-tree style directory at the given node path
- fn append(&mut self, fdt_node_path: &CStr, fs_path: &Path) -> Result<()>;
+ /// Overlay an FDT from /proc/device-tree style directory at the given node path
+ fn overlay_onto(&mut self, fdt_node_path: &CStr, fs_path: &Path) -> Result<()>;
}
impl<'a> FsFdt<'a> for Fdt {
@@ -35,12 +35,12 @@
let fdt = Fdt::create_empty_tree(fdt_buffer)
.map_err(|e| anyhow!("Failed to create FDT, {e:?}"))?;
- fdt.append(&CString::new("").unwrap(), fs_path)?;
+ fdt.overlay_onto(&CString::new("").unwrap(), fs_path)?;
Ok(fdt)
}
- fn append(&mut self, fdt_node_path: &CStr, fs_path: &Path) -> Result<()> {
+ fn overlay_onto(&mut self, fdt_node_path: &CStr, fs_path: &Path) -> Result<()> {
// Recursively traverse fs_path with DFS algorithm.
let mut stack = vec![fs_path.to_path_buf()];
while let Some(dir_path) = stack.pop() {
@@ -56,7 +56,7 @@
let mut node = self
.node_mut(&fdt_path)
.map_err(|e| anyhow!("Failed to write FDT, {e:?}"))?
- .ok_or_else(|| anyhow!("Failed to find {fdt_node_path:?} in FDT"))?;
+ .ok_or_else(|| anyhow!("Failed to find {fdt_path:?} in FDT"))?;
let mut subnode_names = vec![];
let entries =
@@ -90,9 +90,21 @@
// FDT library may omit address in node name when comparing their name, so sort to add
// node without address first.
subnode_names.sort();
- let subnode_names_c_str: Vec<_> = subnode_names.iter().map(|x| x.as_c_str()).collect();
- node.add_subnodes(&subnode_names_c_str)
- .map_err(|e| anyhow!("Failed to add node, {e:?}"))?;
+ let subnode_names: Vec<_> = subnode_names
+ .iter()
+ .filter_map(|name| {
+ // Filter out subnode names which are already present in the target parent node!
+ let name = name.as_c_str();
+ let is_present_res = node.as_node().subnode(name);
+ match is_present_res {
+ Ok(Some(_)) => None,
+ Ok(None) => Some(Ok(name)),
+ Err(e) => Some(Err(e)),
+ }
+ })
+ .collect::<Result<_, _>>()
+ .map_err(|e| anyhow!("Failed to filter subnodes, {e:?}"))?;
+ node.add_subnodes(&subnode_names).map_err(|e| anyhow!("Failed to add node, {e:?}"))?;
}
Ok(())
@@ -149,5 +161,8 @@
let actual = dts_from_dtb(file.path());
assert_eq!(&expected, &actual);
+ // Again append fdt from TEST_FS_FDT_ROOT_PATH at root & ensure it succeeds when some
+ // subnode are already present.
+ fdt.overlay_onto(&CString::new("/").unwrap(), fs_path).unwrap();
}
}
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 62df47d..a2194cc 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -19,9 +19,9 @@
use crate::composite::make_composite_image;
use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmContext, VmInstance, VmState};
use crate::debug_config::DebugConfig;
+use crate::dt_overlay::{create_device_tree_overlay, VM_DT_OVERLAY_MAX_SIZE, VM_DT_OVERLAY_PATH};
use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images, add_microdroid_vendor_image};
use crate::selinux::{getfilecon, SeContext};
-use crate::reference_dt;
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::{
Certificate::Certificate,
@@ -69,6 +69,7 @@
Status, StatusCode, Strong,
IntoBinderResult,
};
+use cstr::cstr;
use disk::QcowFile;
use glob::glob;
use lazy_static::lazy_static;
@@ -80,6 +81,7 @@
use semver::VersionReq;
use std::collections::HashSet;
use std::convert::TryInto;
+use std::fs;
use std::ffi::CStr;
use std::fs::{canonicalize, read_dir, remove_file, File, OpenOptions};
use std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom, Write};
@@ -119,6 +121,8 @@
/// crosvm requires all partitions to be a multiple of 4KiB.
const PARTITION_GRANULARITY_BYTES: u64 = 4096;
+const VM_REFERENCE_DT_ON_HOST_PATH: &str = "/proc/device-tree/avf/reference";
+
lazy_static! {
pub static ref GLOBAL_SERVICE: Strong<dyn IVirtualizationServiceInternal> =
wait_for_interface(BINDER_SERVICE_IDENTIFIER)
@@ -382,12 +386,36 @@
check_gdb_allowed(config)?;
}
- let reference_dt = reference_dt::parse_reference_dt(&temporary_directory)
- .context("Failed to create VM reference DT")
- .or_service_specific_exception(-1)?;
- if reference_dt.is_none() {
- warn!("VM reference DT doesn't exist");
- }
+ // Currently, VirtMgr adds the host copy of reference DT & an untrusted prop (instance-id)
+ let host_ref_dt = Path::new(VM_REFERENCE_DT_ON_HOST_PATH);
+ let host_ref_dt = if host_ref_dt.exists()
+ && read_dir(host_ref_dt).or_service_specific_exception(-1)?.next().is_some()
+ {
+ Some(host_ref_dt)
+ } else {
+ warn!("VM reference DT doesn't exist in host DT");
+ None
+ };
+
+ let untrusted_props = if cfg!(llpvm_changes) {
+ // TODO(b/291213394): Replace this with a per-VM instance Id.
+ let instance_id = b"sixtyfourbyteslonghardcoded_indeed_sixtyfourbyteslonghardcoded_h";
+ vec![(cstr!("instance-id"), &instance_id[..])]
+ } else {
+ vec![]
+ };
+
+ let device_tree_overlay = if host_ref_dt.is_some() || !untrusted_props.is_empty() {
+ let dt_output = temporary_directory.join(VM_DT_OVERLAY_PATH);
+ let mut data = [0_u8; VM_DT_OVERLAY_MAX_SIZE];
+ let fdt = create_device_tree_overlay(&mut data, host_ref_dt, &untrusted_props)
+ .map_err(|e| anyhow!("Failed to create DT overlay, {e:?}"))
+ .or_service_specific_exception(-1)?;
+ fs::write(&dt_output, fdt.as_slice()).or_service_specific_exception(-1)?;
+ Some(File::open(dt_output).or_service_specific_exception(-1)?)
+ } else {
+ None
+ };
let debug_level = match config {
VirtualMachineConfig::AppConfig(config) => config.debugLevel,
@@ -537,7 +565,7 @@
gdb_port,
vfio_devices,
dtbo,
- reference_dt,
+ device_tree_overlay,
};
let instance = Arc::new(
VmInstance::new(
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 84c60bd..2c23441 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -118,7 +118,7 @@
pub gdb_port: Option<NonZeroU16>,
pub vfio_devices: Vec<VfioDevice>,
pub dtbo: Option<File>,
- pub reference_dt: Option<File>,
+ pub device_tree_overlay: Option<File>,
}
/// A disk image to pass to crosvm for a VM.
@@ -896,10 +896,8 @@
.arg("--socket")
.arg(add_preserved_fd(&mut preserved_fds, &control_server_socket.as_raw_descriptor()));
- if let Some(reference_dt) = &config.reference_dt {
- command
- .arg("--device-tree-overlay")
- .arg(add_preserved_fd(&mut preserved_fds, reference_dt));
+ if let Some(dt_overlay) = &config.device_tree_overlay {
+ command.arg("--device-tree-overlay").arg(add_preserved_fd(&mut preserved_fds, dt_overlay));
}
append_platform_devices(&mut command, &mut preserved_fds, &config)?;
diff --git a/virtualizationmanager/src/dt_overlay.rs b/virtualizationmanager/src/dt_overlay.rs
new file mode 100644
index 0000000..83f7734
--- /dev/null
+++ b/virtualizationmanager/src/dt_overlay.rs
@@ -0,0 +1,117 @@
+// 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.
+
+//! This module support creating AFV related overlays, that can then be appended to DT by VM.
+
+use anyhow::{anyhow, Result};
+use cstr::cstr;
+use fsfdt::FsFdt;
+use libfdt::Fdt;
+use std::ffi::CStr;
+use std::path::Path;
+
+pub(crate) const AVF_NODE_NAME: &CStr = cstr!("avf");
+pub(crate) const UNTRUSTED_NODE_NAME: &CStr = cstr!("untrusted");
+pub(crate) const VM_DT_OVERLAY_PATH: &str = "vm_dt_overlay.dtbo";
+pub(crate) const VM_DT_OVERLAY_MAX_SIZE: usize = 2000;
+
+/// Create a Device tree overlay containing the provided proc style device tree & properties!
+/// # Arguments
+/// * `dt_path` - (Optional) Path to (proc style) device tree to be included in the overlay.
+/// * `untrusted_props` - Include a property in /avf/untrusted node. This node is used to specify
+/// host provided properties such as `instance-id`.
+///
+/// Example: with `create_device_tree_overlay(_, _, [("instance-id", _),])`
+/// ```
+/// {
+/// fragment@0 {
+/// target-path = "/";
+/// __overlay__ {
+/// avf {
+/// untrusted { instance-id = [0x01 0x23 .. ] }
+/// }
+/// };
+/// };
+/// };
+/// };
+/// ```
+pub(crate) fn create_device_tree_overlay<'a>(
+ buffer: &'a mut [u8],
+ dt_path: Option<&'a Path>,
+ untrusted_props: &[(&'a CStr, &'a [u8])],
+) -> Result<&'a mut Fdt> {
+ if dt_path.is_none() && untrusted_props.is_empty() {
+ return Err(anyhow!("Expected at least one device tree addition"));
+ }
+
+ let fdt =
+ Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
+ let mut root = fdt.root_mut().map_err(|e| anyhow!("Failed to get root: {e:?}"))?;
+ let mut node =
+ root.add_subnode(cstr!("fragment@0")).map_err(|e| anyhow!("Failed to fragment: {e:?}"))?;
+ node.setprop(cstr!("target-path"), b"/\0")
+ .map_err(|e| anyhow!("Failed to set target-path: {e:?}"))?;
+ let mut node = node
+ .add_subnode(cstr!("__overlay__"))
+ .map_err(|e| anyhow!("Failed to __overlay__ node: {e:?}"))?;
+
+ if !untrusted_props.is_empty() {
+ let mut node = node
+ .add_subnode(AVF_NODE_NAME)
+ .map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
+ let mut node = node
+ .add_subnode(UNTRUSTED_NODE_NAME)
+ .map_err(|e| anyhow!("Failed to add /avf/untrusted node: {e:?}"))?;
+ for (name, value) in untrusted_props {
+ node.setprop(name, value).map_err(|e| anyhow!("Failed to set property: {e:?}"))?;
+ }
+ }
+
+ if let Some(path) = dt_path {
+ fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
+ }
+ fdt.pack().map_err(|e| anyhow!("Failed to pack DT overlay, {e:?}"))?;
+
+ Ok(fdt)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn empty_overlays_not_allowed() {
+ let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
+ let res = create_device_tree_overlay(&mut buffer, None, &[]);
+ assert!(res.is_err());
+ }
+
+ #[test]
+ fn untrusted_prop_test() {
+ let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
+ let prop_name = cstr!("XOXO");
+ let prop_val_input = b"OXOX";
+ let fdt =
+ create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)]).unwrap();
+
+ let prop_value_dt = fdt
+ .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
+ .unwrap()
+ .expect("/avf/untrusted node doesn't exist")
+ .getprop(prop_name)
+ .unwrap()
+ .expect("Prop not found!");
+ assert_eq!(prop_value_dt, prop_val_input, "Unexpected property value");
+ }
+}
diff --git a/virtualizationmanager/src/main.rs b/virtualizationmanager/src/main.rs
index 2e542c3..b2a734a 100644
--- a/virtualizationmanager/src/main.rs
+++ b/virtualizationmanager/src/main.rs
@@ -19,8 +19,8 @@
mod composite;
mod crosvm;
mod debug_config;
+mod dt_overlay;
mod payload;
-mod reference_dt;
mod selinux;
use crate::aidl::{GLOBAL_SERVICE, VirtualizationService};
diff --git a/virtualizationmanager/src/reference_dt.rs b/virtualizationmanager/src/reference_dt.rs
deleted file mode 100644
index 797ee3c..0000000
--- a/virtualizationmanager/src/reference_dt.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.
-
-//! Functions for VM reference DT
-
-use anyhow::{anyhow, Result};
-use cstr::cstr;
-use fsfdt::FsFdt;
-use libfdt::Fdt;
-use std::fs;
-use std::fs::File;
-use std::path::Path;
-
-const VM_REFERENCE_DT_ON_HOST_PATH: &str = "/proc/device-tree/avf/reference";
-const VM_REFERENCE_DT_NAME: &str = "vm_reference_dt.dtbo";
-const VM_REFERENCE_DT_MAX_SIZE: usize = 2000;
-
-// Parses to VM reference if exists.
-// TODO(b/318431695): Allow to parse from custom VM reference DT
-pub(crate) fn parse_reference_dt(out_dir: &Path) -> Result<Option<File>> {
- parse_reference_dt_internal(
- Path::new(VM_REFERENCE_DT_ON_HOST_PATH),
- &out_dir.join(VM_REFERENCE_DT_NAME),
- )
-}
-
-fn parse_reference_dt_internal(dir_path: &Path, fdt_path: &Path) -> Result<Option<File>> {
- if !dir_path.exists() || fs::read_dir(dir_path)?.next().is_none() {
- return Ok(None);
- }
-
- let mut data = vec![0_u8; VM_REFERENCE_DT_MAX_SIZE];
-
- let fdt = Fdt::create_empty_tree(&mut data)
- .map_err(|e| anyhow!("Failed to create an empty DT, {e:?}"))?;
- let mut root = fdt.root_mut().map_err(|e| anyhow!("Failed to find the DT root, {e:?}"))?;
- let mut fragment = root
- .add_subnode(cstr!("fragment@0"))
- .map_err(|e| anyhow!("Failed to create the fragment@0, {e:?}"))?;
- fragment
- .setprop(cstr!("target-path"), b"/\0")
- .map_err(|e| anyhow!("Failed to set target-path, {e:?}"))?;
- fragment
- .add_subnode(cstr!("__overlay__"))
- .map_err(|e| anyhow!("Failed to create the __overlay__, {e:?}"))?;
-
- fdt.append(cstr!("/fragment@0/__overlay__"), dir_path)?;
-
- fdt.pack().map_err(|e| anyhow!("Failed to pack VM reference DT, {e:?}"))?;
- fs::write(fdt_path, fdt.as_slice())?;
-
- Ok(Some(File::open(fdt_path)?))
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_parse_reference_dt_from_empty_dir() {
- let empty_dir = tempfile::TempDir::new().unwrap();
- let test_dir = tempfile::TempDir::new().unwrap();
-
- let empty_dir_path = empty_dir.path();
- let fdt_path = test_dir.path().join("test.dtb");
-
- let fdt_file = parse_reference_dt_internal(empty_dir_path, &fdt_path).unwrap();
-
- assert!(fdt_file.is_none());
- }
-
- #[test]
- fn test_parse_reference_dt_from_empty_reference() {
- let fdt_file = parse_reference_dt_internal(
- Path::new("/this/path/would/not/exists"),
- Path::new("test.dtb"),
- )
- .unwrap();
-
- assert!(fdt_file.is_none());
- }
-}