Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 6: 虚拟中断处理和优先级

本章描述了GIC虚拟中断处理和优先级的基本方面:

  • 关于GIC虚拟化支持 .

  • 操作概述 .

  • VM的配置和控制 .

  • 伪代码 .

6.1 关于GIC虚拟化支持

在EL2执行的管理程序控制下在EL1执行的操作系统有时被称为_虚拟机_(VM)。VM可以支持多处理,这意味着多个由管理程序调度的_虚拟PE_(vPE)在一个或多个物理PE上执行。当vPE在PE上执行时,VM的该vPE被称为在物理PE上调度。

在Armv8中,当EL2被实现并启用时,CPU interface提供机制来最小化将中断路由到VM的管理程序开销。有关vPE的更多信息,请参阅_操作概述_。

有关EL2和虚拟中断的更多信息,请参阅_Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile_。

在GICv4中,对于直接注入的虚拟LPI,调度的vPE由GICR_VPENDBASER确定。有关更多信息,请参阅_门铃中断_。

注意 GIC不为GICD_*、GICR_*和GITS_*寄存器的虚拟化提供额外机制。要虚拟化VM对这些寄存器的访问,管理程序必须为这些内存位置设置stage 2 Data Abort,以便管理程序可以模拟这些效果。有关stage 2 Data Abort的更多信息,请参阅_Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile_。

当GIC提供虚拟化支持时,VM在具有以下特性的环境中操作:

  • vPE可以被配置为接收虚拟Group 0中断。

  • vPE可以被配置为接收虚拟Group 1中断。

  • 虚拟Group 0中断使用虚拟FIQ信号向非安全EL1发出信号。

  • 虚拟Group 1中断使用虚拟IRQ信号向非安全EL1发出信号。

  • vPE可以像处理物理中断一样处理虚拟中断。

注意

这适用于启用亲和性路由和System register访问的情况。有关传统操作中虚拟中断支持的信息,请参阅_VM传统操作的支持_。

EL2控制VM的虚拟中断生成。这允许在EL2执行的软件:

  • 为vPE生成虚拟Group 0和Group 1中断。

  • 保存和恢复vPE的中断状态。

  • 控制虚拟中断的优先级处理。

  • 更改调度的vPE。

GICv4引入了从ITS直接向vPE呈现虚拟LPI的能力,无需管理程序干预。

在传统操作中处理虚拟中断需要GICV_*内存映射接口。有关更多信息,请参阅_VM传统操作的支持_。

6.2 操作概述

GICv3支持Armv8-A虚拟化功能。在EL2执行的管理程序使用ICH_* System register接口来配置和控制在EL1执行的虚拟PE(vPE)。有关VM控制接口的信息,请参阅_VM的配置和控制_。vPE使用ICC_*_EL1 System register接口与GIC通信。HCR_EL2.{IMO, FMO}的配置决定了是访问虚拟还是物理接口寄存器。

注意 本章描述了在启用System register访问的AArch64状态上下文中虚拟中断的处理。本章中交叉引用的各个AArch64 System register描述包含对提供相同功能的AArch32 System register的引用。有关传统操作中VM的信息,请参阅_VM传统操作的支持_。

在EL3或EL2执行的软件配置PE将物理中断路由到EL2。中断可以是:

  • 针对vPE的中断。管理程序在目标vPE上将相应的虚拟INTID设置为挂起状态,并包含关于相关物理INTID的信息。当vPE未在PE上调度时,管理程序可能选择重新调度vPE。否则,中断在vPE上保持挂起,供管理程序稍后调度。

  • 针对管理程序的中断。此中断可能:

    • 由系统生成。

    • 是与调度的VM相关的维护中断。有关更多详细信息,请参阅_维护中断_。

    • 在GICv4中,是来自ITS的门铃中断。在GICv4中,可以在没有管理程序参与的情况下向vPE呈现虚拟中断。当为vPE设置虚拟中断挂起但vPE未在PE上调度时,必须生成门铃中断。

管理程序根据第4章_物理中断处理和优先级_中描述的规则处理物理中断,然后将其虚拟化。有关传统操作期间物理中断处理及其虚拟化的信息,请参阅第14章_传统操作和不对称配置_。

