1Virtual I/O (VIRTIO) 2########################## 3 4Overview 5******** 6 7Virtual I/O (VIRTIO) is a protocol used for communication with various devices, typically used in 8virtualized environments. Its main goal is to provide an efficient and standardized mechanism for 9interfacing with virtual devices from within a virtual machine. The communication relies on virtqueues 10and standard transfer methods like PCI or MMIO. 11 12Concepts 13******** 14 15Virtio defines various components used during communication and initialization. It specifies both the 16host (named "device" in the specification) and guest (named "driver" in the specification) sides. 17Currently Zephyr can only work as a guest. On top of the facilities exposed by the Virtio driver, 18a driver for a specific device (e.g. network card) can be implemented. 19 20A 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 59Configuration space 60=================== 61Each device provides configuration space, used for initialization and configuration. It allows 62selection of device and driver features, enabling specific virtqueues and setting their addresses. 63Once the device is configured, most of its configuration cannot be changed without resetting the device. 64The exact layout of the configuration space depends on the transfer method. 65 66Driver and device features 67-------------------------- 68The configuration space provides a way to negotiate feature bits, determining some non-mandatory 69capabilities of the devices. The exact available feature bits depend on the device and platform. 70 71Device-specific configuration 72----------------------------- 73Some of the devices offer device-specific configuration space, providing additional configuration options. 74 75Virtqueues 76========== 77The main mechanism used for transferring data between host and guest is a virtqueue. Specific 78devices have different numbers of virtqueues, for example devices supporting bidirectional transfer 79usually have one or more tx/rx virtqueue pairs. Virtio specifies two types of virtqueues: split 80virtqueues and packed virtqueues. Zephyr currently supports only split virtqueues. 81 82Split virtqueues 83---------------- 84A split virtqueue consists of three parts: descriptor table, available ring and used ring. 85 86The descriptor table holds descriptors of buffers, that is their physical addresses, lengths and flags. 87Each descriptor is either device writeable or driver writeable. The descriptors can be chained, creating 88descriptor chains. Typically a chain begins with descriptors containing the data for the device to read 89and ends with the device writeable part, where the device places its response. 90 91The main part of the available ring is a circular buffer of references (in the form of indexes) to the 92descriptors in the descriptor table. Once the guest decides to send the data to the host, it adds the index of 93the head of the descriptor chain to the top of the available ring. 94 95The used ring is similar to the available ring, but it's used by the host to return descriptors to the guest. In 96addition to storing descriptor indexes, it also provides information about the amount of data written to them. 97 98Common Virtio libraries 99*********************** 100 101Zephyr provides an API for interfacing with Virtio devices and virtqueues, which allows performing necessary operations 102over the lifetime of the Virtio device. 103 104Device initialization 105===================== 106Once the Virtio driver finishes performing low-level initialization common to the all devices using a given transfer method, 107like finding device on the bus and mapping Virtio structures, the device specific driver steps in and performs the next 108stages of initialization with the help of the Virtio API. 109 110The first thing the device-specific driver does is feature bits negotiation. It uses :c:func:`virtio_read_device_feature_bit` 111to determine which features the device offers, and then selects the ones it needs using :c:func:`virtio_write_driver_feature_bit`. 112After all required features have been selected, the device-specific driver calls :c:func:`virtio_commit_feature_bits`. Then, virtqueues 113are 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 116specific device provides one, the device-specific config can be obtained by calling :c:func:`virtio_get_device_specific_config`. 117 118Virtqueue operation 119=================== 120Once the virtqueues are operational, they can be used to send and receive data. To do so, the pointer to the nth 121virtqueue 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 123will 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 126Guest-side Virtio drivers 127************************* 128Currently Zephyr provides drivers for Virtio over PCI and Virtio over MMIO and drivers for two devices using virtio - virtiofs, used 129to access the filesystem of the host and virtio-entropy, used as an entropy source. 130 131Virtiofs 132========= 133This driver provides support for `virtiofs <https://virtio-fs.gitlab.io/>`_ - a filesystem allowing a virtual machine guest to access 134a directory on the host. It uses FUSE messages to communicate between the host and the guest in order to perform filesystem operations such as 135opening and reading files. Every time the guest wants to perform some filesystem operation it places in the virtqueue a descriptor chain 136starting with the device readable part, containing the FUSE input header and input data, and ending it with the device writeable part, with place 137for the FUSE output header and output data. 138 139Virtio-entropy 140============== 141This driver allows using virtio-entropy as an entropy source in Zephyr. The operation of this device is simple - the driver places a 142buffer in the virtqueue and receives it back, filled with random data. 143 144Virtio samples 145************** 146A sample showcasing the use of a driver relying on Virtio is provided in :zephyr:code-sample:`virtiofs`. If you wish 147to check code interfacing directly with the Virtio driver, you can check the virtiofs driver, especially :c:func:`virtiofs_init` 148for initialization and :c:func:`virtiofs_send_receive` with the :c:func:`virtiofs_recv_cb` for data transfer to/from 149the Virtio device. 150 151API Reference 152************* 153 154.. doxygengroup:: virtio_interface 155.. doxygengroup:: virtqueue_interface 156