## 设备直通和非设备直通

### 流程对比

+ 非直通虚拟网卡

1. 虚拟机驱动准备DMA缓冲区

+ 虚拟机内的网络驱动准备发送数据包,分配一块内存缓冲区,地址为**客户机物理地址(GPA)**(例GPA 0x1000

2. 驱动触发虚拟设备操作

+ 驱动将GPA 0x1000写入虚拟网卡的DMA地址寄存器(通过MMIO操作)。

+ 虚拟机内的CPU执行MMIO写指令,目标地址为虚拟网卡的寄存器(GPA 0xA000

3. EPT转换MMIO地址

+ CPU访问MMIO地0xA000时,**EPT(Extended Page Tables)**将其转换为宿主机的物理地址(HPA 0x5000),定位到QEMU模拟的虚拟网卡寄存器。

4. QEMU截获DMA请求

+ QEMU模拟的虚拟网卡接收到DMA配置(目标地址为GPA 0x1000),触发模拟的DMA传输流程。

+ QEMU通过**EPT页表**将GPA 0x1000转换为宿主机的HPA(例HPA 0x8000)。

5. 宿主机驱动发起真实DMA

+ QEMU调用宿主机内核的DMA API(dma_map_single()),使用转换后的HPA 0x8000配置物理网卡的DMA引擎。

+ 物理网卡直接从HPA 0x8000读取数据并发送到网络。

6. 传输完成与中断通知

+ 物理网卡完成数据传输后,通过中断通知宿主机驱动。

+ QEMU模拟虚拟中断,通知虚拟机驱动数据已发送。

+ 直通GPU(PCI Passthrough)

1. 虚拟机驱动准备渲染数据

+ 虚拟机内的GPU驱动分配显存缓冲区,地址为GPA(例GPA 0x2000)。

2. 驱动配置GPU DMA

+ 驱动将GPA 0x2000写入直通GPU的DMA地址寄存器(通过MMIO操作)。

+ CPU执行MMIO写指令,目标地址为GPU的物理寄存器(GPA 0xB000)。

3. EPT转换MMIO地址

+ EPT将GPA 0xB000转换为GPU寄存器的真实HPA(例HPA 0x6000),确保CPU直接操作物理硬件。

4. GPU发起DMA请求

+ GPU根据驱动配置的GPA 0x2000,发起DMA传输请求(例如将渲染数据从内存传输到显存)。

5. IOMMU拦截并转换地址

+ IOMMU拦截DMA请求,查询其页表,将GPA 0x2000转换为宿主机的HPA 0x9000

+ 若IOMMU与EPT共享页表,可能直接复用EPT的GPA→HPA映射。

6. DMA访问物理显存

+ GPU直接读写HPA 0x9000对应的物理显存,完成数据传输。

7. 渲染完成与中断通知

+ GPU触发中断,宿主机将中断路由到虚拟机(需中断重映射支持),通知驱动渲染完成。