xref: /qemu/docs/devel/virtio-backends.rst (revision fd363a14f68a7bcbede024fb5155371c19b8f5d2)
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