接前一篇文章:
本文内容参考:
《 QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
上两回对于virtio进行了简介,并说明了其基本原理以及框架。本回开始正式结合代码讲解virtio的实现机制和细节。
virtio设备的初始化
virtio设备 首先需要创建一个PCI设备 ,叫作 virtio PCI代理设备 ,这个代理设备 挂到PCI总线上 。
接着, virtio代理设备再创建一条virtio总线 ,这样 virtio设备就可以挂到这条virtio总线上了 。
首先来看virtio PCI代理设备类型的定义,在QEMU源码(qemu-8.1.3)的hw/virtio/virtio-pci.c中,代码如下:
static const TypeInfo virtio_pci_info = {
.name = TYPE_VIRTIO_PCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VirtIOPCIProxy),
.class_init = virtio_pci_class_init,
.class_size = sizeof(VirtioPCIClass),
.abstract = true,
};
……
static const TypeInfo virtio_pci_bus_info = {
.name = TYPE_VIRTIO_PCI_BUS,
.parent = TYPE_VIRTIO_BUS,
.instance_size = sizeof(VirtioPCIBusState),
.class_size = sizeof(VirtioPCIBusClass),
.class_init = virtio_pci_bus_class_init,
};
static void virtio_pci_register_types(void)
{
/* Base types: */
type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_info);
}
type_init(virtio_pci_register_types)
这里给出以上几个宏的定义:
- TYPE_VIRTIO_PCI
TYPE_VIRTIO_PCI的定义在include/hw/virtio/virtio-pci.h中,如下:
/*
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
*/
#define TYPE_VIRTIO_PCI "virtio-pci"
- TYPE_PCI_DEVICE
TYPE_PCI_DEVICE的定义在include/hw/pci/pci_device.h中,如下:
#define TYPE_PCI_DEVICE "pci-device"
- TYPE_VIRTIO_PCI_BUS
TYPE_VIRTIO_PCI_BUS的定义在include/hw/virtio/virtio-pci.h中,如下:
#define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus"
- TYPE_VIRTIO_BUS
TYPE_VIRTIO_BUS的定义在include/hw/virtio/virtio-bus.h中,如下:
#define TYPE_VIRTIO_BUS "virtio-bus"
从virtio PCI代理设备的定义就可以看出,virtio PCI代理设备的 父设备是一个PCI设备 (.parent = TYPE_PCI_DEVICE,), 类型为VirtIOPCIClass (.class_size = sizeof(VirtioPCIClass),), 实例为virtIOPCIProxy (.instance_size = sizeof(VirtIOPCIProxy),),注意这是一个 抽象设备 (.abstract = true,),因此并 不能创建其实例,只能由其子类去创建 。
QEMU中定义了所有virtio设备的PCI代理设备,如virtio balloon PCI设备、virtio scsi PCI设备、virtio crypto PCI设备等。各代理设备的定义分别如下所示:
- 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)
- 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)
- 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 block PCI设备
virtio block PCI设备的定义在hw/virtio/virtio-blk-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = {
.base_name = TYPE_VIRTIO_BLK_PCI,
.generic_name = "virtio-blk-pci",
.transitional_name = "virtio-blk-pci-transitional",
.non_transitional_name = "virtio-blk-pci-non-transitional",
.instance_size = sizeof(VirtIOBlkPCI),
.instance_init = virtio_blk_pci_instance_init,
.class_init = virtio_blk_pci_class_init,
};
static void virtio_blk_pci_register(void)
{
virtio_pci_types_register(&virtio_blk_pci_info);
}
type_init(virtio_blk_pci_register)
- virtio net PCI设备
virtio net PCI设备的定义在hw/virtio/virtio-net-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = {
.base_name = TYPE_VIRTIO_NET_PCI,
.generic_name = "virtio-net-pci",
.transitional_name = "virtio-net-pci-transitional",
.non_transitional_name = "virtio-net-pci-non-transitional",
.instance_size = sizeof(VirtIONetPCI),
.instance_init = virtio_net_pci_instance_init,
.class_init = virtio_net_pci_class_init,
};
static void virtio_net_pci_register(void)
{
virtio_pci_types_register(&virtio_net_pci_info);
}
type_init(virtio_net_pci_register)
- virtio serial PCI设备
virtio serial PCI设备的定义在hw/virtio/virtio-serial-pci.c中,代码如下:
static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = {
.base_name = TYPE_VIRTIO_SERIAL_PCI,
.generic_name = "virtio-serial-pci",
.transitional_name = "virtio-serial-pci-transitional",
.non_transitional_name = "virtio-serial-pci-non-transitional",
.instance_size = sizeof(VirtIOSerialPCI),
.instance_init = virtio_serial_pci_instance_init,
.class_init = virtio_serial_pci_class_init,
};
static void virtio_serial_pci_register(void)
{
virtio_pci_types_register(&virtio_serial_pci_info);
}
type_init(virtio_serial_pci_register)
- virtio input PCI设备
(各种)virtio input PCI设备的定义在hw/virtio/virtio-input-pci.c中,代码如下:
static const TypeInfo virtio_input_pci_info = {
.name = TYPE_VIRTIO_INPUT_PCI,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(VirtIOInputPCI),
.class_init = virtio_input_pci_class_init,
.abstract = true,
};
static const TypeInfo virtio_input_hid_pci_info = {
.name = TYPE_VIRTIO_INPUT_HID_PCI,
.parent = TYPE_VIRTIO_INPUT_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.abstract = true,
};
static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = {
.generic_name = TYPE_VIRTIO_KEYBOARD_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_kbd_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_keyboard_initfn,
};
static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = {
.generic_name = TYPE_VIRTIO_MOUSE_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_mouse_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_mouse_initfn,
};
static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = {
.generic_name = TYPE_VIRTIO_TABLET_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_tablet_initfn,
};
static const VirtioPCIDeviceTypeInfo virtio_multitouch_pci_info = {
.generic_name = TYPE_VIRTIO_MULTITOUCH_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_multitouch_initfn,
};
static void virtio_pci_input_register(void)
{
/* Base types: */
type_register_static(&virtio_input_pci_info);
type_register_static(&virtio_input_hid_pci_info);
/* Implementations: */
virtio_pci_types_register(&virtio_keyboard_pci_info);
virtio_pci_types_register(&virtio_mouse_pci_info);
virtio_pci_types_register(&virtio_tablet_pci_info);
virtio_pci_types_register(&virtio_multitouch_pci_info);
}
type_init(virtio_pci_input_register)
上边各virtio代理设备都使用了VirtioPCIDeviceTypeInfo,该结构的定义在include/hw/virtio/virtio-pci.h中,代码如下:
/* Input for virtio_pci_types_register() */
typedef struct VirtioPCIDeviceTypeInfo {
/*
* Common base class for the subclasses below.
*
* Required only if transitional_name or non_transitional_name is set.
*
* We need a separate base type instead of making all types
* inherit from generic_name for two reasons:
* 1) generic_name implements INTERFACE_PCIE_DEVICE, but
* transitional_name does not.
* 2) generic_name has the "disable-legacy" and "disable-modern"
* properties, transitional_name and non_transitional name don't.
*/
const char *base_name;
/*
* Generic device type. Optional.
*
* Supports both transitional and non-transitional modes,
* using the disable-legacy and disable-modern properties.
* If disable-legacy=auto, (non-)transitional mode is selected
* depending on the bus where the device is plugged.
*
* Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE,
* but PCI Express is supported only in non-transitional mode.
*
* The only type implemented by QEMU 3.1 and older.
*/
const char *generic_name;
/*
* The transitional device type. Optional.
*
* Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE.
*/
const char *transitional_name;
/*
* The non-transitional device type. Optional.
*
* Implements INTERFACE_CONVENTIONAL_PCI_DEVICE only.
*/
const char *non_transitional_name;
/* Parent type. If NULL, TYPE_VIRTIO_PCI is used */
const char *parent;
/* Same as TypeInfo fields: */
size_t instance_size;
size_t class_size;
void (*instance_init)(Object *obj);
void (*instance_finalize)(Object *obj);
void (*class_init)(ObjectClass *klass, void *data);
InterfaceInfo *interfaces;
} VirtioPCIDeviceTypeInfo;
virtio设备在系统的设备树中的位置如下图所示:
欲知后事如何,请看下回分解。