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