blob: 6011d8f4c0c3a989246ce5b23cc791d952f7c89c [file] [log] [blame] [view]
# 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.
`__symbol__` has label of nodes, and it's required for the next step.
```dts
// generated __symbols__
__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. symbol in `__symbols__`). Must be
non-empty and unique in the XML.
* `<sysfs_path>`: Sysfs path of the device in host, used to bind to the VFIO
driver. Must be non-empty and unique in the XML.
### List support assignable devices
In order to query list of the devices that can be assigned to a pVM, run the
following command:
```bash
adb shell /apex/com.android.virt/bin/vm info
```
All supported assignable devices will be located under the "Assignable devices:"
section of the output.
## 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](../guest/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
```