GIC虚拟化支持包括存储在硬件List寄存器中的vPE虚拟中断列表,请参阅_List寄存器的使用模型_。列表中的每个条目对应于挂起或活动中断,条目描述虚拟中断号、中断组、中断状态和中断的虚拟优先级。列表条目中描述的虚拟中断可以配置为与物理SPI或PPI关联。

GIC实现从List寄存器中保存的中断列表中选择最高优先级挂起虚拟中断,如果与活动虚拟中断和虚拟优先级掩码相比具有足够的虚拟优先级,则根据中断的组将其呈现为虚拟FIQ或虚拟IRQ。虚拟CPU interface控制以与物理中断控制应用于物理中断相同的方式应用于虚拟中断。因此,使用虚拟CPU interface控制,在vPE上执行的软件可以:

  • 设置虚拟优先级掩码。

  • 控制如何将虚拟优先级分割为组优先级和子优先级。

  • 确认虚拟中断。

  • 对虚拟中断执行优先级下降。

  • 去激活虚拟中断。

虚拟CPU interface支持两种EOImode,因此虚拟EOI可以单独执行优先级下降,或者组合优先级下降和去激活。

当虚拟中断被确认时,虚拟中断的状态在相应的List寄存器条目中从挂起变为活动。

当虚拟中断被去激活时,虚拟中断的状态在相应的List寄存器条目中从活动变为非活动,或从活动和挂起变为挂起。如果虚拟中断与物理中断关联,则相关的物理中断被去激活。

传递到EL1的虚拟中断以类似于在具有单一安全状态的系统中处理物理中断的方式处理,即GICD_CTLR.DS设置为1的情况:

  • Group 0中断使用虚拟FIQ信号发出信号。

  • Group 1中断使用虚拟IRQ信号发出信号。

  • Group 0和Group 1中断共享中断优先级处理和抢占方案。支持最少32级和最多256级优先级,由ICH_VTR_EL2中的值确定。

注意 优先级值不受用于非安全物理中断的移位影响。虽然虚拟化支持多达8位优先级,但必须实现最少5位和最多8位。

注意 有关Armv8-A PE上异常输入的管理规则的信息,请参阅_Arm[®] Architecture Reference Manual, Armv8, for Armv8-A architecture profile_。

在EL1对Group 0寄存器的访问在以下情况下是虚拟的:

  • 当前安全状态是非安全且HCR_EL2.FMO == 1。

  • 当前安全状态是安全,HCR_EL2.FMO == 1且SCR_EL3.EEL2 == 1。

对以下Group 0 ICC_*寄存器的虚拟访问访问ICV_*等价物:

  • 对ICC_AP0R_EL1的访问访问ICV_AP0R_EL1。

  • 对ICC_BPR0_EL1的访问访问ICV_BPR0_EL1。

  • 对ICC_EOIR0_EL1的访问访问ICV_EOIR0_EL1。

  • 对ICC_HPPIR0_EL1的访问访问ICV_HPPIR0_EL1。

  • 对ICC_IAR0_EL1的访问访问ICV_IAR0_EL1。

  • 对ICC_IGRPEN0_EL1的访问访问ICV_IGRPEN0_EL1。

在EL1对Group 1寄存器的访问在以下情况下是虚拟的:

  • 当前安全状态是非安全且HCR_EL2.IMO == 1。

  • 当前安全状态是安全,HCR_EL2.IMO == 1且SCR_EL3.EEL2 == 1。

对以下Group 1 ICC_*寄存器的虚拟访问访问ICV_*等价物:

  • 对ICC_AP1R_EL1的访问访问ICV_AP1R_EL1。

  • 对ICC_BPR1_EL1的访问访问ICV_BPR1_EL1。

  • 对ICC_EOIR1_EL1的访问访问ICV_EOIR1_EL1。

  • 对ICC_HPPIR1_EL1的访问访问ICV_HPPIR1_EL1。

  • 对ICC_IAR1_EL1的访问访问ICV_IAR1_EL1。

  • 对ICC_IGRPEN1_EL1的访问访问ICV_IGRPEN1_EL1。

