接前一篇文章:
本文内容参考:
《 QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
上一回开始正式结合代码讲解virtio的实现机制和细节。首先给出了virtio PCI代理设备类型的定义,以及其下的一些virtio设备,如virtio balloon PCI设备、virtio scsi PCI设备以及virtio crypto PCI设备。并且给出了virtio设备在系统的设备树中的位置,如下图所示:
由上图可见,所有的virtio设备都有一个共同的父类TYPE_VIRTIO_DEVICE。例如:
- virtual balloon设备
virtual balloon设备的定义如下(hw/virtio/virtio-balloon.c中):
static const TypeInfo virtio_balloon_info = {
.name = TYPE_VIRTIO_BALLOON,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBalloon),
.instance_init = virtio_balloon_instance_init,
.class_init = virtio_balloon_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_balloon_info);
}
type_init(virtio_register_types)
关联:
- virtio balloon PCI设备
virtio balloon PCI设备的定义在hw/virtio/virtio-balloon-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { .base_name = TYPE_VIRTIO_BALLOON_PCI, .generic_name = "virtio-balloon-pci", .transitional_name = "virtio-balloon-pci-transitional", .non_transitional_name = "virtio-balloon-pci-non-transitional", .instance_size = sizeof(VirtIOBalloonPCI), .instance_init = virtio_balloon_pci_instance_init, .class_init = virtio_balloon_pci_class_init, }; static void virtio_balloon_pci_register(void) { virtio_pci_types_register(&virtio_balloon_pci_info); } type_init(virtio_balloon_pci_register)
- virtual scsi设备
virtual scsi设备的定义如下(hw/virtio/virtio-scsi.c中):
static const TypeInfo virtio_scsi_info = {
.name = TYPE_VIRTIO_SCSI,
.parent = TYPE_VIRTIO_SCSI_COMMON,
.instance_size = sizeof(VirtIOSCSI),
.class_init = virtio_scsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
static void virtio_register_types(void)
{
type_register_static(&virtio_scsi_common_info);
type_register_static(&virtio_scsi_info);
}
type_init(virtio_register_types)
关联:
- virtio scsi PCI设备
virtio scsi PCI设备的定义在hw/virtio/virtio-scsi-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { .base_name = TYPE_VIRTIO_SCSI_PCI, .generic_name = "virtio-scsi-pci", .transitional_name = "virtio-scsi-pci-transitional", .non_transitional_name = "virtio-scsi-pci-non-transitional", .instance_size = sizeof(VirtIOSCSIPCI), .instance_init = virtio_scsi_pci_instance_init, .class_init = virtio_scsi_pci_class_init, }; static void virtio_scsi_pci_register(void) { virtio_pci_types_register(&virtio_scsi_pci_info); } type_init(virtio_scsi_pci_register)
- virtual crypto设备
virtual crypto设备的定义如下(hw/virtio/virtio-crypto.c中):
static const TypeInfo virtio_crypto_info = {
.name = TYPE_VIRTIO_CRYPTO,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOCrypto),
.instance_init = virtio_crypto_instance_init,
.class_init = virtio_crypto_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_crypto_info);
}
type_init(virtio_register_types)
关联:
- virtio crypto PCI设备
virtio crypto PCI设备的定义在hw/virtio/virtio-crypto-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_crypto_pci_info = { .generic_name = TYPE_VIRTIO_CRYPTO_PCI, .instance_size = sizeof(VirtIOCryptoPCI), .instance_init = virtio_crypto_initfn, .class_init = virtio_crypto_pci_class_init, }; static void virtio_crypto_pci_register_types(void) { virtio_pci_types_register(&virtio_crypto_pci_info); } type_init(virtio_crypto_pci_register_types)
上边各设备(包括上一回的virtio PCI代理设备)都使用了TypeInfo,该结构的定义在include/qom/object.h中,代码如下:
/**
* struct TypeInfo:
* @name: The name of the type.
* @parent: The name of the parent type.
* @instance_size: The size of the object (derivative of #Object). If
* @instance_size is 0, then the size of the object will be the size of the
* parent object.
* @instance_align: The required alignment of the object. If @instance_align
* is 0, then normal malloc alignment is sufficient; if non-zero, then we
* must use qemu_memalign for allocation.
* @instance_init: This function is called to initialize an object. The parent
* class will have already been initialized so the type is only responsible
* for initializing its own members.
* @instance_post_init: This function is called to finish initialization of
* an object, after all @instance_init functions were called.
* @instance_finalize: This function is called during object destruction. This
* is called before the parent @instance_finalize function has been called.
* An object should only free the members that are unique to its type in this
* function.
* @abstract: If this field is true, then the class is considered abstract and
* cannot be directly instantiated.
* @class_size: The size of the class object (derivative of #ObjectClass)
* for this object. If @class_size is 0, then the size of the class will be
* assumed to be the size of the parent class. This allows a type to avoid
* implementing an explicit class type if they are not adding additional
* virtual functions.
* @class_init: This function is called after all parent class initialization
* has occurred to allow a class to set its default virtual method pointers.
* This is also the function to use to override virtual methods from a parent
* class.
* @class_base_init: This function is called for all base classes after all
* parent class initialization has occurred, but before the class itself
* is initialized. This is the function to use to undo the effects of
* memcpy from the parent class to the descendants.
* @class_data: Data to pass to the @class_init,
* @class_base_init. This can be useful when building dynamic
* classes.
* @interfaces: The list of interfaces associated with this type. This
* should point to a static array that's terminated with a zero filled
* element.
*/
struct TypeInfo
{
const char *name;
const char *parent;
size_t instance_size;
size_t instance_align;
void (*instance_init)(Object *obj);
void (*instance_post_init)(Object *obj);
void (*instance_finalize)(Object *obj);
bool abstract;
size_t class_size;
void (*class_init)(ObjectClass *klass, void *data);
void (*class_base_init)(ObjectClass *klass, void *data);
void *class_data;
InterfaceInfo *interfaces;
};
以virtio balloon设备为例。为了便于理解,再次贴出源码,分别在hw/virtio/virtio-balloon-pci.c和hw/virtio/virtio-balloon.c中,如下:
static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
.base_name = TYPE_VIRTIO_BALLOON_PCI,
.generic_name = "virtio-balloon-pci",
.transitional_name = "virtio-balloon-pci-transitional",
.non_transitional_name = "virtio-balloon-pci-non-transitional",
.instance_size = sizeof(VirtIOBalloonPCI),
.instance_init = virtio_balloon_pci_instance_init,
.class_init = virtio_balloon_pci_class_init,
};
static void virtio_balloon_pci_register(void)
{
virtio_pci_types_register(&virtio_balloon_pci_info);
}
type_init(virtio_balloon_pci_register)
static const TypeInfo virtio_balloon_info = {
.name = TYPE_VIRTIO_BALLOON,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBalloon),
.instance_init = virtio_balloon_instance_init,
.class_init = virtio_balloon_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_balloon_info);
}
type_init(virtio_register_types)
VirtIOBalloonPCI的定义在hw/virtio/virtio-balloon-pci.c中,如下:
typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
struct VirtIOBalloonPCI的定义也在hw/virtio/virtio-balloon-pci.c中,如下:
struct VirtIOBalloonPCI {
VirtIOPCIProxy parent_obj;
VirtIOBalloon vdev;
};
VirtIOPCIProxy的定义在include/hw/virtio/virtio-pci.h中,如下:
/*
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
*/
#define TYPE_VIRTIO_PCI "virtio-pci"
OBJECT_DECLARE_TYPE(VirtIOPCIProxy, VirtioPCIClass, VIRTIO_PCI)
struct VirtIOPCIProxy的定义也在include/hw/virtio/virtio-pci.h中,如下:
struct VirtIOPCIProxy {
PCIDevice pci_dev;
MemoryRegion bar;
union {
struct {
VirtIOPCIRegion common;
VirtIOPCIRegion isr;
VirtIOPCIRegion device;
VirtIOPCIRegion notify;
VirtIOPCIRegion notify_pio;
};
VirtIOPCIRegion regs[5];
};
MemoryRegion modern_bar;
MemoryRegion io_bar;
uint32_t legacy_io_bar_idx;
uint32_t msix_bar_idx;
uint32_t modern_io_bar_idx;
uint32_t modern_mem_bar_idx;
int config_cap;
uint32_t flags;
bool disable_modern;
bool ignore_backend_features;
OnOffAuto disable_legacy;
/* Transitional device id */
uint16_t trans_devid;
uint32_t class_code;
uint32_t nvectors;
uint32_t dfselect;
uint32_t gfselect;
uint32_t guest_features[2];
VirtIOPCIQueue vqs[VIRTIO_QUEUE_MAX];
VirtIOIRQFD *vector_irqfd;
int nvqs_with_notifiers;
VirtioBusState bus;
};
VirtIOBalloon的定义在include/hw/virtio/virtio-balloon.h中,如下:
#define TYPE_VIRTIO_BALLOON "virtio-balloon-device"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBalloon, VIRTIO_BALLOON)
struct VirtIOBalloon的定义也在include/hw/virtio/virtio-balloon.h中,如下:
struct VirtIOBalloon {
VirtIODevice parent_obj;
VirtQueue *ivq, *dvq, *svq, *free_page_vq, *reporting_vq;
uint32_t free_page_hint_status;
uint32_t num_pages;
uint32_t actual;
uint32_t free_page_hint_cmd_id;
uint64_t stats[VIRTIO_BALLOON_S_NR];
VirtQueueElement *stats_vq_elem;
size_t stats_vq_offset;
QEMUTimer *stats_timer;
IOThread *iothread;
QEMUBH *free_page_bh;
/*
* Lock to synchronize threads to access the free page reporting related
* fields (e.g. free_page_hint_status).
*/
QemuMutex free_page_lock;
QemuCond free_page_cond;
/*
* Set to block iothread to continue reading free page hints as the VM is
* stopped.
*/
bool block_iothread;
NotifierWithReturn free_page_hint_notify;
int64_t stats_last_update;
int64_t stats_poll_interval;
uint32_t host_features;
bool qemu_4_0_config_size;
uint32_t poison_val;
};
virtio balloon设备的实例对象为VirtIOBalloon。具体的virtio设备、virtio PCI代理设备、virtio公共设备的关系如下图所示:
上图显示了virtio balloon设备对应的几个数据结构及其关系。VirtIOBalloonPCI是virtio balloon PCI代理设备的实例对象,其中包括两个部分:一个是VirtIOPCIProxy,这是virtio PCI代理设备的通用结构,里边存放了具体virtio PCI代理设备的相关成员;另一个是VirtIOBalloon,此结构中存放的是virtio balloon设备的相关数据。其第一个成员是VirtIODevice,也即virtio公共设备的实例对象。VirtIOBalloon剩下的成员是与virtio balloon设备相关的数据。
欲知后事如何,且看下回分解。