Table of Contents
QEMU设备模型发展历史参考下图。最终QEMU选择面向对象的QEMU Object Module (QOM)来实现对所有的设备,总线,接口的模拟。
下面先介绍QOM模型的几个重要概念,然后以hw/misc/Pci-testdev.c中的代码实现作为实例介绍整个QOM初始化过程。
QOM模型中几个重要的概念
- 类型Type,QOM中所有的模型都是通过类型Type注册的,具体实现过程就是从类型信息TypeInfo注册为类型实现TypeImpl,并把所有类型实现添加到全局的GHashTable表中,hash表以类型Type的名字作为key键值。类型Type有父子的概念,QOM有对象(TYPE_OBJECT)和接口(TYPE_INTERFACE)两种根父类型。
- 对象类,ObjectClass是对象类的基类,其余所有的对象类都是继承自ObjectClass,每个类型Type在注册过程中都会实例化对象类。ObjectClass的第一个元素指向类型实现TypeImpl。
- 对象,Object是对象的基类,其余所有对象都是继承自Object,每个类型Type在注册过程中都会实例化对象。对象Ojbect的第一个元素是指向对象类的指针。
- 属性Property,属性有两类,一类是对象维护属性GHashTable表。一类是设备对象的属性结构数组
- 接口Interface,对象类维护接口GSList单向队列。
TypeInfo
每个QOM设备模型类型包括设备,总线,接口等都会定义一个类型信息TypeInfo。类型信息TypeInfo是用于注册类型实现TypeImpl的结构模板。TypeInfo通过name定义类型名称,通过parernt指定父类型名称。
struct TypeInfo
{
const char *name; //类型名称
const char *parent; //父类型名称,TYPE_OBJECT和TYPE_INTERFACE是两个根类型的名称
size_t instance_size; //对象实例的大小
void (*instance_init)(Object *obj); //对象实例的init函数,父类型的init已被执行过了,只需要负责本类型的
void (*instance_post_init)(Object *obj); //对象实例的post_init函数,在init执行完后执行
void (*instance_finalize)(Object *obj); //对象实例销毁时执行,释放动态资源
bool abstract; //如为true则是抽象的类型,不能直接实例
size_t class_size; //类对象实例的大小
void (*class_init)(ObjectClass *klass, void *data); //类对象实例的init函数,初始化自己的方法指针,也可覆盖父类的方法指针
void (*class_base_init)(ObjectClass *klass, void *data); //在父类的class_init执行完,自己的class_init执行之前执行,做一些清理工作。
void (*class_finalize)(ObjectClass *klass, void *data); //类对象实例销毁时执行,释放动态资源
void *class_data; //传递给类对象实例各个方法的数据
InterfaceInfo *interfaces; //类型定义的接口信息名称数组
};
struct InterfaceInfo {
const char *type; //每个接口类型,也会注册一个TypeImpl类型,这里只是提供每个接口的名字
};
TypeInfo一般都是静态定义的,例如如下的pci_testdev_info。
static const TypeInfo pci_testdev_info = {
.name = TYPE_PCI_TEST_DEV,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCITestDevState),
.class_init = pci_testdev_class_init,
};
有时也会动态生成
static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
TypeImpl *parent_type)
{
TypeInfo info = { };
...
info.parent = parent_type->name;
info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
info.abstract = true;
...
}
根类型TypeInfo
所有的TypeInfo的parent的根为TYPE_OBJECT和TYPE_INTERFACE
static TypeInfo interface_info = {
.name = TYPE_INTERFACE,
.class_size = sizeof(InterfaceClass),
.abstract = true,
};
static TypeInfo object_info = {
.name = TYPE_OBJECT,
.instance_size = sizeof(Object),
.instance_init = object_instance_init,
.abstract = true,
};
TYPE_OBJECT的一级子类型
name | parent |
TYPE_ACCEL | TYPE_OBJECT |
TYPE_IOTHREAD | TYPE_OBJECT |
TYPE_MEMORY_REGION | TYPE_OBJECT |
TYPE_QJSON | TYPE_OBJECT |
TYPE_MEMORY_BACKEND | TYPE_OBJECT |
TYPE_RNG_BACKEND | TYPE_OBJECT |
TYPE_TPM_BACKEND | TYPE_OBJECT |
TYPE_QCRYPTO_TLS_CREDS | TYPE_OBJECT |
TYPE_IRQ | TYPE_OBJECT |
TYPE_MACHINE | TYPE_OBJECT |
TYPE_DEVICE | TYPE_OBJECT |
TYPE_BUS | TYPE_OBJECT |
TYPE_XILINX_AXI_DMA_DATA_STREAM | TYPE_OBJECT |
TYPE_XILINX_AXI_DMA_CONTROL_STREAM | TYPE_OBJECT |
TYPE_XILINX_AXI_ENET_DATA_STREAM | TYPE_OBJECT |
TYPE_XILINX_AXI_ENET_CONTROL_STREAM | TYPE_OBJECT |
TYPE_NETFILTER | TYPE_OBJECT |
"container" | TYPE_OBJECT |
TYPE_DIRECT_IMPL | TYPE_OBJECT |
TYPE_DUMMY | TYPE_OBJECT |
TYPE_DUMMY_DEV | TYPE_OBJECT |
TYPE_DUMMY_BUS | TYPE_OBJECT |
TYPE_DUMMY_BACKEND | TYPE_OBJECT |
TYPE_NONDEVICE | TYPE_OBJECT |
TYPE_QEMU_CONSOLE | TYPE_OBJECT |
TYPE_INTERFACE的一级子类型
name | parent |
TYPE_ACPI_DEVICE_IF | TYPE_INTERFACE |
TYPE_ARM_LINUX_BOOT_IF | TYPE_INTERFACE |
TYPE_FW_PATH_PROVIDER | TYPE_INTERFACE |
TYPE_HOTPLUG_HANDLER | TYPE_INTERFACE |
TYPE_NMI | TYPE_INTERFACE |
TYPE_STREAM_SLAVE | TYPE_INTERFACE |
TYPE_NVRAM | TYPE_INTERFACE |
TYPE_USER_CREATABLE | TYPE_INTERFACE |
TYPE_TEST_IF | TYPE_INTERFACE |
TypeInfo链路
由根TypeInfo出发,可以组成不同的TypeInfo链路
- TYPE_OBJECT -> TYPE_DEVICE -> TYPE_PCI_DEVICE -> TYPE_PCI_TEST_DEV
- TYPE_OBJECT -> TYPE_DEVICE -> TYPE_SYS_BUS_DEVICE -> TYPE_VIRTIO_PCI
- TYPE_OBJECT -> TYPE_DEVICE -> TYPE_SYS_BUS_DEVICE -> TYPE_VIRTIO_MMIO
- TYPE_OBJECT -> TYPE_BUS -> TYPE_PCI_BUS -> TYPE_PCIE_BUS
- TYPE_OBJECT -> TYPE_BUS -> TYPE_USB_BUS
- TYPE_OBJECT -> TYPE_BUS -> TYPE_VIRTIO_BUS -> TYPE_VIRTIO_PCI_BUS
- TYPE_OBJECT -> TYPE_BUS -> TYPE_VIRTIO_BUS -> TYPE_VIRTIO_MMIO_BUS
- TYPE_OBJECT -> TYPE_MEMORY_BACKEND
- TYPE_OBJECT -> "container"
- TYPE_INTERFACE -> TYPE_NMI
- TYPE_INTERFACE -> TYPE_HOTPLUG_HANDLER -> TYPE_USB_BUS::TYPE_HOTPLUG_HANDLER (动态生成)
- TYPE_INTERFACE -> TYPE_ACPI_DEVICE_IF
- TYPE_INTERFACE -> TYPE_USR_CREATABLE -> TYPE_MEMORY_BACKEND::TYPE_USR_CREATABLE (动态生成)
示意图如下
初始化TypeInfo -> ModuleEntry
每个静态定义的TypeInfo,通过宏type_init定义的构造函数,在main函数被调用之前生成一个ModuleEntry把typeinfo的注册函数和类型挂载到全局ModuleTypeList队列中。
以pci_testdev及其parent为例,数据结构如下。这边TypeInfo指向ModuleEntry.init的箭头表示TypeInfo会作为ModuleEntry.init注册函数的输入形参。
Dump TypeInfo
写个python抓取QEMU代码中所有的TypeInfo定义,保存到typeinfo.csv文件中。
# -*- coding: utf-8 -*-
import os
import re
import pandas as pd
typeinfos = []
def find_cfile(path):
g = os.walk(path)
cfiles = []
for path,dir_list,file_list in g:
for file_name in file_list:
if (file_name.endswith('.c')):
cfiles.append(os.path.join(path, file_name))
return cfiles
def find_typeinfo_file(cfiles):
typeinfo_files = []
for cfile in cfiles:
with open(cfile, 'r') as f:
while True:
line = f.readline() # 逐行读取
if not line:
break
if (line.find('static const TypeInfo') != -1):
typeinfo_files.append(cfile)
break
return typeinfo_files
def find_typeinfos(typeinfo_files):
for typeinfo_file in typeinfo_files:
find_typeinfo(typeinfo_file)
def find_typeinfo(file):
with open(file, 'r') as f:
lines = f.readlines() # 全部读取
i = 0
while True:
if i == len(lines):
break
if lines[i].find('static const TypeInfo') != -1:
i = parse_typeinfo(file, lines, i)
else:
i += 1
def parse_typeinfo (file, lines, i):
typeinfo = {}
typeinfo['file'] = file
typeinfo['name'] = lines[i].split()[3]
typeinfos.append(typeinfo)
i += 1
i = pasre_typeinfo_tokens(lines, i, typeinfo)
return i
def pasre_typeinfo_tokens (lines, i, typeinfo):
while True:
if lines[i].find('.interfaces') != -1:
i = pasre_typeinfo_interface(lines, i, typeinfo)
elif lines[i].find('};') != -1:
return i+1
else:
l = lines[i].split()
if l[0].startswith('.'):
typeinfo[l[0][1:]] = l[2][:-1]
i += 1
return i
def pasre_typeinfo_interface (lines, i, typeinfo):
i += 1
interface = []
while True:
pattern = re.compile(r'{.+}')
result = pattern.findall(lines[i])
if len(result) == 0:
break
for r in result:
r = r[1:-1]
r = r.strip()
if len(r) == 0:
continue
interface.append(r)
i += 1
typeinfo['interface'] = interface
return i
def dump_typeinfo(qemupath):
cfiles = find_cfile(qemupath)
typeinfo_files = find_typeinfo_file(cfiles)
find_typeinfos(typeinfo_files)
pd.DataFrame(typeinfos).to_csv('typeinfo.csv',encoding='utf_8_sig')
return typeinfos
def main():
dump_typeinfo ("C:/qemu")
if __name__ == "__main__":
main()
TypeImpl
每个ypInfo都会注册一个TypeImpl,所有的TypeImpl会以类型名为键值保存在全局的hash表中。
struct TypeImpl
{
//和TypeInfo一一对应部分 - 开始
const char *name;
size_t class_size;
size_t instance_size;
void (*class_init)(ObjectClass *klass, void *data);
void (*class_base_init)(ObjectClass *klass, void *data);
void (*class_finalize)(ObjectClass *klass, void *data);
void *class_data;
void (*instance_init)(Object *obj);
void (*instance_post_init)(Object *obj);
void (*instance_finalize)(Object *obj);
bool abstract;
const char *parent;
//和TypeInfo一一对应部分 - 结束
TypeImpl *parent_type; //父类型的TypeImpl指针
ObjectClass *class; //类型对应的对象类的基类ObjectClass的指针,因为基类是派生类的第一个元素,所以派生对象类指针也相同
int num_interfaces; //TypeInfo中定义的接口数组的个数
InterfaceImpl interfaces[MAX_INTERFACES]; //复制自TypeInfo中InterfaceInfo数组提供的接口名字
};
struct InterfaceImpl
{
const char *typename; //InterfaceImpl数组也是提供接口的名字
};
#define MAX_INTERFACES 32 //TypeInfo中没有个数的限制,TypeImpl中新增加了个数限制,一个类型支持的接口类型最大数目为32
type_new函数会根据TypeInfo输入,初始化生成性的TypeImpl结构。
static TypeImpl *type_new(const TypeInfo *info)
{
TypeImpl *ti = g_malloc0(sizeof(*ti)); //申请空间
int i;
g_assert(info->name != NULL);
if (type_table_lookup(info->name) != NULL) {
fprintf(stderr, "Registering `%s' which already exists\n", info->name);
abort();
}
//从TypeInfo复制数据
ti->name = g_strdup(info->name);
ti->parent = g_strdup(info->parent);
ti->class_size = info->class_size;
ti->instance_size = info->instance_size;
ti->class_init = info->class_init;
ti->class_base_init = info->class_base_init;
ti->class_finalize = info->class_finalize;
ti->class_data = info->class_data;
ti->instance_init = info->instance_init;
ti->instance_post_init = info->instance_post_init;
ti->instance_finalize = info->instance_finalize;
ti->abstract = info->abstract;
for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
}
ti->num_interfaces = i;
return ti;
}
初始化 ModuleEntry -> TypeImpl
QEMU入口main函数的一开始就执行module_call_init(MODULE_INIT_QOM)
int main(int argc, char **argv, char **envp)
{
...
module_call_init(MODULE_INIT_QOM);
...
}
module_call_init找到之前注册的所有的init函数,然后执行它
void module_call_init(module_init_type type)
{
ModuleTypeList *l;
ModuleEntry *e;
module_load(type);
l = find_type(type);
QTAILQ_FOREACH(e, l, node) {
e->init(); //找到之前注册的init函数,调用执行
}
}
以pci_testdev为例,init函数为pci_testdev_register_types,真正执行注册的函数为type_register_internal,调用关系为pci_testdev_register_types->type_register_static->type_register->type_register_internal。
static void pci_testdev_register_types(void)
{
//直接调用type_register_static,并以TypeInfo结构地址为输入参数
type_register_static(&pci_testdev_info);
}
TypeImpl *type_register_static(const TypeInfo *info)
{
//直接调用type_register
return type_register(info);
}
static TypeImpl *type_register_internal(const TypeInfo *info)
{
TypeImpl *ti;
ti = type_new(info);
type_table_add(ti);
return ti;
}
type_register_internal首先调用type_new创建一个TypeImpl结构,并根据TypeInfo初始化它。随后调用type_table_add把TypeImpl添加到hash表,键值为TypeImpl.name
static void type_table_add(TypeImpl *ti)
{
assert(!enumerating_types);
g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
}
static GHashTable *type_table_get(void)
{
static GHashTable *type_table; //静态变量,保存TypeImplhash表地址
//第一次需要初始化
if (type_table == NULL) {
type_table = g_hash_table_new(g_str_hash, g_str_equal);
}
return type_table; //返回hash表地址
}
总结如下
对象类
基对象类ObjectClass
struct ObjectClass
{
/*< private >*/
Type type; //对象类对应的类型TypeImpl的指针
GSList *interfaces; //接口类InterfaceClass指针单向列表,函数type_initialize_interface初始化
const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE]; //debug选项,保存object cast历史
const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE]; //debug选项,保存object class的cast历史
ObjectUnparent *unparent;
};
设备派生对象类
示例PCIDeviceClass对象类的派生关系是ObjectClass->DeviceClass->PCIDeviceClass。
总线派生对象类
示例PciBusClass的派生顺序为ObjectClass -> BusClass -> PCIBusClass
接口对象类
示例UserCreatableClass的派生顺序为ObjectClass -> InterfacClass -> HotplugHandlerClass
内存派生对象类
示例HostMemoryBackendClass的派生顺序为ObjectClass -> HostMemoryBackendClass
加速器派生对象类
示例AccelClass的派生顺序为ObjectClass -> AccelClass
初始化 TypeImpl -> ObjectClass
对象类的初始化是由TypeImpl.class_init函数完成的。TypeImpl.class_init函数在type_initialize函数中被调用。
type_initialize调用有几种情况
- 当要获取一种类型的所有对象类时主动调用循环初始化每个对象类,object_class_get_list -> object_class_foreach -> object_class_foreach_tramp -> type_initialize
- 通过对象类查找父对象类,object_class_get_parent -> type_initialize
- 通过类型名查找对象类,object_new_with_props -> object_new_with_propv -> object_class_by_name -> type_initialize
- 新建一个对象实例, object_get_root -> object_new -> object_new_with_type -> type_initialize
- 初始化一个对象实例,object-initialize - > object_initlialize_with_type
- 初始化对象类的接口,object_intialize_interface -> type_initialize
- 递归调用父对象类,type_intialize -> type_initialize
调用关系如图示
type_initialize函数完成如下工作。
- 申请对象类空间
- 调用type_initialize_interface初始化设备接口
- 调用parent的class_base_init
- 调用本类型的class_init
static void type_initialize(TypeImpl *ti)
{
TypeImpl *parent;
if (ti->class) { //对象类建立了就表示已经初始化过了,直接返回
return;
}
ti->class_size = type_class_get_size(ti); //type_new()时初始化过,这里校正一下
ti->instance_size = type_object_get_size(ti); //type_new()时初始化过,这里校正一下
ti->class = g_malloc0(ti->class_size); //为对象类申请空间
parent = type_get_parent(ti); //获取parent的TypeImpl
if (parent) {
type_initialize(parent); //先初始化parent
GSList *e;
int i;
g_assert_cmpint(parent->class_size, <=, ti->class_size);
memcpy(ti->class, parent->class, parent->class_size); //继承parent的对象类,复制到最前面
//parent对象类已经注册的接口
for (e = parent->class->interfaces; e; e = e->next) { //loop已经注册的interface队列
InterfaceClass *iface = e->data; // 接口对象类的data保持的是InterfaceClass的指针
ObjectClass *klass = OBJECT_CLASS(iface); //cast到基类
type_initialize_interface(ti, iface->interface_type, klass->type); //iface->interface_type和klass->type有区别吗?
}
//TypeImpl中定义的接口
for (i = 0; i < ti->num_interfaces; i++) {
TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); //通过接口类型名找到接口通过TypeInfo注册的TypeImpl的指针
for (e = ti->class->interfaces; e; e = e->next) {
TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
if (type_is_ancestor(target_type, t)) {
break;
}
}
if (e) {
continue; //接口已经初始化过了
}
type_initialize_interface(ti, t, t);
}
}
ti->class->type = ti; //设置TypeImpl指针到对象类的type
while (parent) {
if (parent->class_base_init) {
parent->class_base_init(ti->class, ti->class_data); //调用所有parent对象类的class_base_init函数
}
parent = type_get_parent(parent);
}
if (ti->class_init) {
ti->class_init(ti->class, ti->class_data); //调用对象类初始化函数class_init
}
}
type_initialize_interface
首先每个接口类型会定义自己的TypeInfo,然后注册到TypeImpl全局hash表。例如hotplug_handler_info。在随后的初始化type_initialize函数中接口类型会生成自己的对象类,我们暂且称之为接口对象类。所有接口类型及其父类的TypeInfo都没有定义instance_size,所以不存在接口对象实例。
static const TypeInfo hotplug_handler_info = {
.name = TYPE_HOTPLUG_HANDLER,
.parent = TYPE_INTERFACE,
.class_size = sizeof(HotplugHandlerClass),
};
另一方面,有些QOM设备的TypeInfo定义中,会添加自己支持的接口类型,暂且称为设备接口。例如usb_bus_info和pcie_slot_type_info。这些interfaces随后在TypeImpl注册过程中,会添加到数组 InterfaceImpl interfaces[MAX_INTERFACES]中。interfaces的数目设置到num_interfaces。
static const TypeInfo usb_bus_info = {
.name = TYPE_USB_BUS,
.parent = TYPE_BUS,
.instance_size = sizeof(USBBus),
.class_init = usb_bus_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
static const TypeInfo pcie_slot_type_info = {
.name = TYPE_PCIE_SLOT,
.parent = TYPE_PCIE_PORT,
.instance_size = sizeof(PCIESlot),
.abstract = true,
.class_init = pcie_slot_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
Type_initialize_interface负责初始化设备接口,并把设备接口挂在到对象类的ObjectClass->interfaces队列上。每个TypeImpl需要初始化有两类接口
- 已经挂在到其parent的对象类interfaces队列上上的接口,需要继承过来。
- TypeImpl自己的interfaces数组上的接口。
Type_initialize_interface定义如下
static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
TypeImpl *parent_type)
{
InterfaceClass *new_iface;
TypeInfo info = { };
TypeImpl *iface_impl;
//初始化一个新的类型接口TypeInfo,名称问"设备类型名::接口类型名"
info.parent = parent_type->name;
info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
info.abstract = true;
//根据新初始化的TypeInfo,注册新的接口TypeImpl,同时会生成新的对象类InterfaceClass
iface_impl = type_new(&info); //初始化新的类型接口TypeImpl
iface_impl->parent_type = parent_type;
type_initialize(iface_impl); //初始新的类型接口对象类
g_free((char *)info.name);
//初始化新生成的对象类InterfaceClass
new_iface = (InterfaceClass *)iface_impl->class; //cast到InterfaceClass
new_iface->concrete_class = ti->class; //InterfaceClass->concrete_class指向的接口通过Typeinfo注册TypeImpl时,在type_initialize中申请的对象类。即接口对象类
new_iface->interface_type = interface_type; //指向接口TypeImpl类型
//添加新的接口对象类到类型的对象类的接口单向队列
ti->class->interfaces = g_slist_append(ti->class->interfaces,
iface_impl->class);
}
//每个接口
//1,在type_init构造中会注册全局的接口TypeImpl(名称"接口类型名")和接口对象类,
//2,在本函数中,注册一个为本实例类型服务的设备接口TypeImpl(名称"设备类型名::接口类型名")和设备接口对象类。
class_base_init
在调用class_init之前,先需要调用父类的class_base_init。
对于pci-testdev设备,只有DeviceClass对象类的class_init为device_class_init,如下
static void device_class_base_init(ObjectClass *class, void *data)
{
DeviceClass *klass = DEVICE_CLASS(class);
/* We explicitly look up properties in the superclasses,
* so do not propagate them to the subclasses.
*/
klass->props = NULL;
}
TYPE_MACHINE有定义一个class_base_init,如下
static void machine_class_base_init(ObjectClass *oc, void *data)
{
if (!object_class_is_abstract(oc)) {
MachineClass *mc = MACHINE_CLASS(oc);
const char *cname = object_class_get_name(oc);
assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX));
mc->name = g_strndup(cname,
strlen(cname) - strlen(TYPE_MACHINE_SUFFIX));
}
}
class_init
对象类的class_init初始化从基类开始调用
- ObjectClass基类没有class_init
- DeviceClass对象类的class_init为device_class_init
- PciDeviceClass对象类的class_init为pci_device_class_init
- Pci-testdev没有定义新的对象类,定义了class_init为pci_testdev_class_init
device_class_init定义如下
static void device_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
class->unparent = device_unparent;
dc->realize = device_realize;
dc->unrealize = device_unrealize;
/* by default all devices were considered as hotpluggable,
* so with intent to check it in generic qdev_unplug() /
* device_set_realized() functions make every device
* hotpluggable. Devices that shouldn't be hotpluggable,
* should override it in their class_init()
*/
dc->hotpluggable = true;
}
pci_device_class_init定义如下
static void pci_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
k->realize = pci_qdev_realize;
k->unrealize = pci_qdev_unrealize;
k->bus_type = TYPE_PCI_BUS;
k->props = pci_props;
pc->realize = pci_default_realize;
}
pci_testdev_class_init定义如下
static void pci_testdev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass); //通过对象类基类cast到DeviceClass子类
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); //通过对象类基类cast到PCIDeviceClass子类
k->realize = pci_testdev_realize; //override realize方法
k->exit = pci_testdev_uninit;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_TEST;
k->revision = 0x00;
k->class_id = PCI_CLASS_OTHERS;
dc->desc = "PCI Test Device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->reset = qdev_pci_testdev_reset;
}
对象
基对象Object
struct Object
{
/*< private >*/
ObjectClass *class; //指向对象类
ObjectFree *free; //当引用计数为0时,执行释放方法
GHashTable *properties; //属性hash表
uint32_t ref; //引用计数
Object *parent; //指向父对象,实现继承
};
设备派生对象
示例PCITestDevState的派生顺序是Object->DeviceState->PCIDevice->PCITestDevState。
总线派生对象
示例PCIBus的派生顺序为Object -> BusState -> PCIBus
初始化 TypeImpl -> Object
对象实例的建立是由函数object_new_with_type完成,也有一些对象的空间是静态分配的或提前准备好的,无需再次动态申请,对于这些对象只需要直接调用初始化函数。对象实例的初始化由object_initialize_with_type完成。
调用关系如下
object_new_with_type
Object *object_new_with_type(Type type)
{
Object *obj;
g_assert(type != NULL);
type_initialize(type); //先确保type已经初始化
obj = g_malloc(type->instance_size); //申请对象实例空间
object_initialize_with_type(obj, type->instance_size, type); //初始化对象实例
obj->free = g_free; //基对象的初始化free方法
return obj;
}
object_initialize_with_type
void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
{
Object *obj = data;
g_assert(type != NULL);
type_initialize(type); //确保type已经初始化过
//基本check,确保对象实例的大小,TypeImpl不是抽象类型等
g_assert_cmpint(type->instance_size, >=, sizeof(Object));
g_assert(type->abstract == false);
g_assert_cmpint(size, >=, type->instance_size);
memset(obj, 0, type->instance_size); //对象实例清0
obj->class = type->class; //填写对象实例中的对象类地址
object_ref(obj); //对象基类的ref引用数增加1
obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, object_property_free); //建立属性hash表
object_init_with_type(obj, type); //调用.instance_init
object_post_init_with_type(obj, type); //调用.instance_post_init
}
object_init_with_type定义如下
static void object_init_with_type(Object *obj, TypeImpl *ti)
{
if (type_has_parent(ti)) {
object_init_with_type(obj, type_get_parent(ti)); //首先执行parent的instance_init
}
if (ti->instance_init) { //执行instance_init
ti->instance_init(obj);
}
}
object_post_init_with_type定义如下
static void object_post_init_with_type(Object *obj, TypeImpl *ti)
{
if (ti->instance_post_init) {
ti->instance_post_init(obj); //先执行对象自身的instance_post_init
}
if (type_has_parent(ti)) {
object_post_init_with_type(obj, type_get_parent(ti)); //再执行parent对象的instance_post_init
}
}
调用object_new
来看看是如何调用到object_new的。每个设备在QEMU启动时都体现为命令行中一个‘-device’参数。QEMU main函数会解析每个-device参数,调用device_init_func来完成设备的初始化。
int main(int argc, char **argv, char **envp)
{
...
/* init generic devices */
if (qemu_opts_foreach(qemu_find_opts("device"), //对于每个“-devcie”参数,调用device_init_func函数
device_init_func, NULL, NULL)) {
exit(1);
}
...
}
device_init_func定义如下
static int device_init_func(void *opaque, QemuOpts *opts, Error **errp)
{
Error *err = NULL;
DeviceState *dev;
dev = qdev_device_add(opts, &err); //添加设备
if (!dev) {
error_report_err(err);
return -1;
}
object_unref(OBJECT(dev)); //对象基类的ref减1,当ref值为1时调用object_finalize
return 0;
}
qdev_device_add
来看看qdev_device_add的完整代码
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
{
DeviceClass *dc;
const char *driver, *path, *id;
DeviceState *dev;
BusState *bus = NULL;
Error *err = NULL;
driver = qemu_opt_get(opts, "driver"); //一定要有driver参数?
if (!driver) {
error_setg(errp, QERR_MISSING_PARAMETER, "driver");
return NULL;
}
/* find driver */
dc = qdev_get_device_class(&driver, errp); //通过driver名找到对象类DeviceClass
if (!dc) {
return NULL;
}
/* find bus */
path = qemu_opt_get(opts, "bus"); //bus参数
if (path != NULL) { //bus参数存在
bus = qbus_find(path, errp); //找到bus的对象类
if (!bus) {
return NULL;
}
if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) { //类型check
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) { //bus参数不存在,对象类的bus_type有值
bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type); //通过对象类的bus_type找到bus对象
if (!bus || qbus_is_full(bus)) {
error_setg(errp, "No '%s' bus found for device '%s'",
dc->bus_type, driver);
return NULL;
}
}
if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) {
error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
return NULL;
}
/* create device */
dev = DEVICE(object_new(driver)); //建立设备对象实例
//bus对象实例存在时,添加设备对象实例到bus对象实例的link属性,bus对象实例的ref增加1,设置设备对象实例的parent_bus
if (bus) {
qdev_set_parent_bus(dev, bus);
}
id = qemu_opts_id(opts); //从命令行参数获取id
if (id) {
dev->id = id; //保持到DeviceState对象中的id
}
//添加对象到qdev的peripheral对象的对象属性中
if (dev->id) { //id有指定
//"container/machine/peripheral"
object_property_add_child(qdev_get_peripheral(), dev->id,
OBJECT(dev), NULL);
} else { //id没有指定
static int anon_count;
gchar *name = g_strdup_printf("device[%d]", anon_count++);
//"container/machine/peripheral"
object_property_add_child(qdev_get_peripheral_anon(), name,
OBJECT(dev), NULL);
g_free(name);
}
/* set properties */
if (qemu_opt_foreach(opts, set_property, dev, &err)) { //解析QEMU命令行参数中的对象属性,执行set方法
error_propagate(errp, err);
object_unparent(OBJECT(dev));
object_unref(OBJECT(dev));
return NULL;
}
dev->opts = opts;
object_property_set_bool(OBJECT(dev), true, "realized", &err); //执行realize对象属性的set方法
if (err != NULL) {
error_propagate(errp, err);
dev->opts = NULL;
object_unparent(OBJECT(dev));
object_unref(OBJECT(dev));
return NULL;
}
return dev;
}
instance_init
instance_init的执行顺序是先parent再自己,对于Pci-testdev
- TYPE_OBJECT的instance_init为object_instance_init
- TYPE_DEVICE的instance_init为device_initfn
- TYPE_PCI_DEVICE的instance_init定义为空
- TYPE_PCI_TEST_DEV的instance_init定义为空
object_instance_init
static void object_instance_init(Object *obj)
{
object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); //添加“type”为string对象属性
}
device_initfn
static void device_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj); //通过对象基类cast到DeviceState
ObjectClass *class;
Property *prop;
if (qdev_hotplug) { //设置支持hotplug的flag
dev->hotplugged = 1;
qdev_hot_added = true;
}
dev->instance_id_alias = -1;
dev->realized = false;
//添加“realized”,"hotpluggable","hotplugged"等bool对象属性
object_property_add_bool(obj, "realized",
device_get_realized, device_set_realized, NULL);
object_property_add_bool(obj, "hotpluggable",
device_get_hotpluggable, NULL, NULL);
object_property_add_bool(obj, "hotplugged",
device_get_hotplugged, device_set_hotplugged,
&error_abort);
//把对象类的属性添加到legacy和static对象属性中?
class = object_get_class(OBJECT(dev));
do {
for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, &error_abort);
qdev_property_add_static(dev, prop, &error_abort);
}
class = object_class_get_parent(class);
} while (class != object_class_by_name(TYPE_DEVICE));
//添加parent_bus到link对象属性
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
(Object **)&dev->parent_bus, NULL, 0,
&error_abort);
//初始化队列dev->gpios
QLIST_INIT(&dev->gpios);
}
instance_post_init
instance_post_init的执行顺序是先自己再parent,对于Pci-testdev
- TYPE_OBJECT的instance_post_init定义为空
- TYPE_DEVICE的instance_post_init为device_post_init
- TYPE_PCI_DEVICE的instance_post_init定义为空
- TYPE_PCI_TEST_DEV的instance_post_init定义为空
device_post_init
static void device_post_init(Object *obj)
{
qdev_prop_set_globals(DEVICE(obj));
}
void qdev_prop_set_globals(DeviceState *dev)
{
ObjectClass *class = object_get_class(OBJECT(dev));
//对象类到父对象类递归,得到对象类型名称
do {
qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
class = object_class_get_parent(class);
} while (class);
}
static void qdev_prop_set_globals_for_type(DeviceState *dev,
const char *typename)
{
GlobalProperty *prop;
QTAILQ_FOREACH(prop, &global_props, next) { //全局的队列global_props
Error *err = NULL;
if (strcmp(typename, prop->driver) != 0) { //全局队列global_props中找到driver名字与类型名字一致的项
continue;
}
prop->used = true;
object_property_parse(OBJECT(dev), prop->value, prop->property, &err); //解析对象是否存在global_props中的属性,存在的话执行set方法
if (err != NULL) {
assert(prop->user_provided);
error_report("Warning: global %s.%s=%s ignored (%s)",
prop->driver, prop->property, prop->value,
error_get_pretty(err));
error_free(err);
return;
}
}
}
属性
属性包含两类,一类是对象(Object)属性ObjectProperty,一类是对象类属性Property
ObjectProperty
对象(Object)包含属性hash表GHashTable *properties,存储了 属性名 到 ObjectProperty 的映射。
typedef struct ObjectProperty
{
gchar *name; //属性名
gchar *type; //属性类型
//如"int","uint32","size","uint64","bool","string","child<%s>"等
gchar *description;
ObjectPropertyAccessor *get; //读取属性时触发的get方法
ObjectPropertyAccessor *set; //设置属性时触发的set方法
ObjectPropertyResolve *resolve; //resolve方法
ObjectPropertyRelease *release; //release方法
void *opaque; //额外的非透明的信息,
//在object_property_add_bool中添加的"bool"属性中指向BoolProperty
//在object_property_add_child中添加的"child"属性中指向child的对象实例
//在object_property_add_link中添加的"link"属性中指向LinkProperty
//在object_property_add_str中添加的"string"属性中指向StringProperty
//在object_property_add_enum中添加的"string"属性中指向EnumProperty
} ObjectProperty;
函数object_property_add负责添加
ObjectProperty *
object_property_add(Object *obj, const char *name, const char *type,
ObjectPropertyAccessor *get,
ObjectPropertyAccessor *set,
ObjectPropertyRelease *release,
void *opaque, Error **errp)
{
ObjectProperty *prop;
...
prop = g_malloc0(sizeof(*prop));
prop->name = g_strdup(name);
prop->type = g_strdup(type);
prop->get = get;
prop->set = set;
prop->release = release;
prop->opaque = opaque;
g_hash_table_insert(obj->properties, prop->name, prop); //添加到Object对象的properties hash表
return prop;
}
get/set callback方法
ObjectProperty的get/set callback方法的调用,还用到了很多中间概念。
第一个概念是QObject,它是每个ObjectProperty get/set callback方法调用过程中的数据载体的基类。定义的是ObjectProperty的类型代码,引用次数,以及销毁函数。
typedef struct QObject {
const QType *type; //QObject的代码及销毁函数
size_t refcnt; //引用次数
} QObject;
typedef struct QType {
qtype_code code; //代码
void (*destroy)(struct QObject *); //销毁函数
} QType;
QOBJECT_INIT用于初始化各个派生类型的基类QObject
#define QOBJECT_INIT(obj, qtype_type) \
obj->base.refcnt = 1; \ //设置引用refcnt为1
obj->base.type = qtype_type //设置type为qstring_type
QObject是一个基类结构,它可以派生出很多类型。这些派生类会根据每个类型,添加上数据选项。
typedef struct QBool {
QObject base;
bool value; //布尔数值
} QBool;
typedef struct QString {
QObject base;
char *string; //字串
size_t length; //字串长度
size_t capacity; //字串容量,和长度值相同
} QString;
typedef struct QInt {
QObject base;
int64_t value; //整型数值
} QInt;
typedef struct QDict {
QObject base;
size_t size;
QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX]; //字典
} QDict;
typedef struct QFloat {
QObject base;
double value; //浮点数值
} QFloat;
typedef struct QList {
QObject base;
QTAILQ_HEAD(,QListEntry) head; //队列
} QList;
每个派生类型的Qtype定义为
Qtype | |
.code | .destroy |
QTYPE_QSTRING | qstring_destroy_obj |
QTYPE_QBOOL | qbool_destroy_obj |
QTYPE_QDICT | qdict_destroy_obj |
QTYPE_QFLOAT | qfloat_destroy_obj |
QTYPE_QINT | qint_destroy_obj |
QTYPE_QLIST | qlist_destroy_obj |
QTYPE_QNULL | qnull_destroy_obj |
第二个概念是方法Visitor结构,它定义了访问ObjectProperty各个数据类型的方法。
struct Visitor
{
/* Must be set */
void (*start_struct)(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp);
void (*end_struct)(Visitor *v, Error **errp);
void (*start_implicit_struct)(Visitor *v, void **obj, size_t size,
Error **errp);
void (*end_implicit_struct)(Visitor *v, Error **errp);
void (*start_list)(Visitor *v, const char *name, Error **errp);
GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
void (*end_list)(Visitor *v, Error **errp);
void (*type_enum)(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp);
void (*get_next_type)(Visitor *v, int *kind, const int *qobjects,
const char *name, Error **errp);
void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
void (*type_number)(Visitor *v, double *obj, const char *name,
Error **errp);
void (*type_any)(Visitor *v, QObject **obj, const char *name,
Error **errp);
/* May be NULL */
void (*optional)(Visitor *v, bool *present, const char *name,
Error **errp);
void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);
void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp);
void (*type_uint64)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
void (*type_int8)(Visitor *v, int8_t *obj, const char *name, Error **errp);
void (*type_int16)(Visitor *v, int16_t *obj, const char *name, Error **errp);
void (*type_int32)(Visitor *v, int32_t *obj, const char *name, Error **errp);
void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp);
/* visit_type_size() falls back to (*type_uint64)() if type_size is unset */
void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
bool (*start_union)(Visitor *v, bool data_present, Error **errp);
void (*end_union)(Visitor *v, bool data_present, Error **errp);
};
对于set方法,QmpInputVisitor定义了Vistor方法,以及一个StackObject数组。每个数组元素StackObject是一个QObject的派生。StackObject还包括一个QObject的队列,以及一个hash表。
struct QmpInputVisitor
{
Visitor visitor; //Visitor方法数组
StackObject stack[QIV_STACK_SIZE]; //StackObject数组, 最大1024个
int nb_stack;
bool strict;
};
#define QIV_STACK_SIZE 1024
typedef struct StackObject
{
QObject *obj; //指向各个派生类型的QObject基类
const QListEntry *entry; //QObject队列?
GHashTable *h; //为字典类型准备的hash表
} StackObject;
typedef struct QListEntry {
QObject *value;
QTAILQ_ENTRY(QListEntry) next;
} QListEntry;
对于get方法,QmpOutputVisitor定义了Vistor方法,以及一个QStack队列头。队列元素为QStackEntry。
struct QmpOutputVisitor
{
Visitor visitor; //vistor方法
QStack stack; //QStack队列
};
typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
typedef struct QStackEntry //QStack队列元素为QStackEntry
{
QObject *value; //QStackEntry是基类QObject的派生
bool is_list_head;
QTAILQ_ENTRY(QStackEntry) node;
} QStackEntry;
QmpImputVisitor负责新建一个QmpInputVisitor,并初始化它。
QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
{
QmpInputVisitor *v;
v = g_malloc0(sizeof(*v)); //申请空间
//初始化Visitor各个方法
v->visitor.start_struct = qmp_input_start_struct;
v->visitor.end_struct = qmp_input_end_struct;
v->visitor.start_implicit_struct = qmp_input_start_implicit_struct;
v->visitor.end_implicit_struct = qmp_input_end_implicit_struct;
v->visitor.start_list = qmp_input_start_list;
v->visitor.next_list = qmp_input_next_list;
v->visitor.end_list = qmp_input_end_list;
v->visitor.type_enum = input_type_enum;
v->visitor.type_int = qmp_input_type_int;
v->visitor.type_bool = qmp_input_type_bool;
v->visitor.type_str = qmp_input_type_str;
v->visitor.type_number = qmp_input_type_number;
v->visitor.type_any = qmp_input_type_any;
v->visitor.optional = qmp_input_optional;
v->visitor.get_next_type = qmp_input_get_next_type;
qmp_input_push(v, obj, NULL); //添加QObject到StackObject->stack
qobject_incref(obj); //该QObecjt的引用次数refcnt增加1
return v;
}
qmp_input_push初始化QmpInputVisitor中的StackObject->stack
static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
{
GHashTable *h;
if (qiv->nb_stack >= QIV_STACK_SIZE) {
error_setg(errp, "An internal buffer overran");
return;
}
qiv->stack[qiv->nb_stack].obj = obj;
qiv->stack[qiv->nb_stack].entry = NULL;
qiv->stack[qiv->nb_stack].h = NULL;
if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
h = g_hash_table_new(g_str_hash, g_str_equal);
qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
qiv->stack[qiv->nb_stack].h = h;
}
qiv->nb_stack++;
}
对于get方法,qmp_output_visitor_new负责new一个QmpOutputVisitor,并初始化vistor各个 方法和QStack队列。
QmpOutputVisitor *qmp_output_visitor_new(void)
{
QmpOutputVisitor *v;
v = g_malloc0(sizeof(*v));
v->visitor.start_struct = qmp_output_start_struct;
v->visitor.end_struct = qmp_output_end_struct;
v->visitor.start_list = qmp_output_start_list;
v->visitor.next_list = qmp_output_next_list;
v->visitor.end_list = qmp_output_end_list;
v->visitor.type_enum = output_type_enum;
v->visitor.type_int = qmp_output_type_int;
v->visitor.type_bool = qmp_output_type_bool;
v->visitor.type_str = qmp_output_type_str;
v->visitor.type_number = qmp_output_type_number;
v->visitor.type_any = qmp_output_type_any;
QTAILQ_INIT(&v->stack);
return v;
}
每个ObjectProperty的get/set方法的第二个参数就是vistor结构指针
typedef void (ObjectPropertyAccessor)(Object *obj,
struct Visitor *v,
void *opaque,
const char *name,
Error **errp);
通过这个指针也很容易cast到QmpOutputVisitor结构
static QmpOutputVisitor *to_qov(Visitor *v)
{
return container_of(v, QmpOutputVisitor, visitor);
}
#define container_of(ptr, type, member) ({ \
const typeof(((type *) 0)->member) *__mptr = (ptr); \
(type *) ((char *) __mptr - offsetof(type, member));})
下面以string属性为类,看看具体的get/set方法
先看set,object_property_set_str函数先把string转换为QStraing,并添加到QmpInputVisitor中。随后的Visitor方法再逆向得到string字串,调用StringProperty->set方法完成最终的设置动作。
再看get,object_property_get_str函数先通过object_property_get_qobject获取String的QString对象,然后通过qstring_get_str得到最终的string字串,最后还需要将refcnt减1,并判断是否需要销毁该QObject。
部分ObjectProperty的API接口总结
API | type | get | set | release | opaque |
object_property_add_child | "child<%typename%>" | object_get_child_property | NULL | object_finalize_child_property | Object |
object_property_add_str | "string" | property_get_str | property_set_str | property_release_str | StringProperty |
object_property_add_bool | "bool" | property_get_bool | property_set_bool | property_release_bool | BoolProperty |
object_property_add_link | "link<%typename%>" | object_get_link_property | object_set_link_property | object_release_link_property | LinkProperty |
object_property_add_enum | input | property_get_enum | property_set_enum | property_release_enum | EnumProperty |
object_property_add_uint8_ptr | "uint8" | property_get_uint8_ptr | NULL | NULL | uint8_t |
object_property_add_uint16_ptr | "uint16" | property_get_uint16_ptr | NULL | NULL | uint16_t |
object_property_add_uint32_ptr | "uint32" | property_get_uint32_ptr | NULL | NULL | uint32_t |
object_property_add_uint64_ptr | "uint64" | property_get_uint64_ptr | NULL | NULL | uint64_t |
object_property_add_alias | "link<%typename%>" or %typename% |
property_get_alias | property_set_alias | property_release_alias | AliasProperty |
object_property_add | input | input | input | input | input |
qdev_property_add_legacy | "legacy-%Propertyname%" | qdev_get_legacy_property | NULL | NULL | Property |
qdev_property_add_static | "%Propertyname%" | Property.info->get | Property.info->set | Property.info->release | Property |
Property
对象类DeviceClass (派生自ObjectClass基类)包含Property列表
typedef struct DeviceClass {
/*< private >*/
ObjectClass parent_class;
/*< public >*/
...
Property *props; //属性列表
...
} DeviceClass;
Property结构定义如下
struct Property {
const char *name;
PropertyInfo *info;
ptrdiff_t offset;
uint8_t bitnr;
qtype_code qtype;
int64_t defval;
int arrayoffset;
PropertyInfo *arrayinfo;
int arrayfieldsize;
};
struct PropertyInfo {
const char *name;
const char *description;
const char * const *enum_table;
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
ObjectPropertyRelease *release;
};
DeviceClass.props一般在对象类的class_init中执行,属性列表一般为静态的,初始化就是指针赋值动作。
static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
...
dc->props = host_x86_cpu_properties;
...
}
//静态属性列表
static Property host_x86_cpu_properties[] = {
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false),
DEFINE_PROP_END_OF_LIST()
};
DeviceClass.class_init方法把Property属性会转化为ObjectProperty
static void device_initfn(Object *obj)
{
...
class = object_get_class(OBJECT(dev));
do {
for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, &error_abort); //名为"legacy-%接口名%"的字串属性
qdev_property_add_static(dev, prop, &error_abort); //以Property信息为input
}
class = object_class_get_parent(class);
} while (class != object_class_by_name(TYPE_DEVICE));
...
}
GlobalProperty
GlobalProperty定义如下,它包含QTAIL_ENTRY队列
typedef struct GlobalProperty {
const char *driver;
const char *property;
const char *value;
bool user_provided;
bool used;
QTAILQ_ENTRY(GlobalProperty) next;
} GlobalProperty;
所有的GlobalProperty是挂载到QTAIL_HEAD队列头global_props
static QTAILQ_HEAD(, GlobalProperty) global_props =
QTAILQ_HEAD_INITIALIZER(global_props);
void qdev_prop_register_global(GlobalProperty *prop)
{
QTAILQ_INSERT_TAIL(&global_props, prop, next);
}
void qdev_prop_register_global_list(GlobalProperty *props)
{
int i;
for (i = 0; props[i].driver != NULL; i++) {
qdev_prop_register_global(props+i);
}
}
添加GlobalProperty的几种方法
- 命令行参数“global”定义多个GlobalProperty,由函数qemu_add_globals添加到队列中
- 特别的一些QEMU命令行参数,例如“rtc_td_hack”,定义一个GlobalProperty entry,通过qdev_prop_register_global_list函数添加
- 定义machine时,SET_MACHINE_COMPAT宏定义MachineClass.compat_props,随后通过qdev_prop_register_global_list函数来添加到队列中
注册好的GloabalProperty在device_post_init函数中会被使用。device_post_init为TYPE_DEVICE的instance_post_init。每个QOM设备在初始化过程中都需要调用到该函数。查看每个设备是否包含GloabalProperty定义的属性,找到的话就调用它的set方法。
device_post_init
-> qdev_prop_set_globals
-> loop device and its parent 调用 qdev_prop_set_globals_for_type
-> loop GlobalProperty in global_props队列,调用object_property_parse
-> string_input_visitor_new 新建并初始化StringInputVisitor
-> object_property_set
-> ObjectProperty->set
-> string_input_visitor_cleanup
"container"属性
Qdev使用“containner"属性来实现device tree功能。
在qom/container.c中定义了container设备的TypeInfo信息。
static const TypeInfo container_info = {
.name = "container",
.instance_size = sizeof(Object),
.parent = TYPE_OBJECT,
};
object_get_root接口生成root 对象。
Object *object_get_root(void)
{
static Object *root;
if (!root) {
root = object_new("container"); //生成“container”对象
}
return root;
}
container_get接口用于建立设备的path tree。为每一级path建立一个“container”对象,然后把每一级path路径作为child属性添加到这一级的“container”对象上。
Object *container_get(Object *root, const char *path)
{
Object *obj, *child;
gchar **parts;
int i;
parts = g_strsplit(path, "/", 0);
assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
obj = root;
for (i = 1; parts[i] != NULL; i++, obj = child) {
child = object_resolve_path_component(obj, parts[i]); //找到路径的对象
if (!child) {
child = object_new("container"); //没有找到,新建一个
object_property_add_child(obj, parts[i], child, NULL); //添加路径到对象属性
}
}
g_strfreev(parts);
return obj;
}
例如qdev_get_machine会调用container_get,建立/machine路径。
Object *qdev_get_machine(void)
{
static Object *dev;
if (dev == NULL) {
dev = container_get(object_get_root(), "/machine");
}
return dev;
}
Reference
https://www.binss.me/blog/qemu-note-of-qemu-object-model/
https://terenceli.github.io/%E6%8A%80%E6%9C%AF/2017/01/08/qom-introduction
https://www.linux-kvm.org/images/0/0b/Kvm-forum-2013-Modern-QEMU-devices.pdf