在EL1对通用寄存器的访问在以下情况下是虚拟的:

  • 当前安全状态是非安全且(HCR_EL2.FMO == 1 || HCR_EL2.IMO == 1)。

  • 当前安全状态是安全,(HCR_EL2.FMO == 1 || HCR_EL2.IMO == 1)且SCR_EL3.EEL2 == 1。

对以下通用ICC_*寄存器的虚拟访问访问ICV_*等价物:

  • 对ICC_RPR_EL1的访问访问ICV_RPR_EL1。

  • 对ICC_CTLR_EL1的访问访问ICV_CTLR_EL1。

  • 对ICC_DIR_EL1的访问访问ICV_DIR_EL1。

  • 对ICC_PMR_EL1的访问访问ICV_PMR_EL1。

对ICC_SGI0R_EL1、ICC_SGI1R_EL1或ICC_ASGI1R_EL1的虚拟写入陷阱到EL2。

在EL2执行的软件可以使用ICH_VMCR_EL2和ICH_VTR_EL2访问某些ICV_*寄存器状态,如下所示:

  • ICV_PMR_EL1.Priority别名为ICH_VMCR_EL2.VPMR。

  • ICV_BPR0_EL1.BinaryPoint别名为ICH_VMCR_EL2.VBPR0。

  • ICV_BPR1_EL1.BinaryPoint别名为ICH_VMCR_EL2.VBPR1。

  • ICV_CTLR_EL1.EOImode别名为ICH_VMCR_EL2.VEOIM。

  • ICV_CTLR_EL1.CBPR别名为ICH_VMCR_EL2.VCBPR。

  • ICV_IGRPEN0_EL1别名为ICH_VMCR_EL2.VENG0。

  • ICV_IGRPEN1_EL1.别名为ICH_VMCR_EL2.VENG1。

  • ICV_CTLR_EL1.PRIbits别名为ICH_VTR_EL2.PRIbits。

  • ICV_CTLR_EL1.IDbits别名为ICH_VTR_EL2.IDbits。

  • ICV_CTLR_EL1.SEIS别名为ICH_VTR_EL2.SEIS。

  • ICV_CTLR_EL1.A3V别名为ICH_VTR_EL2.A3V。

6.2.1 List寄存器的使用模型

中断控制器的一个基本功能是为每个PE开发按优先级排序的挂起中断列表,然后如果中断具有足够的优先级,则向PE呈现最高优先级中断。对于物理中断,此任务完全在硬件中由GIC执行。但是,为了降低硬件成本,GIC使用硬件和软件处理虚拟中断。

对于接收到的针对vPE的每个物理中断,管理程序将该中断添加到呈现给vPE的优先级排序的挂起虚拟中断列表中。GIC硬件还提供一组List寄存器ICH_LR_EL2,它保存当前运行vPE的优先级排序列表中IMPLEMENTATION DEFINED数量的顶部条目。通常,该vPE最多只有几个挂起虚拟中断。List寄存器中的中断然后由vPE在硬件中处理,为VM提供与非虚拟化操作系统处理物理中断相同的行为。

但是,挂起、活动和挂起或活动的中断总数可能超过可用List寄存器的数量。在这种情况下,管理程序可以将一个或多个条目保存到内存中,然后根据其优先级将它们恢复到List寄存器中。这样,List寄存器充当软件控制的vPE挂起、活动或活动和挂起中断列表的缓存。

List寄存器提供维护中断:

  • 用于在List寄存器中没有挂起中断时发出信号,以允许管理程序向List寄存器加载更多挂起中断。

  • 用于在List寄存器为空或接近空时发出信号,以允许管理程序从内存中的列表重新填充List寄存器。

  • 用于在为不在List寄存器中的条目接收到EOI时发出信号,这可能在活动中断保存在内存中时发生。

  • 用于启用和禁用虚拟中断组,这可能导致需要更改List寄存器的内容。

有关维护中断的更多详细信息,请参阅_维护中断_。

注意 尽管List寄存器可能只包含活动中断,管理程序在内存中维护任何挂起中断,但挂起中断无法向vPE发出信号,直到管理程序将其添加到List寄存器中。因此,为了最小化中断延迟并确保vPE的高效操作,Arm强烈建议如果List寄存器可用于此中断,List寄存器至少包含一个挂起中断。

