Qemu: How to create the bridge device, bus, and pci device.

How to create bridge device, bus, and pci device.

As we all know, the "device and bus" architecture in qemu is that, a pci
device should attach to a pci bus, and a pci bus should add to a bridge
device, and the bridge device should link to main-system-bus.

To realize this, four important functions are introduced:
1. qdev_bridge_create() to create a bridge device named "s390-bridge-dev".
2. qbus_create() to create a pci bus named "s390-pci-bus" and attach
   "s390-pci-bus" to "s390-bridge-dev".
3. s390_pci_bus_init() is used by coder to assign a bridge device and a pci bus,
   it will call qdev_bridge_create() and qbus_create().
4. qdev_device_add() to create a pci device and attach it to designated bus.

The following codes are telling how to realize this in detail.

I. Define TypeInfo in test_pci.c file.

static void s390_pci_dev_class_init(ObjectClass *kclass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(kclass);

    dc->bus_type = TYPE_S390_PCI_BUS;
}

static const TypeInfo s390_bridge_dev_info = {
    .name       = TYPE_S390_BRIDGE_DEV,
    .parent     = TYPE_SYS_BUS_DEVICE,
    .class_init = s390_bridge_dev_class_init,
}

static const TypeInfo s390_pci_bus_info = {
    .name       = TYPE_S390_PCI_BUS,
    .parent     = TYPE_BUS,
}

static const TypeInfo s390_pci_dev_info = {
    .name       = TYPE_S390_PCI_DEV,
    .parent     = TYPE_DEVICE,
    .class_init = s390_pci_dev_class_init,
};

II. Define macro in test_pci.h file.

#define TYPE_S390_BRIDGE_DEV  "s390-bridge-dev"
#define TYPE_SYS_BUS_DEVICE   "sys-bus-device"

typedef struct S390PCIBus {
    BusState parent_obj;
} S390PCIBus

#define TYPE_S390_PCI_BUS     "s390-pci-bus"
#define S390_PCI_BUS(obj) \
     OBJECT_CHECK(S390PCIBus, (obj)TYPE_S390_PCI_BUS)

#define TYPE_BUS              "bus"

#define TYPE_S390_PCI_DEV     "s390-pci-dev"
#define TYPE_DEVICE           "device"

III. How to create s390-bridge-dev and s390-pci-bus.

/**
 * object_class_by_name to initialize ObjectClass.
 *
 * Will find corresponding TypeImpl by given typename, like "s390-bridge-dev".
 * Then call type_initialize() to initialize device's ObjectClass.
 *
 * Actually, in our code, all devices' ObjectClass initialization is already
 * realized by object_class_foreach_tramp() in find_default_machine().
 *
 * Returns: one device's ObjectClass according to its TypeInfo's name.
 */
static ObjectClass *object_class_by_name(const char *typename)
{
    TypeImpl *type = type_get_by_name(typename);

    if (!type) {
        return NULL;
    }

    type_initialize(type);

    return type->class;
}

/**
 * To create a bridge device, named "s390-bridge-dev".
 * After initialization, the new created "s390-bridge-dev" device
 * should attach to main_system_bus as its parent bus.
 */
DeviceState *qdev_bridge_create(BusState *bus, const char *typename)
{
    DeviceState *dev;

    /* Initialize ObjectClass. */
    if (object_class_by_name(typename) == NULL) {
        return NULL;
    }
    /* Initialize Object to create a device. */
    dev = DEVICE(object_new(typename));
    if (!dev) {
        return NULL;
    }

    /* to get main_system_bus */
    if (!bus) {
        bus = sysbus_get_default();
    }

    /* add s390-bridge-dev's link to main_system_bus */
    qdev_set_parent_bus(dev, bus);

    /* add s390-bridge-dev to main_system_bus as a child */
    object_property_add_child(qdev_get_machine, typename,
                              OBJECT(dev), NULL);

    object_unref(OBJECT(dev));
    return dev;
}

