qemu-kvm设备初始化

来源:互联网 发布:安装淘宝还要旺信吗 编辑:程序博客网 时间:2024/05/22 07:58
1. vm_config_groups是一个数组,数组每一个成员是一个链表表头,这些链表包含了qemu-kvm的各种启动参数,device链表是链表数组中的一个链表。
2. QemuOptsList类型的device链表中的成员是QemuOpts类型,一个QemuOpts变量代表一个qemu-kvm中的“-device参数”,device链表中QemuOpts的数量就等于“-device”的数量,初始化时,会循环为每一个QemuOpts变量调用device_init_func函数。
3. 因为“-device”参数还有子参数(如virtio-scsi-pci.hotplug=on/off),所以QemuOptsList也引导一个链表,链表节点是QemuOpt类型,链表的每一个节点就对应“-device”的一个子参数。
4.device链表中每一个QemuOptsList节点对应一个“-device”参数,QemuOptsList链表中的每一个节点对应该“-device”的一个子参数。这些信息都是从qemu-kvm的启动参数初始化而来的。该函数完成工作就是 在vm_config_groups中找到device链表成员并返回。


main()
{
    ...
    /* init generic devices */
    if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
        exit(1);
    ...
}


/*
该函数完成工作就是 在vm_config_groups中找到device链表成员并返回。
*/
QemuOptsList *qemu_find_opts(const char *group)
{
    QemuOptsList *ret;
    Error *local_err = NULL;


    ret = find_list(vm_config_groups, group, &local_err);
    if (error_is_set(&local_err)) {
        error_report("%s\n", error_get_pretty(local_err));
        error_free(local_err);
    }


    return ret;
}
/*
“-device”参数初始化函数,qemu-kvm启动参数中定义的每一个“-device”都在device链表中,依次为这些“-device”调用device_init_func函数初始化它们。
 */
static int device_init_func(QemuOpts *opts, void *opaque)
{
    DeviceState *dev;


    dev = qdev_device_add(opts);
    if (!dev)
        return -1;
    return 0;
}


/*
每一个“-device”对应一个QemuOpts结构体变量,“-device”实际上是指定使用某一驱动,因此这个结构体变量用来保存驱动的名字以及该驱动的各种启动参数(即“-device”后面的子参数), qdev_device_add函数初始化该驱动。 
 */
DeviceState *qdev_device_add(QemuOpts *opts)
{
    ObjectClass *obj;
    DeviceClass *k;
    const char *driver, *path, *id;
    DeviceState *qdev;
    BusState *bus;
    /* 找到“-device”中指定的驱动的名字,opts中成员"driver"的值就是设备对应驱动的名字 */
    driver = qemu_opt_get(opts, "driver");
    if (!driver) {
        qerror_report(QERR_MISSING_PARAMETER, "driver");
        return NULL;
    }


    /* find driver */
    obj = object_class_by_name(driver);
    if (!obj) {
        const char *typename = find_typename_by_alias(driver);


        if (typename) {
            driver = typename;
            obj = object_class_by_name(driver);
        }
    }


    if (!obj) {
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
        return NULL;
    }


    k = DEVICE_CLASS(obj);


    /* find bus */
    path = qemu_opt_get(opts, "bus");
    if (path != NULL) {
        bus = qbus_find(path);
        if (!bus) {
            return NULL;
        }
        if (strcmp(object_get_typename(OBJECT(bus)), k->bus_type) != 0) {
            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
                          driver, object_get_typename(OBJECT(bus)));
            return NULL;
        }
    } else {
        bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
        if (!bus) {
            qerror_report(QERR_NO_BUS_FOR_DEVICE,
                          driver, k->bus_type);
            return NULL;
        }
    }
    if (qdev_hotplug && !bus->allow_hotplug) {
        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
        return NULL;
    }


    if (!bus) {
        bus = sysbus_get_default();
    }


    /* create device, set properties */
    qdev = DEVICE(object_new(driver));
    qdev_set_parent_bus(qdev, bus);


    id = qemu_opts_id(opts);
    if (id) {
        qdev->id = id;
    }
    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
        qdev_free(qdev);
        return NULL;
    }
    if (qdev->id) {
        object_property_add_child(qdev_get_peripheral(), qdev->id,
                                  OBJECT(qdev), 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(qdev), NULL);
        g_free(name);
    }        
    if (qdev_init(qdev) < 0) {
        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
        return NULL;
    }
    qdev->opts = opts;
    return qdev;
}
原创粉丝点击