Merge "Replace use of deprecated logging functions" into main
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/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/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/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..d7486f9 100644
--- a/pvmfw/platform.dts
+++ b/pvmfw/platform.dts
@@ -57,96 +57,432 @@
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
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>; };
+ };
};
};
@@ -321,4 +657,9 @@
id = <PLACEHOLDER>;
#iommu-cells = <1>;
};
+
+ cpufreq {
+ compatible = "virtual,android-v-only-cpufreq";
+ reg = <0x1040000 PLACEHOLDER2>;
+ };
};
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index ac52be9..65b46c0 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 = 16;
+}
+
+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; DeviceTreeInfo::MAX_CPUS]>>,
+) -> 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/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index e9c84fb..2d52732 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -49,7 +49,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
@@ -277,10 +276,6 @@
(builder) -> builder);
}
- // TODO(b/323768068): Enable this test when we can inject vendor digest for test purpose.
- // After introducing VM reference DT, non-pVM cannot trust test_microdroid_vendor_image.img
- // as well, because it doesn't pass the hashtree digest of testing image into VM.
- @Ignore
@Test
public void testMicrodroidDebugBootTime_withVendorPartition() throws Exception {
assume().withMessage("Cuttlefish doesn't support device tree under" + " /proc/device-tree")
@@ -293,8 +288,10 @@
.isFalse();
assumeFeatureEnabled(VirtualMachineManager.FEATURE_VENDOR_MODULES);
- File vendorDiskImage =
- new File("/data/local/tmp/microdroid-bench/microdroid_vendor_image.img");
+ File vendorDiskImage = new File("/vendor/etc/avf/microdroid/microdroid_vendor.img");
+ assume().withMessage("Microdroid vendor image doesn't exist, skip")
+ .that(vendorDiskImage.exists())
+ .isTrue();
runBootTimeTest(
"test_vm_boot_time_debug_with_vendor_partition",
"assets/" + os() + "/vm_config.json",
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 4e340f0..0687a7b 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -73,7 +73,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
@@ -2157,10 +2156,6 @@
.contains("android.permission.USE_CUSTOM_VIRTUAL_MACHINE permission");
}
- // TODO(b/323768068): Enable this test when we can inject vendor digest for test purpose.
- // After introducing VM reference DT, non-pVM cannot trust test_microdroid_vendor_image.img
- // as well, because it doesn't pass the hashtree digest of testing image into VM.
- @Ignore
@Test
public void bootsWithVendorPartition() throws Exception {
assumeSupportedDevice();
@@ -2174,8 +2169,8 @@
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
- File vendorDiskImage =
- new File("/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img");
+ File vendorDiskImage = new File("/vendor/etc/avf/microdroid/microdroid_vendor.img");
+ assumeTrue("Microdroid vendor image doesn't exist, skip", vendorDiskImage.exists());
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
.setVendorDiskImage(vendorDiskImage)