hci\ } }
voidpc_basic_device_init(ISABus*isa_bus,qemu_irq*gsi,
ISADevice**rtc_state,
ISADevice**floppy,
boolno_vmport) {
//初始化HPET
//初始化mc146818 rtc //初始化i8042 PIT
pit=pit_init(isa_bus,0x40,pit_isa_irq,pit_alt_irq); //初始化串口,并口
//初始化vmmouse ps2_mouse }
接下来的流程是pit_init -> isa_create(bus, \qdev_create -> qdev_try_create,qdev_try_create的实现在前面已经讲了,如上节所述,它分别使用 object_class_by_name和object_new来初始化ObjectClass和Object。
属性设置
Object同ObjectClass的显著区别就是Object提供了属性的概念,以MC146818为例,其定义时设置了\和\: static Property mc146818rtc_properties[] =
{ DEFINE_PROP_INT32(\DEFINE_PROP_LOSTTICKPOLICY(\lost_tick_policy, LOST_TICK_DISCARD), DEFINE_PROP_END_OF_LIST(), };
staticPropertymc146818rtc_properties[]={
};
DEFINE_PROP_INT32(\DEFINE_PROP_LOSTTICKPOLICY(\lost_tick_policy,LOST_TICK_DISCARD), DEFINE_PROP_END_OF_LIST(),
但是用GDB一看:
(gdb) p *obj->properties.tqh_first
$15 = {name = 0x555556a17df0 \\
release = 0x555555727980 , opaque = 0x555556a17d80, node = {tqe_next = 0x555556a17e50, tqe_prev = 0x555556a17af0}} (gdb) p *obj->properties.tqh_first.node.tqe_next
$21 = {name = 0x555556a17ea0 \\release = 0x555555727940 , opaque = 0x555556a17e30, node = {tqe_next = 0x555556a17ee0, tqe_prev = 0x555556a17dd0}} (gdb) p *obj->properties.tqh_first.node.tqe_next.node.tqe_next $22 = {name = 0x555556a17f30 \\= 0,
opaque = 0x555555d4e1a0, node = {tqe_next = 0x555556a50ee0, tqe_prev = 0x555556a17e80}} (gdb) p
*obj->properties.tqh_first.node.tqe_next.node.tqe_next.node.t
qe_next
$23 = {name = 0x555556a1be30 \0x555556a1be50 \0x5555556af990 ,
release = 0, opaque = 0x555555d4e1c0, node = {tqe_next = 0x555556a50fa0, tqe_prev = 0x555556a17f10}} (gdb) p
*obj->properties.tqh_first.node.tqe_next.node.tqe_next.node.tqe_next.node.tqe_next
$24 = {name = 0x555556a50f80 \type = 0x55555680b1d0 \
set = 0x55555572a320 , release = 0, opaque = 0x555556a17b30, node = {tqe_next = 0x0, tqe_prev = 0x555556a50f10}} (gdb) p
*obj->properties.tqh_first.node.tqe_next.node.tqe_next.node.tqe_next.node.tqe_next.node.tqe_next Cannot access memory at address 0x0
事实上却多了\,这些属性都是动态添加的。
在\类型的,instance_init = object_instance_init回调处,添加了
object_property_add_str(obj, \NULL);
1 object_property_add_str(obj,\
在\类型的instance_init = device_initfn回调处,添加了 object_property_add_bool(obj, \device_set_realized, NULL);
bject_property_add_link(OBJECT(dev), \(Object **)&dev->parent_bus, NULL);
object_property_add_bool(obj,\1 device_get_realized,2 device_set_realized,NULL); 3 bject_property_add_link(OBJECT(dev),\4 (Object**)&dev->parent_bus,NULL);
设置属性的时候,调用类似qdev_prop_set_int32(&dev->qdev, \base_year);进行设置,这里,注意第一个参数为什么是DeviceState* dev->qdev而不是ISADevice *dev?
因为rtc_class_initfn里初始化props是给 DeviceClass *dc初始化的,所以对应的应该是DeviceState而不是子类ISADevice。 设置属性是如何实现的?
以\的bool属性设置为例,调用顺序为
object_property_set_bool -> object_property_set_qobject -> object_property_set,此函数定义:
void object_property_set(Object *obj, Visitor *v, const char *name, Error **errp) { //obj还是\的实例,name为
\,object_property_find其实就是查找obj的properties链表里是否存在名字为name的属性 ObjectProperty *prop = object_property_find(obj, name, errp); if (prop == NULL) { return; } if (!prop->set) {//如果存在,且没有设置过set handler,错误 error_set(errp, QERR_PERMISSION_DENIED); } else
{//\的set函数为property_set_bool prop->set(obj, v, prop->opaque, name, errp); } } static void
property_set_bool(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { BoolProperty *prop = opaque; bool value; Error *local_err = NULL; visit_type_bool(v, &value, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; } prop->set(obj, value, errp); //对于realized来说,其实就是调用device_set_realized }
1 voidobject_property_set(Object*obj,Visitor*v,constchar*name, 2 Error**errp) 3 {
4 //obj还是\的实例,name为\,
5 object_property_find其实就是查找obj的properties链表里是否存在名字6 为name的属性
7 ObjectProperty*prop=object_property_find(obj,name,errp); 8 if(prop==NULL){ 9 return; 1 }
0 if(!prop->set){//如果存在,且没有设置过set handler,错误 1 error_set(errp,QERR_PERMISSION_DENIED); 1 }else{//\的set函数为property_set_bool 1 prop->set(obj,v,prop->opaque,name,errp); 2 } 1} 3
1staticvoidproperty_set_bool(Object*obj,Visitor*v,void*opaque,