1.. SPDX-License-Identifier: GPL-2.0+ 2.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com> 3 4VirtIO Support 5============== 6 7This document describes the information about U-Boot support for VirtIO_ 8devices, including supported boards, build instructions, driver details etc. 9 10What's VirtIO? 11-------------- 12VirtIO is a virtualization standard for network and disk device drivers where 13just the guest's device driver "knows" it is running in a virtual environment, 14and cooperates with the hypervisor. This enables guests to get high performance 15network and disk operations, and gives most of the performance benefits of 16paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the 17virtual environment are normally QEMU_ targets like ARM, RISC-V and x86. 18 19Status 20------ 21VirtIO can use various different buses, aka transports as described in the 22spec. While VirtIO devices are commonly implemented as PCI devices on x86, 23embedded devices models like ARM/RISC-V, which does not normally come with 24PCI support might use simple memory mapped device (MMIO) instead of the PCI 25device. The memory mapped virtio device behaviour is based on the PCI device 26specification. Therefore most operations including device initialization, 27queues configuration and buffer transfers are nearly identical. Both MMIO 28and PCI transport options are supported in U-Boot. 29 30The VirtIO spec defines a lots of VirtIO device types, however at present only 31network and block device, the most two commonly used devices, are supported. 32 33The following QEMU targets are supported. 34 35 - qemu_arm_defconfig 36 - qemu_arm64_defconfig 37 - qemu-riscv32_defconfig 38 - qemu-riscv64_defconfig 39 - qemu-x86_defconfig 40 - qemu-x86_64_defconfig 41 42Note ARM and RISC-V targets are configured with VirtIO MMIO transport driver, 43and on x86 it's the PCI transport driver. 44 45Build Instructions 46------------------ 47Building U-Boot for pre-configured QEMU targets is no different from others. 48For example, we can do the following with the CROSS_COMPILE environment 49variable being properly set to a working toolchain for ARM: 50 51.. code-block:: bash 52 53 $ make qemu_arm_defconfig 54 $ make 55 56You can even create a QEMU ARM target with VirtIO devices showing up on both 57MMIO and PCI buses. In this case, you can enable the PCI transport driver 58from 'make menuconfig': 59 60.. code-block:: none 61 62 Device Drivers ---> 63 ... 64 VirtIO Drivers ---> 65 ... 66 [*] PCI driver for virtio devices 67 68Other drivers are at the same location and can be tuned to suit the needs. 69 70Requirements 71------------ 72It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support 73on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V. 74 75Testing 76------- 77The following QEMU command line is used to get U-Boot up and running with 78VirtIO net and block devices on ARM. 79 80.. code-block:: bash 81 82 $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \ 83 -netdev tap,ifname=tap0,id=net0 \ 84 -device virtio-net-device,netdev=net0 \ 85 -drive if=none,file=test.img,format=raw,id=hd0 \ 86 -device virtio-blk-device,drive=hd0 87 88On x86, command is slightly different to create PCI VirtIO devices. 89 90.. code-block:: bash 91 92 $ qemu-system-i386 -nographic -bios u-boot.rom \ 93 -netdev tap,ifname=tap0,id=net0 \ 94 -device virtio-net-pci,netdev=net0 \ 95 -drive if=none,file=test.img,format=raw,id=hd0 \ 96 -device virtio-blk-pci,drive=hd0 97 98Additional net and block devices can be created by appending more '-device' 99parameters. It is also possible to specify both MMIO and PCI VirtIO devices. 100For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO 101and 2 on PCI bus. 102 103.. code-block:: bash 104 105 $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \ 106 -netdev tap,ifname=tap0,id=net0 \ 107 -device virtio-net-pci,netdev=net0 \ 108 -drive if=none,file=test0.img,format=raw,id=hd0 \ 109 -device virtio-blk-device,drive=hd0 \ 110 -drive if=none,file=test1.img,format=raw,id=hd1 \ 111 -device virtio-blk-pci,drive=hd1 112 113By default QEMU creates VirtIO legacy devices by default. To create non-legacy 114(aka modern) devices, pass additional device property/value pairs like below: 115 116.. code-block:: bash 117 118 $ qemu-system-i386 -nographic -bios u-boot.rom \ 119 -netdev tap,ifname=tap0,id=net0 \ 120 -device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \ 121 -drive if=none,file=test.img,format=raw,id=hd0 \ 122 -device virtio-blk-pci,drive=hd0,disable-legacy=true,disable-modern=false 123 124A 'virtio' command is provided in U-Boot shell. 125 126.. code-block:: none 127 128 => virtio 129 virtio - virtio block devices sub-system 130 131 Usage: 132 virtio scan - initialize virtio bus 133 virtio info - show all available virtio block devices 134 virtio device [dev] - show or set current virtio block device 135 virtio part [dev] - print partition table of one or all virtio block devices 136 virtio read addr blk# cnt - read `cnt' blocks starting at block 137 `blk#' to memory address `addr' 138 virtio write addr blk# cnt - write `cnt' blocks starting at block 139 `blk#' from memory address `addr' 140 141To probe all the VirtIO devices, type: 142 143.. code-block:: none 144 145 => virtio scan 146 147Then we can show the connected block device details by: 148 149.. code-block:: none 150 151 => virtio info 152 Device 0: QEMU VirtIO Block Device 153 Type: Hard Disk 154 Capacity: 4096.0 MB = 4.0 GB (8388608 x 512) 155 156And list the directories and files on the disk by: 157 158.. code-block:: none 159 160 => ls virtio 0 / 161 <DIR> 4096 . 162 <DIR> 4096 .. 163 <DIR> 16384 lost+found 164 <DIR> 4096 dev 165 <DIR> 4096 proc 166 <DIR> 4096 sys 167 <DIR> 4096 var 168 <DIR> 4096 etc 169 <DIR> 4096 usr 170 <SYM> 7 bin 171 <SYM> 8 sbin 172 <SYM> 7 lib 173 <SYM> 9 lib64 174 <DIR> 4096 run 175 <DIR> 4096 boot 176 <DIR> 4096 home 177 <DIR> 4096 media 178 <DIR> 4096 mnt 179 <DIR> 4096 opt 180 <DIR> 4096 root 181 <DIR> 4096 srv 182 <DIR> 4096 tmp 183 0 .autorelabel 184 185Driver Internals 186---------------- 187There are 3 level of drivers in the VirtIO driver family. 188 189.. code-block:: none 190 191 +---------------------------------------+ 192 | virtio device drivers | 193 | +-------------+ +------------+ | 194 | | virtio-net | | virtio-blk | | 195 | +-------------+ +------------+ | 196 +---------------------------------------+ 197 +---------------------------------------+ 198 | virtio transport drivers | 199 | +-------------+ +------------+ | 200 | | virtio-mmio | | virtio-pci | | 201 | +-------------+ +------------+ | 202 +---------------------------------------+ 203 +----------------------+ 204 | virtio uclass driver | 205 +----------------------+ 206 207The root one is the virtio uclass driver (virtio-uclass.c), which does lots of 208common stuff for the transport drivers (virtio_mmio.c, virtio_pci.c). The real 209virtio device is discovered in the transport driver's probe() method, and its 210device ID is saved in the virtio uclass's private data of the transport device. 211Then in the virtio uclass's post_probe() method, the real virtio device driver 212(virtio_net.c, virtio_blk.c) is bound if there is a match on the device ID. 213 214The child_post_bind(), child_pre_probe() and child_post_probe() methods of the 215virtio uclass driver help bring the virtio device driver online. They do things 216like acknowledging device, feature negotiation, etc, which are really common 217for all virtio devices. 218 219The transport drivers provide a set of ops (struct dm_virtio_ops) for the real 220virtio device driver to call. These ops APIs's parameter is designed to remind 221the caller to pass the correct 'struct udevice' id of the virtio device, eg: 222 223.. code-block:: C 224 225 int virtio_get_status(struct udevice *vdev, u8 *status) 226 227So the parameter 'vdev' indicates the device should be the real virtio device. 228But we also have an API like: 229 230.. code-block:: C 231 232 struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, 233 unsigned int vring_align, 234 struct udevice *udev) 235 236Here the parameter 'udev' indicates the device should be the transport device. 237Similar naming is applied in other functions that are even not APIs, eg: 238 239.. code-block:: C 240 241 static int virtio_uclass_post_probe(struct udevice *udev) 242 static int virtio_uclass_child_pre_probe(struct udevice *vdev) 243 244So it's easy to tell which device these functions are operating on. 245 246Development Flow 247---------------- 248At present only VirtIO network card (device ID 1) and block device (device 249ID 2) are supported. If you want to develop new driver for new devices, 250please follow the guideline below. 251 2521. add new device ID in virtio.h 253 254.. code-block:: C 255 256 #define VIRTIO_ID_XXX X 257 2582. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1 259 2603. add new driver name string in virtio.h 261 262.. code-block:: C 263 264 #define VIRTIO_XXX_DRV_NAME "virtio-xxx" 265 2664. create a new driver with name set to the name string above 267 268.. code-block:: C 269 270 U_BOOT_DRIVER(virtio_xxx) = { 271 .name = VIRTIO_XXX_DRV_NAME, 272 ... 273 .remove = virtio_reset, 274 .flags = DM_FLAG_ACTIVE_DMA, 275 } 276 277Note the driver needs to provide the remove method and normally this can be 278hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA 279for the remove method to be called before jumping to OS. 280 2815. provide bind() method in the driver, where virtio_driver_features_init() 282 should be called for driver to negotiate feature support with the device. 283 2846. do funny stuff with the driver 285 286.. _VirtIO: http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf 287.. _QEMU: https://www.qemu.org 288