Explanation on how QEMU speeds up Embedded Software Development.

 

QEMU emulated devices provide a platform by which software development can be completely decoupled from hardware delivery. This enables the acceleration of embedded software development whilst also potentially improving the quality of the embedded product.

How QEMU Emulated Devices can Benefit Embedded Software Development

By introducing QEMU emulated devices to the software development plan, the dependency of the software schedule on hardware delivery is greatly reduced. This means that the software development process can be initiated at a much earlier point in the product development cycle. The following figure illustrates how QEMU emulated devices can impact a typical embedded product development schedule.

QEMU emulated devices can provide benefits to both the development and validation of the software package as well as validation of the hardware:

Software Development

Including emulated devices in the software development plan means that software schedules are not impacted by delays in hardware delivery. Therefore, the software development team is not under pressure to deliver a software package in a reduced time frame. When software schedules are squeezed it normally results in the reduction of feature sets in order to provide a hardened product. This risk is reduced greatly through the introduction of virtualized emulated devices. Finally, by starting the software development process earlier in the product development cycle, it provides a buffer before final software delivery if any delays do occur.

Software Debugging

QEMU emulated devices can also facilitate a more complete approach to driver debugging. The emulated device can easily be updated to provide valuable debug information to the developer which can lead issues being resolved in a more efficient manner.

Software Validation

The inclusion of emulated devices also results in the software validation schedule not being impacted by any delay in the delivery of physical hardware. Reducing the allocated time to validate a software package may result in defects being missed and therefore being included in the final software package. This risk is reduced by negating the dependency on hardware delivery. Another advantage of using QEMU emulated devices for software validation is that it becomes much easier to simulate error conditions which might otherwise be difficult to do with real hardware. Therefore, the emulated devices can provide a method to increase test coverage and facilitate a broader scope of test automation.

Hardware Validation

If QEMU emulated devices are included in the software development plan, these can also be leveraged by the hardware validation team. The time allocated for the hardware validation of devices using hardware emulation platforms is limited by the time between the delivery of the first hardware emulation package and the manufacturing of the silicon. Therefore, reducing the hardware validation teams dependency on hardware delivery potentially decreases the risk of hardware defects going undetected as the validation schedule is not impacted. The late detection of hardware defects can be very costly and so it is hugely important to identify these as early as possible.

Hardware Interface Design

The development of the QEMU emulated device itself can provide extremely useful data which can feed back into the hardware interface design. As the hardware implementation is not complete, the development of QEMU emulated devices can help to identify issues in the hardware design before the hardware is finalised. Essentially, hardware defects relating to interface design can be identified before they become defects.

What are QEMU Emulated Devices?

QEMU is a generic and open source machine emulator and virtualizer. In short, QEMU provides a platform to test Operating Systems and applications using hardware that may not exist on the host system. As such, QEMU provides a framework where such devices, otherwise known as emulated devices, can be developed and integrated within the QEMU build system.

A QEMU emulated device is presented to the virtual machine, or 'guest', as a real physical device. The Operating System is never aware that the device is, in fact, virtualized. This means that a driver developed to interface with a physical device can be used, without modification, to interface with an emulated version of the same device.

It is rare that the complexity of an emulated device will match that of the physical device. An emulated device will essentially replicate the physical devices behaviour from the perspective of the device driver. This means that much of the internal complexity of a physical device is not required in an emulated version.

QEMU emulated devices can also be expanded to use a backend in order to provide a more expandable solution while exposing the device to real-world scenarios. For example, an emulated network device can be attached to a network TAP device backend. By bridging this TAP device to a physical interface on the host, the emulated device becomes exposed to real physical network conditions. This allows a device driver to be developed and validated, using an emulated device, in an identical environment to that of a physical device.

QEMU Emulated Device Development.

Enabling a basic QEMU emulated device is not a difficult process. We will take a very basic 2-pin GPIO controller as an example with the following specification:

Memory Mapped IO Registers

Memory Offset Default Value Register Name Description
0x00 0x0 GPIO_DIR GPIO set direction
0x04 0x0 GPIO_VALUE GPIO input/output value

GPIO_DIR

Bits Access Type Default Value Description
31:2 RO 0x0 Reserved
1:0 RW 0x0

Pin Direction

Each bit represents a GPIO pin.

Values written to this register control the directions of the GPIO pins.

0 - Input

1 - Output

GPIO_VALUE

Bits Access Type Default Value Description
31:2 RO 0x0 Reserved
1:0 RW 0x0

Pin Value

Each bit represents a GPIO pin.

Values written to this register will set the GPIO pin value but only if the pin is set as output. Otherwise the written value will be ignored.

Values read from this register represent the current value at which a pin is set. Values can be read from a pin configured for either input or output.

The first step is to register the device within QEMU. This involves populating the TypeInfo structure and calling the required registration function.