List寄存器构成vPE上下文的一部分。当从在PE上运行的一个vPE切换到另一个vPE时,管理程序相应地切换List寄存器。

List寄存器的数量是IMPLEMENTATION DEFINED,可以通过读取ICH_VTR_EL2来发现。

以下伪代码指示实现的List寄存器数量。

// NumListRegs()
// =============
// 实现的List寄存器数量。此值是IMPLEMENTATION DEFINED。

6.2.2 导致UNPREDICTABLE行为的List寄存器使用

以下情况被认为是软件编程错误,会导致UNPREDICTABLE行为:

  • 在单个虚拟CPU interface的List寄存器中有两个或多个具有相同pINTID的中断。

  • 在List寄存器中有一个与物理中断关联的ICH_LR_EL2.HW= 1的List寄存器条目处于活动状态或挂起状态,但Distributor没有相应的物理中断处于活动状态或活动和挂起状态。

  • 如果ICV_CTLR_EL1.EOImode ==0,则要么:

    • List寄存器中有活动中断,其优先级未在相应的Active Priority Register中设置。

    • List寄存器中有两个处于活动状态且具有相同抢占优先级的中断。

  • 当支持GICv4时,为vPE拥有有效的List寄存器和ITS映射,它们使用相同的vINTID。

  • 当支持GICv4.1时,拥有vINTID设置为SGI的有效List Register并通过ITS为vPE生成相同的SGI。

6.3 VM的配置和控制

虚拟GIC通过为每个PE保存优先级排序的挂起虚拟中断列表来工作。在GICv3中,此列表在软件中编译,顶部的多个条目在硬件的List寄存器中保存。对于LPI,此列表可以使用每个vPE的表编译。这些表由GICR_*寄存器控制。

管理程序使用在EL2可访问的System register接口来切换上下文和控制多个VM。ICH_* System register中保存的上下文是调度vPE的上下文。vPE在以下情况下调度:

  • ICH_HCR_EL2.En == 1。

  • HCR_EL2.FMO == 1,当虚拟化Group 0中断时。

  • HCR_EL2.IMO == 1,当虚拟化Group 1中断时。

  • PE在EL1执行且:

    • SCR_EL3.NS == 1。

    • SCR_EL3.EEL2 == 1。

当调度vPE时,ICH_*_EL2寄存器影响在EL1执行的软件。

ICH_*_EL2寄存器如下控制和维护vPE:

  • ICH_HCR_EL2用于虚拟中断的顶级配置和控制。

  • 有关实现的信息,如支持的虚拟INTID的大小和优先级处理级别数,从ICH_VTR_EL2读取。

  • 管理程序可以使用ICH_VMCR_EL2监视和为ICV_CTLR_EL1提供上下文。

  • 一组List寄存器ICH_LREL2由管理程序用于向PE转发挂起中断队列,请参阅_List寄存器的使用模型。ICH_LR_EL2中空闲位置的状态保存在ICH_ELRSR_EL2中。

  • List寄存器的中断结束状态保存在ICH_EISR_EL2中。

  • VM维护中断状态保存在ICH_MISR_EL2中。

  • 活动优先级状态保存在:

    • ICH_AP0R_EL2,其中n = 0-3。

    • ICH_AP1R_EL2,其中n = 0-3。

6.3.1 虚拟中断与物理中断的关联

虚拟中断可以响应物理中断而变为挂起,例如,物理中断被特定VM拥有的外设使用,或者它可以由管理程序因其他原因生成,其中没有相应的物理中断。第二种情况可以用于,例如,当管理程序模拟虚拟外设时。

为了支持这两种模型,对于SPI和PPI,GIC List寄存器提供了一种机制来配置虚拟中断与物理中断关联。物理中断和虚拟中断不一定具有相同的INTID。

将虚拟中断与物理中断关联的使用模型

