小谈虚拟化中的中断演进

目的

本文主要跟踪Linux kerenl中断系统虚拟化方向的演进,
希望能尽量用少的篇幅把整个虚拟化中断说清楚。

读者

本文假设读者已有linux中断的编程经验,熟悉ARM GIC的基本概念和工作原理。

总述

QEMU/KVM中,设备虚拟化有3种方法:纯软件模拟,virtio虚拟和SRIOV物理分配。
本文先集中解析virtio pci虚拟设备的中断,后续再补充SRIOV设备的中断,
不讨论纯软件模拟设备的中断过程。其中1到4章节简单介绍下虚拟化和virtio,
如果只想了解中断部分,可以从第5章节开始。

QEMU/KVM软件堆栈和virtio简介

在介绍中断细节前先介绍下整个系统的组成,再以网络收发包为例介绍中断细节。

QEMU/KVM软件堆栈

系统的部署图如下图:

QEMU/KVM系统图

QEMU中组件关系如下图:

QEMU/KVM组成图

  • QEMU Core: 模拟外设、虚拟硬件平台,实现前端设备模拟
  • Event Loop:监听后端fd,一旦fd收到event即调用回调函数
  • vCPU Thread: 执行guest代码的
  • Worker Thread:执行阻塞代码,完成时通知Event Loop

VirtIO关键数据结构关系

VirtIO在guest kernel模拟设备驱动,在qemu中模拟设备。
数据通道上借助内存映射做到guest和host的0内存拷贝通信;
中断方面通过中断注入或者中断透传实现。

VirtIO关键数据结构图

其中virtqueue_ops结构体在2.6内核之后已经被去掉,直接使用函数代替;代码位置请以最新内核为准。
vring_virtqueue封装了vring和vritqueue,vring是底层的物理内存实现。
已知virtqueue的话,可以通过container_of找到vring_virtqueue.

VirtIO设备和外界数据交互

交互的流程图如下:

VirtIO设备和外界数据交互图

  1. 虚拟机中,VirtIO设备驱动通过virtqueue的add_buf函数,把request写入到virtqueue中;
  2. 虚拟机中,VirtIO设备驱动通过virtqueue的kick函数写eventfd(vp_notify),该eventfd会和某块内存绑定;
  3. host中的QEMU Event Loop监听到该eventfd的signal,执行eventfd的回调函数;
  4. host中回调函数把虚拟机中的request数据转发给真实物理设备;
  5. host把真实物理设备response数据通过virtqueue的get_buf写入到virtqueue中;
  6. QEMU中irqfd接口收到请求,调用回调函数,并通过写内存地址产生中断上报给虚拟机(irqfd的底层实现是eventfd,QEMU中虚拟机初始化的时候,会给这个eventfd挂回调函数);
  7. 虚拟机中的vgic代码产生vIRQ把上报给GICC;
  8. 虚拟机收到中断请求,处理response数据。

以virtio net为例,细节如下图:

###组件关系图:

virtio pci 组件关系图

发包流程:

virtio net tx流程图

收包流程:

virtio net tx流程图

GIC简介

软件主要控制GIC的GICD、GICR和GICC。

GIC编程接口图

ITS和GIC的关系如下,注意LPI可以不经过ITS直接发给GICR,非常重要,虚拟化的伏笔。
ITS编程接口图

GIC虚拟化也是分成GIC和ITS两部分。

  • GIC的模拟,并没有模拟全部的GIC部分,只是VGICC部分,当前是在host的kernel中virt/kvm/arm/vgic/vgic-vx.c中实现。
  • ITS的模拟,是使用纯软件模拟,当前是在host的kernel中virt/kvm/arm/vgic/vgic-its.c中。

GICv2时代的虚拟机中断处理机制

GICv2的硬件拓扑结构如下:

GICv2控制器架构图

GICv针对虚拟化的扩展图

GICv2中断虚拟化实现细节如下:

GICv2中断虚拟化处理流程图

GICv3时代的虚拟机中断处理机制

GICv3控制器架构图

GICv3中断处理流程图

GICv4时代的虚拟机中断处理机制

GICv4 VLPI直通流程图

MSI中断处理

PCIe设备中MSI 配置空间中保存ITS的地址,

  • QEMU中virtio PCI模拟该配置空间和能力
  • 虚拟机内核PCIe设备初始化的时候,向该配置空间写入ITS或者GICR地址。
  • host中QEMU通过向该PCIe设备配置地址写中断消息,从而虚拟机中产生msi中断。
知道是不会有人点的,但万一有人呢:)