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