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