Designing a vdev

Before you begin writing a vdev, you should decide what you need the vdev to do.

The questions below are to offer general guidance. The rest of this guide and the source code examples provide a better understanding of how these questions are answered in practice.

What, exactly, do I need my vdev to do?

Does the vdev need to initiate actions without prompting from a guest or hardware (e.g., a watchdog), or does it just need to assemble itself and wait for the guest or the hardware to ask it to do something (e.g., handle hardware device I/O)?

What kind of vdev do I need?

Will my vdev emulate a device for which a physical hardware device already exists, or will it implement functionality that is only possible (and perhaps only relevant) in a hypervisor system?

The answer to this question determines the answers to many of the other questions.

If my vdev will be a para-virtualized device, should I use a standard such as VIRTIO?

QNX hypervisors include a number of para-virtualized devices that implement VIRTIO, including virtio-entropy described in this guide.

What resources, if any, will my vdev need in the hypervisor host?

Will my vdev need a driver or utility in the hypervisor host to access a resource such as a hardware device?

What device interface will my vdev present to the guest?

If the vdev will be an emulation vdev, then it is likely that the guest already has a driver to interface with the hardware device. In this case, you will probably want to write your vdev so that your guest can use its existing driver.

If the vdev will be a para-virtualized device, then the question is: What resources will I need to write and add to my guest so it can use the vdev? That is, what drivers do I need to write for my guest?

What type of device will the vdev present to the guest (e.g., MMIO, PCI)?

If the vdev is an emulation vdev, you should consider designing it so that to the guest it is indistinguishable from the hardware device it is emulating. This way, the guest can use its existing drivers to interface with your vdev.

Will the guest need more than one instance of the vdev?

If the guest will have multiple uses for this type of vdev, the vdev implementation must support multiple instances. For example, static data in the vdev shared object must be limited to information that applies to all vdevs of that type at the same time. Any data that must be maintained on a per-instance basis must be stored in a vdev_t structure for which the total size must be stored in the associated vdev_factory structure. For more information, refer to the Virtual Device Developer's API Reference.

What memory mappings does the vdev require?

For example, are there specific physical addresses where the guest will expect to find the vdev?

What registers will the vdev present to the guest?

Remember, you are designing a device that to the guest looks like hardware. The guest will, therefore, expect to interact with your vdev like it interacts with hardware: reading and writing registers, for example.

What interrupts will the vdev use?

If the vdev is an emulation vdev, what sorts of interrupts does the guest expect from it: interrupts on an interrupt line, MSIs, etc?

How will my vdev be discovered by the guest?

For instance, which of the following will a guest use to discover my vdev?

  • ACPI
  • FDT
  • PCI
  • VIRTIO

Or, will I explicitly specify my vdev's location in memory and interrupts from within the guest?

What language will I use to implement the vdev?

It is recommended to use C to implement vdevs, but if you want to use other languages, (e.g., C++, Rust), then you must consider how any language-specific mechanisms can affect the vdev behavior during qvm shutdown or following an unexpected runtime error. For example, you must consider the following features:
  • C++ destructors — a vdev must not assume that the control message handler for VDEV_CTRL_TERMINATE and C++ static object destructors will be called in any specific order. They must not conflict with each other in any way, including by order dependence.
  • stack unwinding mechanisms, such as C++ exceptions or Rust panics — these mechanisms cannot be allowed to propagate from a vdev into the qvm runtime.
Page updated: