Skip to content

Commit a0efa50

Browse files
docs: virtio: add virtio docs
This commit adds virtio section in documentation, describing virtio-related concepts Signed-off-by: Jakub Michalski <jmichalski@antmicro.com> Signed-off-by: Filip Kokosinski <fkokosinski@antmicro.com>
1 parent 9082049 commit a0efa50

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

doc/hardware/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ Hardware Support
1515
peripherals/index.rst
1616
pinctrl/index.rst
1717
porting/index
18+
virtualization/index.rst

doc/hardware/virtualization/index.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.. _virtualization:
2+
3+
Virtualization
4+
##############
5+
6+
These pages document Zephyr virtualization facilities.
7+
8+
.. toctree::
9+
:maxdepth: 1
10+
11+
virtio.rst
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
Virtual I/O (VIRTIO)
2+
##########################
3+
4+
Overview
5+
********
6+
7+
Virtual I/O (VIRTIO) is a protocol used for communication with various devices, typically used in
8+
virtualized environments. Its main goal is to provide an efficient and standardized mechanism for
9+
interfacing with virtual devices from within a virtual machine. The communication relies on virtqueues
10+
and standard transfer methods like PCI or MMIO.
11+
12+
Concepts
13+
********
14+
15+
Virtio defines various components used during communication and initialization. It specifies both the
16+
host (named "device" in the specification) and guest (named "driver" in the specification) sides.
17+
Currently Zephyr can only work as a guest. On top of the facilities exposed by the Virtio driver,
18+
a driver for a specific device (e.g. network card) can be implemented.
19+
20+
A high-level overview of a system with a Virtio device is shown below.
21+
22+
.. graphviz::
23+
:caption: Virtual I/O overview
24+
25+
digraph {
26+
27+
subgraph cluster_host {
28+
style=filled;
29+
color=lightgrey;
30+
label = "Host";
31+
labeljust=r;
32+
33+
virtio_device [label = "virtio device"];
34+
}
35+
36+
transfer_method [label = "virtio transfer method"];
37+
38+
subgraph cluster_guest {
39+
style=filled;
40+
color=lightgrey;
41+
label = "Guest";
42+
labeljust=r;
43+
44+
virtio_driver [label = "virtio driver"];
45+
specific_device_driver [label = "specific device driver"];
46+
device_user [label = "device user"];
47+
}
48+
49+
virtio_device -> transfer_method;
50+
transfer_method -> virtio_device;
51+
transfer_method -> virtio_driver;
52+
virtio_driver -> transfer_method;
53+
virtio_driver -> specific_device_driver;
54+
specific_device_driver -> virtio_driver;
55+
specific_device_driver -> device_user;
56+
device_user -> specific_device_driver;
57+
}
58+
59+
Configuration space
60+
===================
61+
Each device provides configuration space, used for initialization and configuration. It allows
62+
selection of device and driver features, enabling specific virtqueues and setting their addresses.
63+
Once the device is configured, most of its configuration cannot be changed without resetting the device.
64+
The exact layout of the configuration space depends on the transfer method.
65+
66+
Driver and device features
67+
--------------------------
68+
The configuration space provides a way to negotiate feature bits, determining some non-mandatory
69+
capabilities of the devices. The exact available feature bits depend on the device and platform.
70+
71+
Device-specific configuration
72+
-----------------------------
73+
Some of the devices offer device-specific configuration space, providing additional configuration options.
74+
75+
Virtqueues
76+
==========
77+
The main mechanism used for transferring data between host and guest is a virtqueue. Specific
78+
devices have different numbers of virtqueues, for example devices supporting bidirectional transfer
79+
usually have one or more tx/rx virtqueue pairs. Virtio specifies two types of virtqueues: split
80+
virtqueues and packed virtqueues. Zephyr currently supports only split virtqueues.
81+
82+
Split virtqueues
83+
----------------
84+
A split virtqueue consists of three parts: descriptor table, available ring and used ring.
85+
86+
The descriptor table holds descriptors of buffers, that is their physical addresses, lengths and flags.
87+
Each descriptor is either device writeable or driver writeable. The descriptors can be chained, creating
88+
descriptor chains. Typically a chain begins with descriptors containing the data for the device to read
89+
and ends with the device writeable part, where the device places its response.
90+
91+
The main part of the available ring is a circular buffer of references (in the form of indexes) to the
92+
descriptors in the descriptor table. Once the guest decides to send the data to the host, it adds the index of
93+
the head of the descriptor chain to the top of the available ring.
94+
95+
The used ring is similar to the available ring, but it's used by the host to return descriptors to the guest. In
96+
addition to storing descriptor indexes, it also provides information about the amount of data written to them.
97+
98+
Common Virtio libraries
99+
***********************
100+
101+
Zephyr provides an API for interfacing with Virtio devices and virtqueues, which allows performing necessary operations
102+
over the lifetime of the Virtio device.
103+
104+
Device initialization
105+
=====================
106+
Once the Virtio driver finishes performing low-level initialization common to the all devices using a given transfer method,
107+
like finding device on the bus and mapping Virtio structures, the device specific driver steps in and performs the next
108+
stages of initialization with the help of the Virtio API.
109+
110+
The first thing the device-specific driver does is feature bits negotiation. It uses :c:func:`virtio_read_device_feature_bit`
111+
to determine which features the device offers, and then selects the ones it needs using :c:func:`virtio_write_driver_feature_bit`.
112+
After all required features have been selected, the device-specific driver calls :c:func:`virtio_commit_feature_bits`. Then, virtqueues
113+
are initialized with :c:func:`virtio_init_virtqueues`. This function enumerates the virtqueues, invoking the provided callback
114+
:c:type:`virtio_enumerate_queues` to determine the required size of each virtqueue. Initialization process is finalized by calling
115+
:c:func:`virtio_finalize_init`. From this point, if none of the functions returned errors, the virtqueues are operational. If the
116+
specific device provides one, the device-specific config can be obtained by calling :c:func:`virtio_get_device_specific_config`.
117+
118+
Virtqueue operation
119+
===================
120+
Once the virtqueues are operational, they can be used to send and receive data. To do so, the pointer to the nth
121+
virtqueue has to be acquired using :c:func:`virtio_get_virtqueue`. To send data consisting of a descriptor chain,
122+
:c:func:`virtq_add_buffer_chain` has to be used. Along the descriptor chain, it takes pointer to the callback that
123+
will be invoked once the device returns the given descriptor chain. After that, the virtqueue has to be notified using
124+
:c:func:`virtio_notify_virtqueue` from the Virtio API.
125+
126+
API Reference
127+
*************
128+
129+
.. doxygengroup:: virtio_interface
130+
.. doxygengroup:: virtqueue_interface

