[<<][arm][>>][..]
Sat Dec 7 09:50:54 EST 2013

Adding a register-mapped QEMU device

1. Build system

Create file hw/zwizwa.c

Add a reference to Makefile.target:
obj-arm-y += zwizwa.o


2. In .c file, register objects:

#include <stdio.h>
#include "module.h"
static void zwizwa_register_types(void) {
    printf("zwizwa_register_types\n");
}
type_init(zwizwa_register_types)


3. Call type_register_static on TypInfo struct

#include "module.h"
#include "sysbus.h"
#include "qemu/object.h"
typedef struct {
} zwizwa_debug_state;
static void zwizwa_debug_class_init(ObjectClass *klass, void *data) {
}
static TypeInfo zwizwa_debug_info = {
    .name          = "zwizwa-debug",
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(zwizwa_debug_state),
    .class_init    = zwizwa_debug_class_init,
};
static void zwizwa_register_types(void) {
    type_register_static(&zwizwa_debug_info);
}
type_init(zwizwa_register_types)


4. Implement ObjectClass init method

This needs a little explanation of the class system.  What I can
gather, the hierarchy is:

object -> device -> sys-bus-device

For this type, there are two methods to register:

static int zwizwa_debug_init(SysBusDevice *dev){
    return 0;
}
static void zwizwa_debug_reset(DeviceState *d){
}
static void zwizwa_debug_class_init(ObjectClass *klass, void *data) {
    DeviceClass *dc = DEVICE_CLASS(klass);
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
    sdc->init = zwizwa_debug_init;
    dc->reset = zwizwa_debug_reset;
}

Here DEVICE_CLASS() and SYS_BUS_DEVICE_CLASS() are dynamic casts with
type checking:

#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
#define TYPE_DEVICE "device"
#define OBJECT_CLASS(class) ((ObjectClass *)(class))
#define OBJECT_CLASS_CHECK(class, obj, name) \
    ((class *)object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name)))

with object_ function implemented in object.c
That file seems to be quite recent:

 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *




5. Nested objects

From the use of container_of(), it seems that much of QEMU's data
structures are organized as composite flat objects (as opposed to
objects pointing to other objects).  I'm guessing this macro
originates in the Linux source[1].

Using a flat representation makes ownership relationships very clear
and makes it possible to traverse the structure hierarchy in two
directions without extra bookkeeping (e.g. reverse pointers).

   - down: C structure member dereference

   - up:   container_of(member_ptr, parent_type, member_name)




6. Access to objects in init / reset.

static int zwizwa_debug_init(SysBusDevice *dev){
    zwizwa_debug_state *s = FROM_SYSBUS(typeof(*s), dev);
    // ...
    return 0;
}
static void zwizwa_debug_reset(DeviceState *d){
    zwizwa_debug_state *s = container_of(d, typeof(*s), busdev.qdev);
    // ...
}


From the CC32RS512 example, the FROM_SYSBUS macro is used to convert a
SysBusDevice pointer to the full object.  Note that this is also a
container_of() style macro.

#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
#define DO_UPCAST(type, field, dev) container_of(dev, type, field)

In the FROM_SYSBUS definition, the field name "busdev" is fixed, so we
need to make sure we have that in our state structure:

typedef struct zwizwa_debug_state {
    SysBusDevice busdev;
}

Actually, this seems deprecated[2]: use your own macro based on OBJECT_CHECK()

For reset, need to know that this is a device method, so we go up one
more in the hierarchy.



7. Implement init / reset.

Some relevant calls from the CC32RS512 module:

qdev_init_gpio_in()
memory_region_init_io()
sysbus_init_irq()
sysbus_init_mmio()

For this example we only use memory mapped io:

typedef struct {
    SysBusDevice busdev;
    MemoryRegion iomem;
} zwizwa_debug_state;
static uint64_t zwizwa_debug_read(void *opaque, target_phys_addr_t offset, unsigned size) {
    return 0;
}
static void zwizwa_debug_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size) {
    printf("%08x <- %08x\n", (unsigned int)offset, (unsigned int)value);
}
static const MemoryRegionOps zwizwa_debug_ops = {
    .read  = zwizwa_debug_read,
    .write = zwizwa_debug_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};
static int zwizwa_debug_init(SysBusDevice *dev){
    zwizwa_debug_state *s = FROM_SYSBUS(typeof(*s), dev);
    memory_region_init_io(&s->iomem, &zwizwa_debug_ops, s, "zwizwa-debug", 4);
    sysbus_init_mmio(dev, &s->iomem);
    return 0;
}


8. Instantiate

Called from machine init:

sysbus_create_varargs("zwizwa-debug", 0x0FF000, NULL);


[1] http://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-linux-kernel
[2] http://osdir.com/ml/qemu-devel/2013-07/msg05332.html





[Reply][About]
[<<][arm][>>][..]