static const TypeInfo emutex_gpio_info = {
    .name = TYPE_EMUTEX_GPIO,
    .parent = TYPE_PCI_DEVICE,
    .instance_size = sizeof(EmutexGPIOState),
    .class_init = emutex_gpio_class_init,
    .instance_init = emutex_gpio_instance_init,
};

static void emutex_gpio_register_types(void)
{
    type_register_static(&emutex_gpio_info);
}

type_init(emutex_gpio_register_types)

The class_init and instance_init functions will setup internal device state and structures for when the device is selected on the QEMU command line. We will not go into detail on these here, instead we will focus on the device read and write functions. The basis of any device is that certain actions are performed depending on when hardware registers are written to or read from. This behaviour is emulated within the emulated device by first registering read and write functions:

static const MemoryRegionOps register_ops = {
    .read = gpio_read,
    .write = gpio_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .impl = {
        .min_access_size = 1,
        .max_access_size = 8,
    },
};

These read and write functions are registered within QEMU when creating the device BAR memory region. When the BAR is written to or read from, QEMU traps the instructions calling the corresponding read/write functions, in this case gpio_read or gpio_write. The GPIO controller in this example contains 2 GPIO pins. The register layout is as follows:

struct gpio_reg{
    uint32_t direction;
    uint32_t value;
}

Although interrupts can easily be added, we will not consider them here. Both the direction and value registers are a bitmask for the GPIO pins meaning that only bits 0 and 1 are used. First we will look at the gpio_read function:

uint64_t gpio_read (gpio_reg *s, uint16_t addr, unsigned size)
{
    switch (addr)
    {
        case GPIO_DIR:
            result = s->direction;
            break;
        case GPIO_VALUE:
            result = s->value;
            break;
        default:
            result = INVALID;
    }
    return result;
}
 

As seen, this function is very simple for such a basic GPIO controller. When reading an address, a value is returned from an internal structure. Note that the complexity of such a function depends on the hardware design. For example, perhaps in the case of a network device, reading from a register returns packet data. A function can be created to perform this which is simply called when the register address is read.

Finally, we will look at the gpio_write function:

void gpio_write(gpio_reg *s, uint16_t addr,
                uint64_t value, unsigned size)
{
    uint32_t input_value;

    switch (addr)
    {
        case GPIO_DIR:
            s->direction = value;
            break;
        case GPIO_VALUE:
            input_value = (s->value | ~s->direction)
            s->value = (value & s->direction);
            s->value |= input_value;
            break;
        default:
            result = INVALID;
    }
} 

Again, this function is quite basic. A value is written to an address in the BAR and the internal structure is updated with the value. Note that the value register bit is only changed if the direction is set to output. If we wanted, we could expand this further by adding a test register. This could, for example, create internal loopbacks which would enable a validation team to leverage the device. The register may not exist in the hardware implementation but test registers can be very useful in the emulated device.

QEMU Emulated Devices in Action

Here at Emutex, we were recently presented with an opportunity with which QEMU emulated devices could be added to our software development schedule. A client required a network boot device driver for a Network card which was still in development. As the client was required to deliver the product soon after the device completion, they came to us in order to identify how this could be achieved. As we had recent experience with QEMU emulated devices, we identified that developing such a device would provide a solution by enabling software development at an earlier time.

The QEMU emulated device was developed using a device hardware specification provided to us by the client. The emulated device was developed side by side with the network boot device driver through continuous integration. As is the case with many product development cycles, the hardware delivery of the product was in fact delayed. However, as we had already developed an emulated device we were able to fully develop the driver before any hardware was received by the client. The software schedule was not impacted by the issues encountered in hardware.

Before any hardware was received we were also able to provide valuable feedback to the hardware team based on the device specification as we discovered implementation issues when creating the emulated device. This is something that could not have been identified without the emulated device. Once hardware was received we had a fully operational interface to the network card through the previously developed driver. This allowed us to identify firmware issues immediately with this feedback being provided back to the hardware team in a matter of days.

Having access to the driver earlier meant that the hardware and software validation teams had a working driver with which to validate. It also meant that the validation teams were able to collaborate on creating a common validation framework in which tests could be reused across both hardware and software validation. In fact, the validation framework and test cases were being developed using the emulated device before any hardware had arrived. This is something that could not have occurred if these components were dependent on hardware delivery.

 

QEMU Final Design

 

How Emutex can help you

At Emutex, we are always looking to learn and to improve our software processes with a view to providing the highest quality software deliverables within an acceptable time frame to our clients. We recommend including QEMU emulated devices within your embedded product development cycles in order to accelerate software development and delivery. This recommendation is based both on research and very positive customer experience.

We would be happy to assist customers in integrating QEMU emulated devices seamlessly into their embedded product development schedules. If you have any questions, please contact our team at This email address is being protected from spambots. You need JavaScript enabled to view it..

 

Go To Top