虚拟中断可以按如下方式与物理中断关联:

  1. 管理程序在此模型中配置ICC_CTLR_EL1.EOImode == 1。

  2. 在接收针对vPE的物理PPI或物理SPI时,中断被传递给管理程序并由管理程序确认,使物理中断变为活动。

  3. 管理程序将虚拟中断插入到目标vPE的挂起中断列表中。当管理程序想要为该中断执行优先级下降时,管理程序执行EOI。管理程序不会去激活中断。

  4. 当此虚拟中断在该vPE的挂起中断列表中具有足够高的优先级,并且该vPE在PE上调度时,管理程序将此挂起虚拟中断写入List寄存器,并将ICH_LR_EL2.HW设置为1以指示虚拟中断与物理中断关联。相关物理中断的INTID保存在同一List寄存器中。

  5. 当vPE运行时,它将接收挂起虚拟中断,并以与确认物理中断相同的方式确认它,使用虚拟CPU interface。当在vPE上运行的中断处理程序完成其任务,虚拟中断要被去激活时,硬件去激活虚拟中断和相关的物理中断。虚拟中断可能由于中断结束而被去激活(如果ICH_VMCR_EL2.VEOIM== 0),或由于单独的去激活而被去激活(如果ICH_VMCR_EL2.VEOIM == 1)。

6.3.2 Active Priority Register

活动优先级使用ICH_AP0R_EL2和ICH_AP1R_EL2(其中n = 0-3)分别为虚拟Group 0和Group 1中断保存。Active Priority Register对实现的每个优先级组都有一位。在GICv3中,虚拟化支持多达8位优先级。但是,由于中断优先级分组,位[0]不能用于抢占。这意味着最多需要128个活动优先级位来维护上下文。实现的寄存器数量取决于支持的组优先级位数,如表6-1所示。

表6-1 管理程序Active Priority Register中的组位计数

位数寄存器寄存器数量
5ICH_AP0R_EL2 ICH_AP1R_EL2n = 0
6ICH_AP0R_EL2 ICH_AP1R_EL2n = 0-1
7ICH_AP0R_EL2 ICH_AP1R_EL2n = 0-3

如果ICH_AP0R_EL2寄存器中的某位设置为1,则在非安全EL1或非安全EL0执行时,ICH_AP1R_EL2寄存器中的等价位必须为零,否则GIC的行为是UNPREDICTABLE。

如果ICH_AP1R_EL2寄存器中的某位设置为1,则在非安全EL1或非安全EL0执行时,ICH_AP0R_EL2寄存器中的等价位必须为零,否则GIC的行为是UNPREDICTABLE。

ICH_AP0R_EL2提供多达128位的列表,其中每个实现的可抢占优先级都有一位。如果某位为1,这表示在该优先级组中有一个Group 0中断已被确认但尚未进行优先级下降。如果某位为0,这表示在该优先级没有Group 0中断活动,或该优先级组内的所有活动Group 0中断都已经历了优先级下降。

注意 写入Link寄存器不会对Active Priority Register产生影响。

ICH_AP1R_EL2提供多达128位的列表,其中每个实现的可抢占优先级都有一位。如果某位为1,这表示在该优先级组中有一个Group 1中断已被确认但尚未进行优先级下降。如果某位为0,这表示在该优先级没有Group 1中断活动,或该优先级组内的所有活动Group 1中断都已经历了优先级下降。

向这些寄存器写入任何除寄存器最后读取值或0x00000000之外的值可能导致:

  • 否则会抢占执行的虚拟中断不抢占执行。

  • 否则不会抢占执行的虚拟中断在EL1或EL0抢占执行。

注意 Arm不期望软件为除以下目的之外的任何目的读取和写入这些寄存器:

  • 作为软件电源管理的一部分,保存和恢复状态。
  • 在同一PE上的vPE之间进行上下文切换。

按除以下顺序之外的任何顺序写入Active Priority Register会导致UNPREDICTABLE行为:

  1. ICH_AP0R_EL2。

  2. ICH_AP1R_EL2。

注意

写入ICH_AP0R_EL2和写入ICH_AP1R_EL2之间不需要ISB。

6.3.3 维护中断

维护中断可以在实现虚拟化的GIC操作中发出关键事件的信号。这些事件由管理程序处理。

  • 注意

  • 只有当虚拟CPU interface的全局启用位ICH_HCR_EL2.En设置为1时,才会生成维护中断。

  • Arm强烈建议将维护中断配置为使用INTID 25。有关更多信息,请参阅_Server Base System Architecture (SBSA)_。

