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