Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 1 | .. SPDX-License-Identifier: GPL-2.0+ |
| 2 | .. sectionauthor:: Bin Meng <bmeng.cn@gmail.com> |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 3 | |
| 4 | VirtIO Support |
| 5 | ============== |
| 6 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 7 | This document describes the information about U-Boot support for VirtIO_ |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 8 | devices, including supported boards, build instructions, driver details etc. |
| 9 | |
| 10 | What's VirtIO? |
| 11 | -------------- |
| 12 | VirtIO is a virtualization standard for network and disk device drivers where |
| 13 | just the guest's device driver "knows" it is running in a virtual environment, |
| 14 | and cooperates with the hypervisor. This enables guests to get high performance |
| 15 | network and disk operations, and gives most of the performance benefits of |
| 16 | paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 17 | virtual environment are normally QEMU_ targets like ARM, RISC-V and x86. |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 18 | |
| 19 | Status |
| 20 | ------ |
| 21 | VirtIO can use various different buses, aka transports as described in the |
| 22 | spec. While VirtIO devices are commonly implemented as PCI devices on x86, |
| 23 | embedded devices models like ARM/RISC-V, which does not normally come with |
| 24 | PCI support might use simple memory mapped device (MMIO) instead of the PCI |
| 25 | device. The memory mapped virtio device behaviour is based on the PCI device |
| 26 | specification. Therefore most operations including device initialization, |
| 27 | queues configuration and buffer transfers are nearly identical. Both MMIO |
| 28 | and PCI transport options are supported in U-Boot. |
| 29 | |
| 30 | The VirtIO spec defines a lots of VirtIO device types, however at present only |
| 31 | network and block device, the most two commonly used devices, are supported. |
| 32 | |
| 33 | The following QEMU targets are supported. |
| 34 | |
| 35 | - qemu_arm_defconfig |
| 36 | - qemu_arm64_defconfig |
Patrick Rudolph | cb42bc8 | 2024-10-23 15:20:08 +0200 | [diff] [blame] | 37 | - qemu-arm-sbsa_defconfig |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 38 | - qemu-riscv32_defconfig |
| 39 | - qemu-riscv64_defconfig |
| 40 | - qemu-x86_defconfig |
| 41 | - qemu-x86_64_defconfig |
| 42 | |
| 43 | Note ARM and RISC-V targets are configured with VirtIO MMIO transport driver, |
| 44 | and on x86 it's the PCI transport driver. |
| 45 | |
| 46 | Build Instructions |
| 47 | ------------------ |
| 48 | Building U-Boot for pre-configured QEMU targets is no different from others. |
| 49 | For example, we can do the following with the CROSS_COMPILE environment |
| 50 | variable being properly set to a working toolchain for ARM: |
| 51 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 52 | .. code-block:: bash |
| 53 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 54 | $ make qemu_arm_defconfig |
| 55 | $ make |
| 56 | |
| 57 | You can even create a QEMU ARM target with VirtIO devices showing up on both |
| 58 | MMIO and PCI buses. In this case, you can enable the PCI transport driver |
| 59 | from 'make menuconfig': |
| 60 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 61 | .. code-block:: none |
| 62 | |
| 63 | Device Drivers ---> |
| 64 | ... |
| 65 | VirtIO Drivers ---> |
| 66 | ... |
| 67 | [*] PCI driver for virtio devices |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 68 | |
| 69 | Other drivers are at the same location and can be tuned to suit the needs. |
| 70 | |
| 71 | Requirements |
| 72 | ------------ |
| 73 | It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support |
| 74 | on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V. |
| 75 | |
| 76 | Testing |
| 77 | ------- |
| 78 | The following QEMU command line is used to get U-Boot up and running with |
| 79 | VirtIO net and block devices on ARM. |
| 80 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 81 | .. code-block:: bash |
| 82 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 89 | On x86, command is slightly different to create PCI VirtIO devices. |
| 90 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 91 | .. code-block:: bash |
| 92 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 99 | Additional net and block devices can be created by appending more '-device' |
| 100 | parameters. It is also possible to specify both MMIO and PCI VirtIO devices. |
| 101 | For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO |
| 102 | and 2 on PCI bus. |
| 103 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 104 | .. code-block:: bash |
| 105 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 114 | By 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 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 117 | .. code-block:: bash |
| 118 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 125 | A 'virtio' command is provided in U-Boot shell. |
| 126 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 127 | .. code-block:: none |
| 128 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 142 | To probe all the VirtIO devices, type: |
| 143 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 144 | .. code-block:: none |
| 145 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 146 | => virtio scan |
| 147 | |
| 148 | Then we can show the connected block device details by: |
| 149 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 150 | .. code-block:: none |
| 151 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 157 | And list the directories and files on the disk by: |
| 158 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 159 | .. code-block:: none |
| 160 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 186 | Driver Internals |
| 187 | ---------------- |
| 188 | There are 3 level of drivers in the VirtIO driver family. |
| 189 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 190 | .. code-block:: none |
| 191 | |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 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 | |
| 208 | The root one is the virtio uclass driver (virtio-uclass.c), which does lots of |
| 209 | common stuff for the transport drivers (virtio_mmio.c, virtio_pci.c). The real |
| 210 | virtio device is discovered in the transport driver's probe() method, and its |
| 211 | device ID is saved in the virtio uclass's private data of the transport device. |
| 212 | Then 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 | |
| 215 | The child_post_bind(), child_pre_probe() and child_post_probe() methods of the |
| 216 | virtio uclass driver help bring the virtio device driver online. They do things |
| 217 | like acknowledging device, feature negotiation, etc, which are really common |
| 218 | for all virtio devices. |
| 219 | |
| 220 | The transport drivers provide a set of ops (struct dm_virtio_ops) for the real |
| 221 | virtio device driver to call. These ops APIs's parameter is designed to remind |
| 222 | the caller to pass the correct 'struct udevice' id of the virtio device, eg: |
| 223 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 224 | .. code-block:: C |
| 225 | |
| 226 | int virtio_get_status(struct udevice *vdev, u8 *status) |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 227 | |
| 228 | So the parameter 'vdev' indicates the device should be the real virtio device. |
| 229 | But we also have an API like: |
| 230 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 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) |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 236 | |
| 237 | Here the parameter 'udev' indicates the device should be the transport device. |
| 238 | Similar naming is applied in other functions that are even not APIs, eg: |
| 239 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 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) |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 244 | |
| 245 | So it's easy to tell which device these functions are operating on. |
| 246 | |
| 247 | Development Flow |
| 248 | ---------------- |
| 249 | At present only VirtIO network card (device ID 1) and block device (device |
| 250 | ID 2) are supported. If you want to develop new driver for new devices, |
| 251 | please follow the guideline below. |
| 252 | |
| 253 | 1. add new device ID in virtio.h |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 254 | |
| 255 | .. code-block:: C |
| 256 | |
| 257 | #define VIRTIO_ID_XXX X |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 258 | |
| 259 | 2. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1 |
| 260 | |
| 261 | 3. add new driver name string in virtio.h |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 262 | |
| 263 | .. code-block:: C |
| 264 | |
| 265 | #define VIRTIO_XXX_DRV_NAME "virtio-xxx" |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 266 | |
| 267 | 4. create a new driver with name set to the name string above |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 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 | } |
Bin Meng | f170edf | 2018-10-15 02:21:27 -0700 | [diff] [blame] | 277 | |
| 278 | Note the driver needs to provide the remove method and normally this can be |
| 279 | hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA |
| 280 | for the remove method to be called before jumping to OS. |
| 281 | |
| 282 | 5. 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 | |
| 285 | 6. do funny stuff with the driver |
| 286 | |
Bin Meng | ad48bd9 | 2021-04-29 17:40:07 +0800 | [diff] [blame] | 287 | .. _VirtIO: http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf |
| 288 | .. _QEMU: https://www.qemu.org |