维护中断是电平敏感中断。ICH_HCR_EL2中的配置位可以设置为1,以在以下情况下启用维护中断的生成:

  • Group 0虚拟中断启用。

  • Group 1虚拟中断启用。

  • Group 0虚拟中断禁用。

  • Group 1虚拟中断禁用。

  • List寄存器中没有挂起中断。

  • 至少有一个EOI请求发生,但相应中断没有有效的List寄存器条目。

  • 没有有效条目,或List寄存器中只有一个有效条目。这是下溢条件。

  • 至少有一个List寄存器条目收到了EOI请求。

有关维护中断的控制和状态报告的更多信息,请参阅_ICH_MISR_EL2, Interrupt Controller Maintenance Interrupt State Register_。

6.4 伪代码

以下伪代码指示虚拟活动优先级位数。

// ActiveVirtualPRIBits()
// ======================

integer ActiveVirtualPRIBits()
    if VirtualPRIBits() == 8 then
         return 128;
    else
         return 2^(VirtualPREBits());

以下伪代码指示最高活动组虚拟优先级。

// GetHighestActiveVGroup()
// ========================
// 返回一个值,指示来自两个寄存器设置的最高优先级
// 位的中断组。如果没有位设置,则返回None。

IntGroup GetHighestActiveVGroup(bits(128) avp0, bits(128) avp1)
    for rval = 0 to ActiveVirtualPRIBits() - 1
        if avp0<rval> != '0' then
            return IntGroup_G0;
        elsif avp1<rval> != '0' then
            return IntGroup_G1NS;

    return IntGroup_None;

以下伪代码指示最高活动虚拟优先级。

// GetHighestActiveVPriority()
// ===========================
// 返回来自两个寄存器设置的最高优先级位的索引。

// 如果没有位设置,则返回0xFF。

bits(8) GetHighestActiveVPriority(bits(128) avp0, bits(128) avp1)
    for rval = 0 to ActiveVirtualPRIBits() - 1
        if avp0<rval> != '0' || avp1<rval> != '0' then
            return rval<7:0>;

    return Ones();

以下伪代码指示在提供的Active Priority Register中是否设置了任何位。

// VPriorityBitsSet()
// ==================
// 如果在提供的寄存器中设置了任何位,则返回TRUE,否则返回FALSE

boolean VPriorityBitsSet(bits(128) avp0, bits(128) avp1)
    for i = 0 to ActiveVirtualPRIBits() - 1
        if avp0<i> != '0' || avp1<i> != '0' then
            return TRUE;

    return FALSE;

以下伪代码清除提供的虚拟Active Priority Register中的最高优先级位。

// VPriorityDrop()
// ===============
// 清除提供的寄存器中设置的最高优先级位。

VPriorityDrop[bits(128) &avp0, bits(128) &avp1] = bit v
    assert IsZero(v);
    for i = 0 to ActiveVirtualPRIBits() - 1
        if avp0<i> != v then
            avp0<i> = v;
            return;
        elsif avp1<i> != v then
            avp1<i> = v;
            return;

    return;

以下伪代码指示最高活动组虚拟优先级。

// GetHighestActiveVGroup()

// ========================
// 如果提供的值在实现范围之上有位或
// 如果提供的值超过适当GITS_BASERn中的最大配置大小,则返回TRUE

boolean VCPUOutOfRange(bits(16) vcpu);

以下伪代码指示最高活动虚拟优先级。

// GetHighestActiveVPriority() // ===========================

// 返回来自两个寄存器设置的最高优先级位的索引。

// 如果没有位设置,则返回0xFF。

bits(8) GetHighestActiveVPriority(bits(128) avp0,
    bits(128) avp1) for rval = 0 to ActiveVirtualPRIBits() - 1
    if avp0<rval> != '0' || avp1<rval> != '0'
    then return rval<7:0>;

return Ones();

以下伪代码指示在提供的Active Priority Register中是否设置了任何位。

// VPriorityBitsSet()
// ==================
// 如果在提供的寄存器中设置了任何位,则返回TRUE,否则返回FALSE
    boolean VPriorityBitsSet(bits(128) avp0,
    bits(128) avp1)
    for i = 0 to ActiveVirtualPRIBits() - 1
    if avp0<i> != '0' || avp1<i> != '0' then
    return TRUE;
    return FALSE;

