162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci.. _virtio:
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci===============
662306a36Sopenharmony_ciVirtio on Linux
762306a36Sopenharmony_ci===============
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciIntroduction
1062306a36Sopenharmony_ci============
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciVirtio is an open standard that defines a protocol for communication
1362306a36Sopenharmony_cibetween drivers and devices of different types, see Chapter 5 ("Device
1462306a36Sopenharmony_ciTypes") of the virtio spec (`[1]`_). Originally developed as a standard
1562306a36Sopenharmony_cifor paravirtualized devices implemented by a hypervisor, it can be used
1662306a36Sopenharmony_cito interface any compliant device (real or emulated) with a driver.
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciFor illustrative purposes, this document will focus on the common case
1962306a36Sopenharmony_ciof a Linux kernel running in a virtual machine and using paravirtualized
2062306a36Sopenharmony_cidevices provided by the hypervisor, which exposes them as virtio devices
2162306a36Sopenharmony_civia standard mechanisms such as PCI.
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciDevice - Driver communication: virtqueues
2562306a36Sopenharmony_ci=========================================
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciAlthough the virtio devices are really an abstraction layer in the
2862306a36Sopenharmony_cihypervisor, they're exposed to the guest as if they are physical devices
2962306a36Sopenharmony_ciusing a specific transport method -- PCI, MMIO or CCW -- that is
3062306a36Sopenharmony_ciorthogonal to the device itself. The virtio spec defines these transport
3162306a36Sopenharmony_cimethods in detail, including device discovery, capabilities and
3262306a36Sopenharmony_ciinterrupt handling.
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciThe communication between the driver in the guest OS and the device in
3562306a36Sopenharmony_cithe hypervisor is done through shared memory (that's what makes virtio
3662306a36Sopenharmony_cidevices so efficient) using specialized data structures called
3762306a36Sopenharmony_civirtqueues, which are actually ring buffers [#f1]_ of buffer descriptors
3862306a36Sopenharmony_cisimilar to the ones used in a network device:
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci.. kernel-doc:: include/uapi/linux/virtio_ring.h
4162306a36Sopenharmony_ci    :identifiers: struct vring_desc
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciAll the buffers the descriptors point to are allocated by the guest and
4462306a36Sopenharmony_ciused by the host either for reading or for writing but not for both.
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciRefer to Chapter 2.5 ("Virtqueues") of the virtio spec (`[1]`_) for the
4762306a36Sopenharmony_cireference definitions of virtqueues and "Virtqueues and virtio ring: How
4862306a36Sopenharmony_cithe data travels" blog post (`[2]`_) for an illustrated overview of how
4962306a36Sopenharmony_cithe host device and the guest driver communicate.
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciThe :c:type:`vring_virtqueue` struct models a virtqueue, including the
5262306a36Sopenharmony_ciring buffers and management data. Embedded in this struct is the
5362306a36Sopenharmony_ci:c:type:`virtqueue` struct, which is the data structure that's
5462306a36Sopenharmony_ciultimately used by virtio drivers:
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci.. kernel-doc:: include/linux/virtio.h
5762306a36Sopenharmony_ci    :identifiers: struct virtqueue
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciThe callback function pointed by this struct is triggered when the
6062306a36Sopenharmony_cidevice has consumed the buffers provided by the driver. More
6162306a36Sopenharmony_cispecifically, the trigger will be an interrupt issued by the hypervisor
6262306a36Sopenharmony_ci(see vring_interrupt()). Interrupt request handlers are registered for
6362306a36Sopenharmony_cia virtqueue during the virtqueue setup process (transport-specific).
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci.. kernel-doc:: drivers/virtio/virtio_ring.c
6662306a36Sopenharmony_ci    :identifiers: vring_interrupt
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciDevice discovery and probing
7062306a36Sopenharmony_ci============================
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciIn the kernel, the virtio core contains the virtio bus driver and
7362306a36Sopenharmony_citransport-specific drivers like `virtio-pci` and `virtio-mmio`. Then
7462306a36Sopenharmony_cithere are individual virtio drivers for specific device types that are
7562306a36Sopenharmony_ciregistered to the virtio bus driver.
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciHow a virtio device is found and configured by the kernel depends on how
7862306a36Sopenharmony_cithe hypervisor defines it. Taking the `QEMU virtio-console
7962306a36Sopenharmony_ci<https://gitlab.com/qemu-project/qemu/-/blob/master/hw/char/virtio-console.c>`__
8062306a36Sopenharmony_cidevice as an example. When using PCI as a transport method, the device
8162306a36Sopenharmony_ciwill present itself on the PCI bus with vendor 0x1af4 (Red Hat, Inc.)
8262306a36Sopenharmony_ciand device id 0x1003 (virtio console), as defined in the spec, so the
8362306a36Sopenharmony_cikernel will detect it as it would do with any other PCI device.
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciDuring the PCI enumeration process, if a device is found to match the
8662306a36Sopenharmony_civirtio-pci driver (according to the virtio-pci device table, any PCI
8762306a36Sopenharmony_cidevice with vendor id = 0x1af4)::
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
9062306a36Sopenharmony_ci	static const struct pci_device_id virtio_pci_id_table[] = {
9162306a36Sopenharmony_ci		{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) },
9262306a36Sopenharmony_ci		{ 0 }
9362306a36Sopenharmony_ci	};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cithen the virtio-pci driver is probed and, if the probing goes well, the
9662306a36Sopenharmony_cidevice is registered to the virtio bus::
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	static int virtio_pci_probe(struct pci_dev *pci_dev,
9962306a36Sopenharmony_ci				    const struct pci_device_id *id)
10062306a36Sopenharmony_ci	{
10162306a36Sopenharmony_ci		...
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		if (force_legacy) {
10462306a36Sopenharmony_ci			rc = virtio_pci_legacy_probe(vp_dev);
10562306a36Sopenharmony_ci			/* Also try modern mode if we can't map BAR0 (no IO space). */
10662306a36Sopenharmony_ci			if (rc == -ENODEV || rc == -ENOMEM)
10762306a36Sopenharmony_ci				rc = virtio_pci_modern_probe(vp_dev);
10862306a36Sopenharmony_ci			if (rc)
10962306a36Sopenharmony_ci				goto err_probe;
11062306a36Sopenharmony_ci		} else {
11162306a36Sopenharmony_ci			rc = virtio_pci_modern_probe(vp_dev);
11262306a36Sopenharmony_ci			if (rc == -ENODEV)
11362306a36Sopenharmony_ci				rc = virtio_pci_legacy_probe(vp_dev);
11462306a36Sopenharmony_ci			if (rc)
11562306a36Sopenharmony_ci				goto err_probe;
11662306a36Sopenharmony_ci		}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		...
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		rc = register_virtio_device(&vp_dev->vdev);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciWhen the device is registered to the virtio bus the kernel will look
12362306a36Sopenharmony_cifor a driver in the bus that can handle the device and call that
12462306a36Sopenharmony_cidriver's ``probe`` method.
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciAt this point, the virtqueues will be allocated and configured by
12762306a36Sopenharmony_cicalling the appropriate ``virtio_find`` helper function, such as
12862306a36Sopenharmony_civirtio_find_single_vq() or virtio_find_vqs(), which will end up calling
12962306a36Sopenharmony_cia transport-specific ``find_vqs`` method.
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciReferences
13362306a36Sopenharmony_ci==========
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci_`[1]` Virtio Spec v1.2:
13662306a36Sopenharmony_cihttps://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci.. Check for later versions of the spec as well.
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci_`[2]` Virtqueues and virtio ring: How the data travels
14162306a36Sopenharmony_cihttps://www.redhat.com/en/blog/virtqueues-and-virtio-ring-how-data-travels
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci.. rubric:: Footnotes
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci.. [#f1] that's why they may be also referred to as virtrings.
146