Qemu VirtIO设备模拟分析1-virtio的QOM分析(以VirtIONetPCI为例)

基本介绍

        本文直接从VirtIO开始分析,在前期需要一些基础只是特别是Qemu的QOM对象模型,有很多其他的技术文档都分析的很好。VirtIONETPCI设备同样遵循QOM模型。VirtIONetPCI是一个半虚拟化的网卡设备,在guest os中存在virtio网络驱动对其进行操作,在qemu中的VirtIONetPCI是virtio网络的后端,它使用host os提供的网络资源来模拟虚拟机的网络设备。VirtIONetPCI即是一个PCI设备又是一个VirtIO设备,在guest os中,它的表现跟传统的PCI设备一样,guest os的PCI设备扫描时能够扫描到该设备,并加载驱动进行执行。
        VirtIO设备模拟分析需要了解一些VirtIO的资料,后续文章慢慢补充,本文先讲解的是VirtIO的QOM过程,暂时不太需要这些知识。

正文

1. VirtIONetPCI设备的继承关系

        VirtIONetPCI设备是一个多重继承的设备,其定义如下所示:

struct VirtIONetPCI {
	 VirtIOPCIProxy parent_obj;
	 VirtIONet vdev;
};  

        VirtIONetPCI包含有两个字段: VirtIOPCIProxy和VirtIONet,它是多重集成,即是一个PCI设备,又是一个VirtIO设备。
        VirtIOPCIProxy代表一个PCI设备,它以QOM正常的继承方式继承父类PCIDeviceClass的,初始化也是以正常的方式(使用object_new)来初始化。其继承链是:
                Object->Device->PCIDevice->VirtIOPCIProxy->VirtIONetPCI

        VirtIONet以组合的方式集成到VirtIONetPCI中,它不能以正常的QOM对象的初始化方式初始化,在VirtIONetPCI初始化的最后一步,会调用type_impl(TYPE_VIRTIO_NET_PCI)->instance_init进行对象初始化,在该函数中调用virtio_instance_init_common->object_initialize函数初始化其内部对象VirtIONet字段,就像C++中的一个对象数据成员的初始化,在构造函数中调用数据成员的构造函数。其继承链是:
                Object->Device->VirtIODevice->VirtIONet

        VirtIONetPCI的初始化分为类初始化和对象初始化两部分,两条继承链都要初始化,QOM的类和对象的初始化顺序来说,其初始化顺序为:
        先初始化继承链上的类型(按从左到右的顺序):
                Objectclass->DeviceClass->PCIDeviceClass->VirtioPCIClass->VirtIoNetPCIClass -->VirtIODevice->VirtIONet
        再初始化继承链上的对象(按从左到右的顺序):
                Object->DeviceState->PCIDevice->VirtIOPCIProxy->VirtIONetPCI–>VirtIODevice->VirtIONet

2. VirtIONetPCI的类型的初始化

        VIrtIONetPCI类型的初始化是沿着类继承链来初始化的,在qemu启动时,每次使用object_new初始化一个对象时,它首先会判断该对象的类型有没有初始化,如果没有初始化就调用type_initialize(Type)来初始化该对象的类,该函数会沿着继承链依次初始化每个类型,其中父类型会拷贝到子类型中的父类型字段中。
        最先初始化的是ObjectClass,其代码如下:

   static TypeInfo object_info = {
       .name = TYPE_OBJECT,
       .instance_size = sizeof(Object),
       .instance_init = object_instance_init,
       .abstract = true,
   };  

        可以看到类型TYPE_OBJECT(ObjectClass)并没有class_init函数,也就是说该类型初始化时并不需要做特殊的初始化操作,这是自然的,对象Object和类型ObjectClass并没有模拟一个有意义的设备,只是为了构建面向对象继承关系的工具结构体,这意味着ObjectClass类型初始化时只是分配了一个struct ObjectClass结构体,放在全局类型hash表中。
        接下来要初始化的是DeviceClass类型:

static const TypeInfo device_type_info = {
   .name = TYPE_DEVICE,
   .parent = TYPE_OBJECT,
   .instance_size = sizeof(DeviceState),
   .instance_init = device_initfn,
   .instance_post_init = device_post_init,
   .instance_finalize = device_finalize,
   .class_base_init = device_class_base_init,
   .class_init = device_class_init,
   .abstract = true,
   .class_size = sizeof(DeviceClass),
};

85 typedef struct DeviceClass {
87     ObjectClass parent_class;
90     DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
91     const char *fw_name;
92     const char *desc;
93     Property *props;
106     bool user_creatable;
107     bool hotpluggable;
110     DeviceReset reset;
111     DeviceRealize realize;
112     DeviceUnrealize unrealize;
115     const struct VMStateDescription *vmsd;
118     const char *bus_type;
119 } DeviceClass;


1040 static void device_class_init(ObjectClass *class, void *data)
1041 {
1042     DeviceClass *dc = DEVICE_CLASS(class);
1043 
1044     class->unparent = device_unparent;
1052     dc->hotpluggable = true;
1053     dc->user_creatable = true;
1054 }

        DeviceClass类型继承自ObjectClass,它是qemu要模拟的所有类型的父类型,定义了设备的通用属性和方法。

  • parent_class : 指向父类型的指针。
  • fw_name : firware名称
  • propertys: 属性,在qemu中,每个设备都有各自的属性,以链表的形式保存在设备的根结构Object的properties字段中。但是每个设备有哪些属性,是在设备的类型中定义的,即这里的properties字段定义设备有哪些属性,设备类型的继承链上每个子类型都有可能定义一些属性,在设备初始化时,会把遍历设备类型继承链,把所有属性都存放到Object的属性链表中。
  • user_creatable:设备是否是可以由用户创建的,理论上所有外设都应该是用户可创建的,这个字段不应该存在,但是有些设备会由于某些隐秘的原因会初始化失败,把这些失败信息反馈给用户是比较残酷的,所以设置该字段。
  • hotpluggable: 设备是否是可插拔的
  • reset: 设备复位回调函数
  • realize: 设备实例化回调函数。qemu的设备初始化分为两步,一个是设备类型中定义的构造函数(instance_init),自创建设备(object_new)时调用,另外一个是这里的realize函数,在设备的realied属性被设置为true时调用。
  • unrealize: 与realize回调函数对应,设备清理时调用。
  • VMStateDescription:该结构体用来保存设备的状态,在虚拟机迁移或冻结时使用。
  • bus_type:总线类型,在qdev的设备模型中,每个设备都有其挂接的总线。
            上面介绍了通用设备类型的一些属性和函数接口,device_class_init对通用设备类型做初始化,它很简单,默认设置设备为用户创建的和可热插拔的。

        DeviceClass类初始化后,接下来初时候PCIDeviceClass。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值