以下伪代码清除提供的虚拟Active Priority Register中的最高优先级位。

// VPriorityDrop()
// ===============
// 清除提供的寄存器中设置的最高优先级位。 VPriorityDrop[bits(128) &avp0,
    bits(128) &avp1] = bit v
    assert IsZero(v);
    for i = 0 to ActiveVirtualPRIBits() - 1
    if avp0<i> != v then avp0<i> = v;
return; elsif avp1<i> != v then avp1<i> = v; return;

return;

以下伪代码确定设置了哪些活动位。

// FindActiveVirtualInterrupt()
// ============================
// 查找匹配的List寄存器。如果没有匹配,则返回-1。

integer FindActiveVirtualInterrupt(bits(INTID_SIZE) vID)

    for i = 0 to NumListRegs() - 1
        if ((ICH_LR_EL2[i].State IN {IntState_Active, IntState_ActivePending}) &&
            ICH_LR_EL2[i].VirtualID<INTID_SIZE-1:0> == vID) then
            return i;

    return -1;

以下伪代码基于最小Binary Point Register指示虚拟组优先级。

// VPriorityGroup()
// ================
// 返回最小BPR值的优先级组字段

bits(8) VPriorityGroup(bits(8) priority, integer group)
    integer vpre_bits = VirtualPREBits();
    mask = Ones(vpre_bits):Zeros(8 - vpre_bits);
    return (priority AND mask);

以下伪代码基于适当的Binary Point Register指示虚拟组优先级。

// VGroupBits()
// ============
// 返回组的当前BPR值的优先级组字段

bits(8) VGroupBits(bits(8) priority, bit group)
  if IsSecure() then
     bpr = UInt(ICH_VMCR_EL2.VBPR1);
  else
     bpr = UInt(ICH_VMCR_EL2.VBPR1) -1;

    if group == '0' || ICH_VMCR_EL2.VCBPR == '1' then
        bpr = UInt(ICH_VMCR_EL2.VBPR0);

    mask = Ones(7-bpr):Zeros(bpr+1);
    return (priority AND mask);

以下伪代码指示虚拟ID位数。

// VIDBits()
// =========

integer VIDBits()
    id_bits = ICH_VTR_EL2.IDbits;
    case id_bits of
        when '000' return 16;
        when '001' return 24;
        otherwise   Unreachable();

以下伪代码指示虚拟抢占位数。

// VirtualPREBits()
// ================

integer VirtualPREBits()
    return UInt(ICH_VTR_EL2.PREbits) + 1;

以下伪代码基于最小Binary Point Register指示虚拟组优先级。

// VPriorityGroup()
// ================
// 返回最小BPR值的优先级组字段
    bits(8) VPriorityGroup(bits(8) priority,
    integer group)
    integer vpre_bits = VirtualPREBits(); mask = Ones(vpre_bits):Zeros(8 - vpre_bits);
    return (priority AND mask);

以下伪代码基于适当的Binary Point Register指示虚拟组优先级。

// VGroupBits()
// ============
// 返回组的当前BPR值的优先级组字段
    bits(8) VGroupBits(bits(8) priority, bit group)
    if IsSecure() then bpr = UInt(ICH_VMCR_EL2.VBPR1);
    else bpr = UInt(ICH_VMCR_EL2.VBPR1) -1;
    if group == '0' || ICH_VMCR_EL2.VCBPR == '1' then bpr = UInt(ICH_VMCR_EL2.VBPR0);

mask = Ones(7-bpr):Zeros(bpr+1); return (priority AND mask);

以下伪代码指示虚拟ID位数。

// VIDBits() // =========
    integer VIDBits() id_bits = ICH_VTR_EL2.IDbits; case id_bits of when '000'
    return 16; when '001'
    return 24; otherwise   Unreachable();

以下伪代码指示虚拟抢占位数。

// VirtualPREBits() // ================

integer VirtualPREBits()
return UInt(ICH_VTR_EL2.PREbits) + 1;

以下伪代码指示虚拟优先级位数。

// VirtualPRIBits()
// ================

integer VirtualPRIBits()
    return UInt(ICH_VTR_EL2.PRIbits) + 1;