5.3 KiB
[Draft] Virtio
1、基本概念
Virtio 是一种标准虚拟化技术,virtio 设备能够像普通设备那样被 Guest 系统枚举和使用。Virtio 设备具备以下特点:
- 简单易开发:virtio 设备使用通用的中断和 DMA 机制,对于设备驱动开发者来说不会带来困难。
- 高效:virtio 设备使用针对输入和输出使用不同的 vring,规避了可能的由高速缓存带来的影响。
- 标准:virtio 不假定其所处的环境。
- 可扩展:virtio 设备包含一组 Feature Bits,在设备安装过程中,可以告知 guest OS。设备和驱动之间相互协调,驱动可以根据设备提供的特性以及驱动自身能够支持的特性来最终确定在 guest OS 里面能够使用的设备特性。这样可以顾及到设备的前后兼容性。
每个 virtio 设备由以下 4 部分构成:
- 设备状态域(Device status field)
- 特征位(Feature bits)
- 设备配置空间(Device Configuration space)
- 一个或多个 Virtqueues
1.1 设备状态域
https://www.ibm.com/developerworks/cn/linux/1402_caobb_virtio/
https://www.ibm.com/developerworks/cn/linux/l-virtio/index.html
2、系统结构
3、Virtio 设备
3.1、Virtio 设备类型
主要分为 PCI 设备和非 PCI 的 mmio 设备。mmio 设备属于 Platform 设备,通过向 kernel 提供
virtio_mmio.device=<size>@<baseaddr>:<irq>[:<id>]
启动参数来让内核感知到设备存在,其中:
<size> := size (can use standard suffixes like K, M and G)
<baseaddr> := physical base address
<irq> := interrupt number (as passed to request_irq())
<id> := (optional) platform device id
使用 virtio mmio 内核参数的示例如下:
virtio_mmio.device=1K@0x100b0000:48:7
可以多次使用该内核参数来指定不同的 virtio mmio 设备。
非 mmio 设备有 Legacy 和 Modern 两种类型,这两种类型设备是通过 PCI 总线枚举而感知到虚拟设备存在的。如果在加载 virtio pci 设备模块时强制使用 Legacy 设备,则优先按 Legacy 设备进行加载,如果加载失败则按 Modern 设备加载。否则优先使用 Modern 设备加载。
Legacy 设备使用 CONFIGURATION ADDRESS(0xCF8) 和 CONFIGURATION DATA PORT(0xCFC)来进行设备访问(CAM);Modern 设备使用 ENHANCED 方式进行设备访问(ECAM)。参见《PCI_Configuration_Register_Access》。
其他还有 virtio vop 设备和 virtio ccw 设备,vop 设备指 Intel Virtio Over PCIe (VOP) driver;ccw 指 Concurrent I/O (CIO) 设备。virtio vop 和 virtio ccw 是分别属于这两种类型的 virtio 设备。
3.2、Virtio 设备 ID
virtio 设备的 Vendor ID 为 0x1AF4,Subsystem device ID 如下:
Subsystem Device ID | Virtio Device |
---|---|
1 | Network card |
2 | Block device |
3 | Console |
4 | Entropy source |
5 | Memory ballooning |
6 | IoMemory |
7 | Rpmsg |
8 | SCSI host |
9 | 9P transport |
10 | Mac80211 wlan |
3.3、Virtio 设备的配置空间
需要使用 PCI 设备的第一块 I/O region 来对 PCI 设备进行配置。针对 virtio 设备来说,在 device 特定的配置区域后会有一块区域存放 virtio header(下表)。
Virtio PCI 配置空间如下:
struct _VIRTIO_PCI_CFG
{
u16 VendorID; // 0x000
u16 DeviceID;
union
{
u32 StatusAndCommand;
struct
{
u32 PortEnable:1; // bit 0
u32 MemorySpaceEnable:1; // bit 1
u32 BusMasterEnable:1; // bit 2
u32 Reserved1:5; // bit 3-7
u32 SERREnable:1; // bit 8
u32 Reserved2:1; // bit 9
u32 InterruptDisable:1; // bit 10
u32 Reserved3:8; // bit 11-18
u32 InterruptStatus:1; // bit 19
u32 CapabilitiesList:1; // bit 20
u32 Reserved4:6; // bit 21-26
u32 STA:1; // bit 27
u32 ReceivedTargetAbort:1; // bit 28
u32 ReceivedMasterAbort:1; // bit 29
u32 SSE:1; // bit 30
u32 Reserved5:1; // bit 31
}
} // 0x004
u8 RevisionID; // 0x008
u8 PROGIF;
u8 SubClassID;
u8 ClassID;
u8 CacheLineSize; // 0x00C
u8 LatencyTimer;
struct
{
u8 HeaderType:7;
u8 MultiFunctionDevice:1
}
u8 Reserved6;
u32 Bar0; // 0x010
u32 Bar1; // 0x014
// 0x028
u16 SubVendorID0; // 0x02C
u16 SubDeviceID0;
// 0x030
u32 CapabilitiesPointer; // 0x034
u8 InterruptRegister; // 0x03C
u8 InterruptPin;
u8 MinGnt;
u8 MaxLat;
// 0x040
}VIRTIO_PCI_CFG;