/**
 * To create a pci bus named "s390-pci-bus".
 * After initialization, the new created "s390-pci-bus" should add
 * to its upper bridge device named "s390-bridge-dev".
 */

BusState *qbus_create(const char *typename,
                      DeviceState *parent, const char *name)
{
    BusState *bus;

    /* Initialize s390-pci-bus */
    bus = BUS(object_new(typename));
    /* Assign name to s390-pci-bus, and add s390-pci-bus to s390-bridge-dev */
    qbus_realize(bus, parent, name);

    return bus;
}

/**
 * To create a bridge device named "s390-bridge-dev", create a pci bus named
 * "s390-pci-bus", and attach "s390-pci-bus" to "s390-bridge-dev".
 *
 * There are two methods to create a device:
 *     -- define in command line, like "-device, s390-bridge-dev"
 *     -- assign name directly in file like ccw_init called by main()
 * Here we adopt the second method.
 */
S390PCIBus *s390_pci_bus_init(void)
{
    S390PCIBus *pbus;
    BusState *bus;
    DeviceState *dev;

    /* Create s390-bridge-dev */
    dev = qdev_bridge_create(NULL, TYPE_S390_BRIDGE_DEV);

    /* Create s390-pci-bus which should attach to s390-bridge-dev */
    bus = qbus_create(TYPE_S390_PCI_BUS, dev, NULL);
    pbus = S390_PCI_BUS(bus);

    return pbus;
}

IV. How to create s390-pci-dev.

/**
 * To create a pci device named "s390-pci-dev", then find its upper bus and
 * attach "s390-pci-dev" to the bus.
 *
 * There are two methods to designate a pci device's upper bus.
 *     -- define bus in command line, like "-device s390-pci-dev, bus=pci.1"
 *     -- designate its bus_type when initializing ObjectClass
 *
 * Here we adopt the second method, this means code will find s390-pci-dev's
 * bus by its bus_type "s390-pci-bus".
 */
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
{
    DeviceClass *dc;
    const char *driver, *path;
    DeviceState *dev;
    BusState *bus = NULL;
    Error *err = NULL;

    /* the value of driver will be returned as "s390-pci-dev" */
    driver = qemu_opt_get(opts, "driver");
    if (!driver) {
        error_setg(errp, QERR_MISSING_PARAMETER, "driver");
        return NULL;
    }

    /* Initialize ObjectClass by typename */
    dc = qdev_get_device_class(&driver, errp);
    if (!dc) {
        return NULL;
    }

    /* will return NULL as we did not define "bus=..." in command line */
    path = qemu_opt_get(opts, "bus");
    if (path != NULL) {
        bus = qbus_find(path, errp);
        if (!bus) {
            return NULL;
        }
        if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
            error_setg(errp, "Device '%s' can't go on %s bus",
                       driver, object_get_typename(OBJECT(bus)));
            return NULL;
        }
    } else if (dc->bus_type != NULL) {
        /* this is a recursion function that will return the matched bus only
         * if the first parameter's busname equals to dc->bus_type.
         */
        bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type);
        if (!bus || qbus_is_full(bus)) {
            error_setg(errp, "No '%s' bus found for device '%s'",
                       dc->bus_type, driver);
            return NULL;
      }
    }

    /* Initialize Object to create device */
    dev = DEVICE(object_new(driver));

    /* add s390-pci-dev's link to s390-pci-bus */
    if (bus) {
        qdev_set_parent_bus(dev, bus);
    }

    /* add s390-pci-dev to s390-pci-bus as a child */
    if (dev->id) {
        object_property_add_child(qdev_get_peripheral(), dev->id,
                                  OBJECT(dev), NULL);
    } else {
        static int anon_count;
        gchar *name = g_strdup_printf("device[%d]", anon_count++);
        object_property_add_child(qdev_get_peripheral_anon(), name,
                                  OBJECT(dev), NULL);
        g_free(name);
    }

   return dev;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值