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