2.1.3节提到在多虚拟机环境下,可以通过虚拟机下陷将物理中断转换为虚拟中断,解决物理中断的路由问题。在此过程中,Hypervisor通过虚拟中断控制器模拟真实环境下中断的分发和传送,完成虚拟中断的注入,因此在介绍中断虚拟化之前有必要先了解物理中断控制器及其工作方式。本节将简要介绍Intel x86架构下的两种中断控制器——PIC(Programmable Interrupt Controller,可编程中断控制器)和APIC(Advanced Programmable Interrupt Controller,高级可编程中断控制器)及它们各自的中断处理流程。
PIC,即Intel 8259A芯片,是单处理器(Uni-processor)时代广泛使用的中断控制器。它主要包含8个中断引脚IR0~IR7,用于连接外部设备以及三个内部寄存器:IMR(Interrupt Mask Register,中断屏蔽寄存器)、IRR(Interrupt Request Register,中断请求寄存器)和ISR(Interrupt Service Register,中断服务寄存器)。
(1)IMR:共8位,对应于IR0~IR7,置1表示相应引脚中断被屏蔽。
(2)IRR:共8位,对应于IR0~IR7,置1表示收到相应引脚的中断信号。
(3)ISR:共8位,对应于IR0~IR7,置1表示收到相应引脚的中断信号正在被CPU处理。
其中IR0~IR7用于连接外部设备,连接到不同的中断引脚对应的中断优先级不同,其中IR0优先级最高,IR7优先级最低。每当外设需要发送中断时,便会拉高相连中断引脚的电平;若相关中断未被屏蔽,就设置IRR中相应位并拉高INT引脚电平通知CPU有中断到达;CPU给INTA引脚发送一个脉冲确认收到中断,8259A芯片收到上述INTA脉冲信号后,将IRR最高优先级位清零并将ISR对应位置1;而后CPU发送第二次脉冲,8259A芯片收到后将最高优先级的中断向量号发送给到数据线上,CPU接收中断向量号并执行相应的中断服务例程;处理完成后,CPU向8259A的命令寄存器写入指定值并发送一个EOI(End of Interrupt,中断结束)信号;8259A芯片收到EOI后,将ISR中的最高优先级位清零。根据上述描述,8259A芯片最多支持8个中断源,而为了支持更多的外设,通常将若干个8259A芯片级联,最多可以支持64个中断。
APIC是20世纪90年代Intel公司为了应对多处理器(Multi-Processor)架构提出的一整套中断处理方案,用于取代老旧的8259A PIC。APIC适用于多处理器机器,每个CPU拥有一个LAPIC(Local APIC,本地APIC),整个机器拥有一个或多个IOAPIC(I/O APIC,输入/输出APIC),设备的中断信号先经由IOAPIC汇总,再分发给一个或多个CPU的LAPIC。LAPIC中也存在IRR和ISR以及EOI寄存器,IRR和ISR的功能与PIC中相应寄存器类似,大小为256位,对应x86平台下的256个中断向量号。在APIC中断架构下,LAPIC的中断来源可分为以下3类:
(1)本地中断。本地中断包括LINT0和LINT1引脚接收的中断、APIC Timer产生的中断、性能计数器产生的中断、温度传感器产生的中断以及APIC内部错误引发的中断。
(2)通过IOAPIC接收的外部中断。当I/O设备通过IOAPIC中断引脚产生中断信号时,IOAPIC从内部的PRT(Programmable Redirection Table,可编程重定向表)中找到相应的RTE(Redirection Table Entry,重定向表项)。PRT共有24条PTE,与IOAPIC的24个中断引脚对应,每条PTE长度为64位。IOAPIC根据PTE中存储的信息(如触发方式、中断向量号、目的处理器等)格式化出一条中断消息发送到系统总线上。在PIC中,中断优先级由所连接的8259A芯片引脚决定,而在APIC中,中断优先级由中断向量号(也称为vector)决定,范围为0~255,ISR和IRR每位对应一个中断向量号,置1表示收到该中断向量号的中断。中断向量号越大,中断优先级越高。IRR和ISR的最大中断向量号记为IRRV和ISRV。
(3)处理器间中断(IPI)。CPU可以通过写入APIC的ICR(Interrupt Control Register,中断控制寄存器)发送一条IPI消息到系统总线上,从而发送给CPU。
LAPIC收到中断消息后,确认自己是否是中断消息的目标,如果是,则对该中断消息进一步处理,这一步称为 中断路由 (Interrupt Routing)。LAPIC接收中断消息后,处理过程如下:
(1)如果收到的中断是NMI、SMI、INIT、ExtINT或SIPI,则直接交给CPU处理,否则设置IRR寄存器中适当的位,将中断加入等待队列,这一步称为 中断接受 (Interrupt Acceptance)。
(2)对于在IRR中阻塞的中断,APIC取出其中优先级最高的中断(要求IRRV[7∶4]>PPR [7∶4])交给CPU处理,并根据中断向量号设置ISR寄存器中相应的位。这一步称为 中断确认 (Interrupt Acknowledgement)。
(3)CPU通过中断向量号索引IDT(Interrupt Descriptor Table,中断描述符表)执行相应的中断处理例程,这一步称为 中断交付 (Interrupt Delivery)。
(4)中断处理例程执行完毕时,应写入EOI寄存器,使得APIC从ISR队列中删除中断对应的项,结束该中断的处理(NMI、SMI、INIT、ExtINT及SIPI不需要写入EOI)。
MSI(Message Signaled Interrupt,消息告知中断)是PCI总线发展出的新型中断传送方式,它允许设备直接发送中断到LAPIC而无须经过IOAPIC。MSI本质上就是在中断发生时,不通过带外(out-band)的中断信号线,而是通过带内(in-band)的PCI写入事务来通知LAPIC中断的发生。从原理上来说,MSI产生的事务与一般的DMA事务并无本质区别,需要依赖特定平台的特殊机制从总线事务中区分出MSI并赋予其中断的语义。在x86平台上,是由Host Bridge/Root Complex负责这一职责,将MSI事务翻译成系统上的中断消息,但凡目标地址落在[0xfee00000,0xfeefffff]的写入事务都会被视为MSI中断请求并翻译成中断消息。一个MSI事务由地址和数据构成,每个设备可以配置其发生中断时产生MSI事务的地址和数据,并且可以在不同事件发生时产生不同的MSI事务(即不同的地址-数据对)。MSI中断消息到达LAPIC后的处理流程与上述过程一致。
在正式介绍中断虚拟化之前,还需要介绍几个重要的概念:IRQ(Interrupt Request,中断请求)、GSI(Global System Interrupt,全局系统中断号)、Vector(中断向量号)和Pin(中断引脚号) 。这几个概念在后续章节将会反复提及,故在此进行区分。
(1)IRQ: IRQ是PIC时代的产物,但是如今可能还会见到IRQ线或者IRQ号等各种说法。在PIC中断架构下,通常将两块8259A芯片级联,支持16个中断,由于ISA设备通常连接到固定的8259A中断引脚,因此设备的IRQ号通常是指它所连接的8259A引脚号。如前所述,8259A有8个中断引脚(IR0~IR7),那么连接到这些主8259A芯片IR0~IR7引脚的设备中断号分别对应IRQ0~IRQ7,连接到从8259A芯片IR0~IR7引脚的设备对应的中断号为IRQ8~IRQ15。而IRQ线可以理解为设备与这些引脚的连线,命名方式通常也为IRQx,它们通常与中断控制器引脚一一对应,故使用IRQ时应当注意相应的情境。
(2)GSI: GSI是ACPI(Advanced Configuration and Power Interface,高级配置和电源管理接口)引入的概念,它为系统中每个中断控制器的输入引脚指定了一个全局统一的编号。例如系统中有多个IOAPIC,每个IOAPIC都会被BIOS分配一个基础GSI(GSI Base),每个IOAPIC中断引脚对应的GSI为基础GSI+Pin。比如IOAPIC 0的基础GSI为0,有24个引脚,则它们分别对应GSI0~GSI23。在APIC系统中,IRQ和GSI通常会被混用,15号以上的IRQ号与GSI相等;而15号以下的IRQ号与ISA设备高度耦合,只有当相应的ISA设备按照对应的IRQ号连接到IOAPIC 0的1~15引脚时,IRQ才和GSI相等,这种情况称为一致性映射。而若IRQ与GSI引脚不一一对应,ACPI将会维护一个ISO(Interrupt Source Override,中断源覆盖)结构描述IRQ与GSI的映射。如PIT(Programmable Interrupt Timer,可编程中断时钟)接PIC的IR0引脚,因此其IRQ为0;但当接IOAPIC时,它通常接在2号中断引脚,所以其GSI为2。而在QEMU/KVM中,GSI和IRQ完全等价,但是不符合前述基础GSI+Pin的映射关系。
(3)Vector: 中断向量号是操作系统中的概念,是中断在IDT中的索引。每个GSI都对应一个Vector,它们的映射关系由操作系统决定。x86中通常包含256个中断向量号,0~31号中断向量号是x86预定义的,32~255号则由软件定义。
(4)Pin: 中断控制器的中断引脚号,对于8259A而言,其Pin取值为0~7;对于IOAPIC,其Pin取值为0~23。
根据以上描述,IRQ、GSI和Vector都可以唯一标识系统中的中断来源,IRQ和GSI的映射关系以及GSI和Pin的映射关系由ACPI设置,IRQ和Vector的映射关系由操作系统设置。