1bcf317f8SAlex Bennée.. 2bcf317f8SAlex Bennée Copyright (c) 2022, Linaro Limited 3bcf317f8SAlex Bennée Written by Alex Bennée 4bcf317f8SAlex Bennée 5bcf317f8SAlex BennéeWriting VirtIO backends for QEMU 6bcf317f8SAlex Bennée================================ 7bcf317f8SAlex Bennée 8bcf317f8SAlex BennéeThis document attempts to outline the information a developer needs to 9bcf317f8SAlex Bennéeknow to write device emulations in QEMU. It is specifically focused on 10bcf317f8SAlex Bennéeimplementing VirtIO devices. For VirtIO the frontend is the driver 11bcf317f8SAlex Bennéerunning on the guest. The backend is the everything that QEMU needs to 12bcf317f8SAlex Bennéedo to handle the emulation of the VirtIO device. This can be done 13bcf317f8SAlex Bennéeentirely in QEMU, divided between QEMU and the kernel (vhost) or 14bcf317f8SAlex Bennéehandled by a separate process which is configured by QEMU 15bcf317f8SAlex Bennée(vhost-user). 16bcf317f8SAlex Bennée 17bcf317f8SAlex BennéeVirtIO Transports 18bcf317f8SAlex Bennée----------------- 19bcf317f8SAlex Bennée 20bcf317f8SAlex BennéeVirtIO supports a number of different transports. While the details of 21bcf317f8SAlex Bennéethe configuration and operation of the device will generally be the 22bcf317f8SAlex Bennéesame QEMU represents them as different devices depending on the 23bcf317f8SAlex Bennéetransport they use. For example -device virtio-foo represents the foo 24bcf317f8SAlex Bennéedevice using mmio and -device virtio-foo-pci is the same class of 25bcf317f8SAlex Bennéedevice using the PCI transport. 26bcf317f8SAlex Bennée 27bcf317f8SAlex BennéeUsing the QEMU Object Model (QOM) 28bcf317f8SAlex Bennée--------------------------------- 29bcf317f8SAlex Bennée 30bcf317f8SAlex BennéeGenerally all devices in QEMU are super classes of ``TYPE_DEVICE`` 31bcf317f8SAlex Bennéehowever VirtIO devices should be based on ``TYPE_VIRTIO_DEVICE`` which 32bcf317f8SAlex Bennéeitself is derived from the base class. For example: 33bcf317f8SAlex Bennée 34bcf317f8SAlex Bennée.. code:: c 35bcf317f8SAlex Bennée 36bcf317f8SAlex Bennée static const TypeInfo virtio_blk_info = { 37bcf317f8SAlex Bennée .name = TYPE_VIRTIO_BLK, 38bcf317f8SAlex Bennée .parent = TYPE_VIRTIO_DEVICE, 39bcf317f8SAlex Bennée .instance_size = sizeof(VirtIOBlock), 40bcf317f8SAlex Bennée .instance_init = virtio_blk_instance_init, 41bcf317f8SAlex Bennée .class_init = virtio_blk_class_init, 42bcf317f8SAlex Bennée }; 43bcf317f8SAlex Bennée 44bcf317f8SAlex BennéeThe author may decide to have a more expansive class hierarchy to 45bcf317f8SAlex Bennéesupport multiple device types. For example the Virtio GPU device: 46bcf317f8SAlex Bennée 47bcf317f8SAlex Bennée.. code:: c 48bcf317f8SAlex Bennée 49bcf317f8SAlex Bennée static const TypeInfo virtio_gpu_base_info = { 50bcf317f8SAlex Bennée .name = TYPE_VIRTIO_GPU_BASE, 51bcf317f8SAlex Bennée .parent = TYPE_VIRTIO_DEVICE, 52bcf317f8SAlex Bennée .instance_size = sizeof(VirtIOGPUBase), 53bcf317f8SAlex Bennée .class_size = sizeof(VirtIOGPUBaseClass), 54bcf317f8SAlex Bennée .class_init = virtio_gpu_base_class_init, 55bcf317f8SAlex Bennée .abstract = true 56bcf317f8SAlex Bennée }; 57bcf317f8SAlex Bennée 58bcf317f8SAlex Bennée static const TypeInfo vhost_user_gpu_info = { 59bcf317f8SAlex Bennée .name = TYPE_VHOST_USER_GPU, 60bcf317f8SAlex Bennée .parent = TYPE_VIRTIO_GPU_BASE, 61bcf317f8SAlex Bennée .instance_size = sizeof(VhostUserGPU), 62bcf317f8SAlex Bennée .instance_init = vhost_user_gpu_instance_init, 63bcf317f8SAlex Bennée .instance_finalize = vhost_user_gpu_instance_finalize, 64bcf317f8SAlex Bennée .class_init = vhost_user_gpu_class_init, 65bcf317f8SAlex Bennée }; 66bcf317f8SAlex Bennée 67bcf317f8SAlex Bennée static const TypeInfo virtio_gpu_info = { 68bcf317f8SAlex Bennée .name = TYPE_VIRTIO_GPU, 69bcf317f8SAlex Bennée .parent = TYPE_VIRTIO_GPU_BASE, 70bcf317f8SAlex Bennée .instance_size = sizeof(VirtIOGPU), 71bcf317f8SAlex Bennée .class_size = sizeof(VirtIOGPUClass), 72bcf317f8SAlex Bennée .class_init = virtio_gpu_class_init, 73bcf317f8SAlex Bennée }; 74bcf317f8SAlex Bennée 75bcf317f8SAlex Bennéedefines a base class for the VirtIO GPU and then specialises two 76bcf317f8SAlex Bennéeversions, one for the internal implementation and the other for the 77bcf317f8SAlex Bennéevhost-user version. 78bcf317f8SAlex Bennée 79bcf317f8SAlex BennéeVirtIOPCIProxy 80bcf317f8SAlex Bennée^^^^^^^^^^^^^^ 81bcf317f8SAlex Bennée 82bcf317f8SAlex Bennée[AJB: the following is supposition and welcomes more informed 83bcf317f8SAlex Bennéeopinions] 84bcf317f8SAlex Bennée 85bcf317f8SAlex BennéeProbably due to legacy from the pre-QOM days PCI VirtIO devices don't 86bcf317f8SAlex Bennéefollow the normal hierarchy. Instead the a standalone object is based 87bcf317f8SAlex Bennéeon the VirtIOPCIProxy class and the specific VirtIO instance is 88bcf317f8SAlex Bennéemanually instantiated: 89bcf317f8SAlex Bennée 90bcf317f8SAlex Bennée.. code:: c 91bcf317f8SAlex Bennée 92bcf317f8SAlex Bennée /* 93bcf317f8SAlex Bennée * virtio-blk-pci: This extends VirtioPCIProxy. 94bcf317f8SAlex Bennée */ 95bcf317f8SAlex Bennée #define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" 96bcf317f8SAlex Bennée DECLARE_INSTANCE_CHECKER(VirtIOBlkPCI, VIRTIO_BLK_PCI, 97bcf317f8SAlex Bennée TYPE_VIRTIO_BLK_PCI) 98bcf317f8SAlex Bennée 99bcf317f8SAlex Bennée struct VirtIOBlkPCI { 100bcf317f8SAlex Bennée VirtIOPCIProxy parent_obj; 101bcf317f8SAlex Bennée VirtIOBlock vdev; 102bcf317f8SAlex Bennée }; 103bcf317f8SAlex Bennée 104*fd363a14SRichard Henderson static const Property virtio_blk_pci_properties[] = { 105bcf317f8SAlex Bennée DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), 106bcf317f8SAlex Bennée DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, 107bcf317f8SAlex Bennée VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), 108bcf317f8SAlex Bennée DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 109bcf317f8SAlex Bennée DEV_NVECTORS_UNSPECIFIED), 110bcf317f8SAlex Bennée DEFINE_PROP_END_OF_LIST(), 111bcf317f8SAlex Bennée }; 112bcf317f8SAlex Bennée 113bcf317f8SAlex Bennée static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) 114bcf317f8SAlex Bennée { 115bcf317f8SAlex Bennée VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); 116bcf317f8SAlex Bennée DeviceState *vdev = DEVICE(&dev->vdev); 117bcf317f8SAlex Bennée 118bcf317f8SAlex Bennée ... 119bcf317f8SAlex Bennée 120bcf317f8SAlex Bennée qdev_realize(vdev, BUS(&vpci_dev->bus), errp); 121bcf317f8SAlex Bennée } 122bcf317f8SAlex Bennée 123bcf317f8SAlex Bennée static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) 124bcf317f8SAlex Bennée { 125bcf317f8SAlex Bennée DeviceClass *dc = DEVICE_CLASS(klass); 126bcf317f8SAlex Bennée VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); 127bcf317f8SAlex Bennée PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); 128bcf317f8SAlex Bennée 129bcf317f8SAlex Bennée set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 130bcf317f8SAlex Bennée device_class_set_props(dc, virtio_blk_pci_properties); 131bcf317f8SAlex Bennée k->realize = virtio_blk_pci_realize; 132bcf317f8SAlex Bennée pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; 133bcf317f8SAlex Bennée pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; 134bcf317f8SAlex Bennée pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; 135bcf317f8SAlex Bennée pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; 136bcf317f8SAlex Bennée } 137bcf317f8SAlex Bennée 138bcf317f8SAlex Bennée static void virtio_blk_pci_instance_init(Object *obj) 139bcf317f8SAlex Bennée { 140bcf317f8SAlex Bennée VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); 141bcf317f8SAlex Bennée 142bcf317f8SAlex Bennée virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 143bcf317f8SAlex Bennée TYPE_VIRTIO_BLK); 144bcf317f8SAlex Bennée object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), 145bcf317f8SAlex Bennée "bootindex"); 146bcf317f8SAlex Bennée } 147bcf317f8SAlex Bennée 148bcf317f8SAlex Bennée static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { 149bcf317f8SAlex Bennée .base_name = TYPE_VIRTIO_BLK_PCI, 150bcf317f8SAlex Bennée .generic_name = "virtio-blk-pci", 151bcf317f8SAlex Bennée .transitional_name = "virtio-blk-pci-transitional", 152bcf317f8SAlex Bennée .non_transitional_name = "virtio-blk-pci-non-transitional", 153bcf317f8SAlex Bennée .instance_size = sizeof(VirtIOBlkPCI), 154bcf317f8SAlex Bennée .instance_init = virtio_blk_pci_instance_init, 155bcf317f8SAlex Bennée .class_init = virtio_blk_pci_class_init, 156bcf317f8SAlex Bennée }; 157bcf317f8SAlex Bennée 158bcf317f8SAlex BennéeHere you can see the instance_init has to manually instantiate the 159bcf317f8SAlex Bennéeunderlying ``TYPE_VIRTIO_BLOCK`` object and link an alias for one of 160bcf317f8SAlex Bennéeit's properties to the PCI device. 161bcf317f8SAlex Bennée 162bcf317f8SAlex Bennée 163bcf317f8SAlex BennéeBack End Implementations 164bcf317f8SAlex Bennée------------------------ 165bcf317f8SAlex Bennée 166bcf317f8SAlex BennéeThere are a number of places where the implementation of the backend 167bcf317f8SAlex Bennéecan be done: 168bcf317f8SAlex Bennée 169bcf317f8SAlex Bennée* in QEMU itself 170bcf317f8SAlex Bennée* in the host kernel (a.k.a vhost) 171bcf317f8SAlex Bennée* in a separate process (a.k.a. vhost-user) 172bcf317f8SAlex Bennée 173bcf317f8SAlex Bennéevhost_ops vs TYPE_VHOST_USER_BACKEND 174bcf317f8SAlex Bennée^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 175bcf317f8SAlex Bennée 176bcf317f8SAlex BennéeThere are two choices to how to implement vhost code. Most of the code 177bcf317f8SAlex Bennéewhich has to work with either vhost or vhost-user uses 178bcf317f8SAlex Bennée``vhost_dev_init()`` to instantiate the appropriate backend. This 179bcf317f8SAlex Bennéemeans including a ``struct vhost_dev`` in the main object structure. 180bcf317f8SAlex Bennée 181bcf317f8SAlex BennéeFor vhost-user devices you also need to add code to track the 182bcf317f8SAlex Bennéeinitialisation of the ``chardev`` device used for the control socket 183bcf317f8SAlex Bennéebetween QEMU and the external vhost-user process. 184bcf317f8SAlex Bennée 185bcf317f8SAlex BennéeIf you only need to implement a vhost-user backed the other option is 186bcf317f8SAlex Bennéea use a QOM-ified version of vhost-user. 187bcf317f8SAlex Bennée 188bcf317f8SAlex Bennée.. code:: c 189bcf317f8SAlex Bennée 190bcf317f8SAlex Bennée static void 191bcf317f8SAlex Bennée vhost_user_gpu_instance_init(Object *obj) 192bcf317f8SAlex Bennée { 193bcf317f8SAlex Bennée VhostUserGPU *g = VHOST_USER_GPU(obj); 194bcf317f8SAlex Bennée 195bcf317f8SAlex Bennée g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND)); 196bcf317f8SAlex Bennée object_property_add_alias(obj, "chardev", 197bcf317f8SAlex Bennée OBJECT(g->vhost), "chardev"); 198bcf317f8SAlex Bennée } 199bcf317f8SAlex Bennée 200bcf317f8SAlex Bennée static const TypeInfo vhost_user_gpu_info = { 201bcf317f8SAlex Bennée .name = TYPE_VHOST_USER_GPU, 202bcf317f8SAlex Bennée .parent = TYPE_VIRTIO_GPU_BASE, 203bcf317f8SAlex Bennée .instance_size = sizeof(VhostUserGPU), 204bcf317f8SAlex Bennée .instance_init = vhost_user_gpu_instance_init, 205bcf317f8SAlex Bennée .instance_finalize = vhost_user_gpu_instance_finalize, 206bcf317f8SAlex Bennée .class_init = vhost_user_gpu_class_init, 207bcf317f8SAlex Bennée }; 208bcf317f8SAlex Bennée 209bcf317f8SAlex BennéeUsing it this way entails adding a ``struct VhostUserBackend`` to your 210bcf317f8SAlex Bennéecore object structure and manually instantiating the backend. This 211bcf317f8SAlex Bennéesub-structure tracks both the ``vhost_dev`` and ``CharDev`` types 212bcf317f8SAlex Bennéeneeded for the connection. Instead of calling ``vhost_dev_init`` you 213bcf317f8SAlex Bennéewould call ``vhost_user_backend_dev_init`` which does what is needed 214bcf317f8SAlex Bennéeon your behalf. 215