Onofog
Onofog

Reputation: 453

How do I make my device available to QEMU

I've written what I believe is a minimal custom device to test my understanding of the QOM and QEMU in general. Below is the relevant code with comments omitted. Unfortunately, when I start the guest and pass my device name as a command line argument, it fails to find my device and exits. I am issuing:

qemu-system-x86_64 -device hello-world-device ...

How can I make QEMU aware of my device? What steps do I need to take to properly build my device?

I can see an objects list in the folder I placed my source into (qemu/hw/misc), but I can't find where the other targets are defined to add in a target for my new device. The code:

#include "qom/object.h"
#include "hw/qdev-core.h"
#define TYPE_HELLO "hello-world-device"
#define HELLO(obj) OBJECT_CHECK(HelloState, (obj), TYPE_HELLO)

typedef struct{
    DeviceClass parent_obj;
    uint8_t member0, member1;
} HelloState;

static const TypeInfo hello_info = {
    .name = TYPE_HELLO,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(HelloState),
    .class_init = class_init,
};

static void class_init(ObjectClass *klass, void *data){
    DeviceClass *dc = DEVICE_CLASS(klass);
}

static void hello_register_types(void){
    type_register_static(&hello_info);
}

type_init(hello_register_types)

Upvotes: 5

Views: 1770

Answers (2)

Purgoufr
Purgoufr

Reputation: 972

To be able to integrate your new device model into the QEMU build system, you should modify Meson and Kconfig, follow these steps:

  1. Add your new device to the build system with Meson:

    • Navigate to the directory where your device source file is located (e.g., hw/misc/foo.c).
  2. Edit the meson.build file in that directory to include your new source file.

    # In hw/misc/meson.build
    
    # Add your new device source file
    softmmu_ss.add(when: 'CONFIG_FOO', if_true: files('foo.c'))
    
  3. Add your device to the Kconfig system:

    • Navigate to the directory where the Kconfig file for your device type is located (e.g., hw/misc/Kconfig).

    • Edit the Kconfig file to add an entry for your new device.

# In hw/misc/Kconfig

config FOO
    bool
  1. Select the new device module on any another machine
# In hw/XXX/Kconfig

config <machine>
    select FOO

To better understand the context, let's assume we want to add our new device module to the Raspberry Pi as an example. In this case, we would need to modify the Raspberry Pi's Kconfig configuration as follows:

# In hw/arm/Kconfig

config RASPI
    bool
    select FRAMEBUFFER
    select PL011
    select SDHCI
    select USB_DWC2
    **select FOO** -> New device added!

And also we would need to modify Raspberry Pi's meson.build configuration as follows:

```meson
# In hw/arm/meson.build

arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c', 'bcm2836.c', 'raspi.c', **'foo.c'**)) -> foo.c added!
```

Upvotes: 1

Onofog
Onofog

Reputation: 453

The documentation is unclear or missing on how this ought to be done, but I did find a solution that worked in the interim.

In the directory where the source file is stored (here, qemu/hw/misc/), there is a file called Makefile.objs with a list of object file targets to create. Adding the following line will induce the main Makefile (in the QEMU root directory) to create a target whenever the configuration flag CONFIG_HELLO is defined:

common-obj-$(CONFIG_HELLO) += hello-world-device.o

To define this custom flag, an entry can be added to the target architecture of choice. Here, I add it to my configuration for x86_64 in qemu/default-configs/x86_64-softmmu.mak:

CONFIG_HELLO=y

After making the above changes, running make creates a rule to build the custom device, and runs it at the appropriate time when building the architecture. This revealed an includes bug in the existing code, repeated here with the corrections for convenience:

#include "qemu/osdeps.h"
#include "hw/hw.h"
#define TYPE_HELLO "hello-world-device"
#define HELLO(obj) OBJECT_CHECK(HelloState, (obj), TYPE_HELLO)

typedef struct{
    DeviceClass parent_obj;
    uint8_t member0, member1;
} HelloState;

static const TypeInfo hello_info = {
    .name = TYPE_HELLO,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(HelloState),
    .class_init = class_init,
};

static void class_init(ObjectClass *klass, void *data){
    DeviceClass *dc = DEVICE_CLASS(klass);
}

static void hello_register_types(void){
    type_register_static(&hello_info);
}

type_init(hello_register_types)

Upvotes: 2

Related Questions