include/zephyr/virtio/virtio.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
extern "C" {
1414
#endif
1515

16+
/**
17+
* @brief Virtio Interface
18+
* @defgroup virtio_interface Virtio Interface
19+
* @{
20+
*/
21+
1622

1723
/**
1824
* Callback used during virtqueue enumeration

include/zephyr/virtio/virtqueue.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,21 @@
1010
#include <stddef.h>
1111
#include <zephyr/kernel.h>
1212

13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
1317
/*
1418
* Based on Virtual I/O Device (VIRTIO) Version 1.3 specification:
1519
* https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.pdf
1620
*/
1721

22+
/**
23+
* @brief Virtqueue Interface
24+
* @defgroup virtqueue_interface Virtqueue Interface
25+
* @{
26+
*/
27+
1828
/**
1929
* used in virtq_desc::flags, enables chaining descriptor via virtq_desc::next
2030
*/
@@ -252,4 +262,12 @@ void virtq_add_free_desc(struct virtq *v, uint16_t desc_idx);
252262
*/
253263
int virtq_get_free_desc(struct virtq *v, uint16_t *desc_idx, k_timeout_t timeout);
254264

265+
/**
266+
* @}
267+
*/
268+
269+
#ifdef __cplusplus
270+
}
271+
#endif
272+
255273
#endif /* ZEPHYR_VIRTIO_VIRTQUEUE_H_ */

0 commit comments

Comments
 (0)