登录后台

页面导航

本文编写于 210 天前,最后修改于 210 天前,其中某些信息可能已经过时。

ARMV8-A架构中包含了对虚拟化的支持。为了与架构保持匹配,GICV3也对虚拟化做了支持。新增了以下特性:

  • 对CPU interface的硬件虚拟化
  • 虚拟中断
  • maintenance 中断:用于通知监管程序(例如hypervisor)一些特定的虚拟机事件

GIC架构不提供对gicd、gicr和ITS部件的虚拟化。对于这些接口的虚拟化必须通过软件来进行处理。这些部件的虚拟化不在我们此处讨论的范围内

hypervisor创建、控制并调度虚拟机VM。一个虚拟机等价于一个物理系统,并且包含一个或多个虚拟处理器。每一个虚拟处理器包含一个或多个虚拟PE(vPEs)

Untitled

GICv3.x和GICv4.1对虚拟化的支持,是作用于vPEs级别上的。例如,当创建了一个虚拟中断,它的目标是特定的vPE,而不是VM。GIC并不知道vPEs和VM之间的关联。

GICv3-虚拟化

CPU Interfaces

CPU interfaces被分为了三个部分:

  • 物理的CPU接口寄存器
  • 虚拟化控制寄存器
  • 虚拟的CPU接口寄存器

8833070E-CB91-4AEA-BFE1-90C309072FFA.jpeg

  • physical CPU interface

    执行在EL2的管理程序可以通过ICC_*_ELn寄存器对物理中断进行处理

  • virtualization control

    管理程序可以访问额外的寄存器ICH_*_EL2,用于控制架构提供的虚拟化特性,包括:

    • 使能/关闭virtual CPU interface
    • 访问虚拟寄存器状态用于进行上下文的切换
    • 配置maintenance中断
    • 控制虚拟中断

    这些寄存器控制的是它们能够访问的物理PE的虚拟化特性,不能访问其他PE的状态(执行在PE X上的软件不能访问PE Y的状态)

  • virtual CPU interface

    执行在虚拟环境中的软件通过ICV_EL1寄存器对中断进行处理。这些寄存器与ICC_EL1寄存器有着相同的形式与功能。

    ICV寄存器和ICC寄存器的instruction encoding都是相同的。在EL2、EL3和安全EL1状态下,往往使用的是ICC寄存器。在非安全EL1状态下,使用ICC寄存器还是ICV寄存器是由HCR_EL2寄存器(FMO、IMO字段)来决定的。

    ICV寄存器被分为三组:

    • group0:用于处理group0中断。例如ICC_IAR0_EL1和ICV_IAR0_EL1。当HCR_EL2.FMO==1时,在EL1访问的是ICV寄存器而不是ICC寄存器。
    • group1:用于处理group1中断。例如ICC_IAR1_EL1和ICV_IAR1_EL1。当HCR_EL2.IMO==1时,在EL1访问的是ICV寄存器而不是ICC寄存器。
    • common:用于处理group0和group1中断。例如ICC_DIR_EL1和ICV_DIR_EL1寄存器。当HCR_EL2.FMO==1或HCR_EL2.IMO==1时,在EL1访问的是ICV寄存器而不是ICC寄存器。

    ICV寄存器是否可用于安全EL1异常等级,是取决于安全虚拟化是否开启。后面会详细阐述。

    Untitled

管理虚拟中断

执行在EL2的管理程序可以通过ICH_LR_EL2(list register)这一组寄存器来产生虚拟中断。每一个寄存器代表了一个虚拟中断,并记录了以下信息:

  • virtual INTID
  • state(pending、active、active&pending、inactive):当运行在虚拟环境中的软件与GIC进行交互之后,这个状态机会自动更新。例如vPE上的软件读取了ICV_IARn_EL1寄存器。
  • group(group0、group1s、group1ns):在非安全状态下,虚拟环境的行为就如同GICD_CTLR.DS==1 。在安全状态下,虚拟环境的行为就如同GICD_CTLR.DS==0。因此虚拟中断可以为group0或group1。group0虚拟中断被上报为vFIQs,group1虚拟中断被上报为vIRQs。
  • pINTID(虚拟中断可以选择与物理中断绑定起来,两者的状态机会同步更新)

list寄存器并没有记录目标vPE。列表寄存器是针对于当前被调度的vPE。当发生vPE切换时,由软件来执行list寄存器的上下文切换。

物理中断转发到vPE的举例

DAAC5D05-7D80-4594-9D15-AC185BCCF048.jpeg

当一个物理中断被转发给vPE时会发生以下步骤:

  1. gicr将一个物理的非安全group1中断转发到物理的CPU interface上
  2. CPU interface检查该中断是否能被转发至PE上
  3. 该中断被在EL2进行处理。管理程序读IAR寄存器,并决定是否将其转发到vPE上。然后写EOIR寄存器。当ICC_CTLR_EL1.EOImode == 1时,写EOIR寄存器这个操作,只会执行优先级下降,而不会deactive这个物理中断。详细内容查看物理中断的生命周期。
  4. 管理程序写上述提到的LIST 寄存器来产生一个虚拟中断。该虚拟中断与物理中断绑定在了一起。然后管理程序进行异常返回。
  5. 虚拟CPU interface检查该虚拟中断是否能被转发到vPE上。除了使用ICV寄存器之外,这些检查与物理中断的检查是相同的。
  6. 这个虚拟中断会被带到非安全的EL1状态。当软件读取IAR寄存器时,该虚拟中断进入active态。
  7. 执行在非安全EL1的软件对该中断进行处理。当其处理完成后,写EOIR寄存器。因为该虚拟中断与物理中断绑定在了一起,所以虚拟中断会和物理中断一起进入deactive状态,结束整个中断处理。

这个示例展示了一个物理中断如何转换成一个虚拟中断转发到vPE上。不是所有的虚拟中断都是由物理中断引发的。虚拟化的软件可以在任意时刻通过list寄存器产生一个虚拟中断。

Maintenance Interrupt

可以配置CPU interface,在当虚拟的CPU interface满足一定条件时产生一个物理的中断。这个中断会被上报为中断号为25的PPI中断。这个中断一般会被配置为非安全group1类型的中断,并且由执行在EL2的管理程序进行处理。

维护中断的生成是由ICH_HCR_EL2进行控制的,并且该类型的中断触发会在ICH_MISR_EL2寄存器报告。

例如:当vPE把虚拟CPU interface上的group0中断的使能位给清零了,就会产生一个维护中断。看到这个中断之后,管理程序可以清除list register上所有处于pending状态的group0中断。

上下文切换

在vPE之间进行上下文切换时,hypervisor软件保存一个vPE的状态,并加载另一个vPE的上下文。虚拟CPU接口的状态构成了vPE上下文的一部分。虚拟CPU接口状态包括以下信息:

  • ICV寄存器的状态。
  • 激活的虚拟优先级。
  • 任何挂起的、活动的或活动的和挂起的虚拟中断。

ICV寄存器的状态可以使用ICH寄存器从EL2访问。例如,下图显示了ICH_VMCR_EL2中的字段如何映射到ICV寄存器状态。

Untitled

切换虚拟机时,需要保存和恢复激活的虚拟优先级。当前vPE的活动优先级可以使用ICH_APxRn_EL2寄存器访问。
如管理虚拟中断中所述,使用List寄存器管理虚拟中断。这些寄存器的状态是特定于当前vPE的。因此,必须在上下文交换机上保存和恢复这些寄存器。

GICv3.1-安全虚拟化

Untitled

在PE支持的情况下,可以通过SCR_EL3.EEL2开启或关闭对安全虚拟化的支持。
GICv3.1将GICv3.0对虚拟化的支持扩展到安全状态,以与Armv8.4-A保持一致。当SCR_EL3.EEL2==1,前一节描述的所有特性也适用于安全状态。
安全和非安全状态虚拟化之间有一些细微的区别。在非安全状态下,虚拟环境始终按照GICD_CTLR.DS==1行事。在安全状态下,虚拟环境的行为与GICD_CTLR.DS==0一样, FIQs路由到EL1。对于大多数寄存器访问,这种区别没有实际的区别。然而,当写入ICV_BPR1_EL1时,该寄存器允许的最小值是不同的。

只有一个GIC维护中断,由处于安全和非安全状态的不同虚拟化软件共享。处理此问题的一种方法是在更改Security状态时保存并恢复此中断的配置。

GICv4.1-直接注入虚拟中断

GICv4继承了前几节中介绍的对虚拟化的所有支持。它增加了对直接注入虚拟中断的支持。这个特性允许软件提前向ITS描述物理事件如何映射到虚拟中断。如果虚拟中断所针对的vPE正在运行,则可以转发虚拟中断,而不需要首先进入管理程序。通过减少进入管理程序的次数,可以减少与虚拟化中断相关的开销。
GICv4.0支持直接注入虚拟lpi。GICv4.1扩展了对虚拟sgi (vsgi)的支持。GICv4.0和GICv4.1之间有一些变化,使它们彼此不兼容。本指南涵盖了GICv4.1编程模型。
在GICv4.0和GICv4.1中,直接注入仅限于非安全状态。安全状态下不支持直接注入。

概述

GICv4.1允许软件定义几个虚拟pe (vPE),并将物理中断映射到这些vPE。vPE由vPEID (virtual Processing Element ID)标识。vPEID是一个全局标识符,由系统中的所有redistributor和ITSs共享。
vPE的配置和状态存储在基于内存的表中。这类似于管理物理lpi的配置和状态的方式。redistributor使用三种基于内存的表来管理虚拟中断:

  • 虚拟LPI pending表:每一个vPE都会拥有一个虚拟LPI待定表。它会保存以该vPE为目标的虚拟中断的pending状态。
  • 虚拟LPI configuration表:它保存了vLPIs的配置信息(使能和优先级)。一个虚拟LPI configuration表必须被所有vPEs所共享。例如在一个虚拟机中的所有vPEs共享一张虚拟LPI configuration表。
  • vPE configuration表:vPE配置表保存了所有vPEs的配置信息。在表中,每一个vPE都会有一个表项,保存了指向该vPE对应的虚拟LPI pending表和虚拟LPI configuration表的指针。该表项中还会保存vPE的其他相关信息,例如vINTID namespace的大小。一个vPE configuration表被多个gicr所共享。

Untitled

vPE配置表的位置和大小由软件使用GICR_VPROPBASER寄存器指定。
GIC需要知道当前在物理PE (pPE)上调度了哪个vPE(如果有的话)。对于GICv4.1,当前调度的vPE在GICR_VPENDBASER中指定。

这是GICv3和GICv4之间的一个显著差异。在GICv3和GICv4中,虚拟中断只能发送到当前调度的vPE。在GICv3中,硬件不知道调度的vPE的ID,而是由软件负责在上下文切换时管理它。在GICv4中,硬件需要知道当前哪个vPE被调度,因为中断可以随时到达。

软件使用ITS命令来创建和管理vPE。VMAPP定义一个新的vPE,指定它的配置和虚拟Pending表和configuration表的位置。这个信息
保存在vPE配置表中。VMAPI和VMAPTI将物理中断映射到针对特定vPE的虚拟中断。
下图显示了当一个针对vPE的中断到达时会发生什么:

Untitled

  1. 外设发送一个MSI给ITS
  2. ITS翻译MSI中的EventID/DeviceID。返回的映射表明中断被映射到了一个vPE,而不是一个物理的LPI。
  3. ITS将中断转发给目标gicr,并且发送中断的vINTID和vPEID
  4. gicr根据vINTID和vPEID在vPE configuration table中检索vPE的配置信息。并且根据GICR_VPENDBASER寄存器检查vPE是否被调度
  5. 如果vPE被调度,中断会被直接转发到虚拟的CPU interface上。否则这个中断会被记录为pending态,等待下一次这个vPE被调度

Redistributor

gicr会根据vINTID和VPEID在vPE configuration table中检索vPE的信息

CommonLPIAff groups

gicr被分组在一起,分组由GICR_TYPER寄存器的CommonLPIAff字段和affinity字段所定义。CommonLPIAff作为亲和性值的掩码,应用掩码后具有相同亲和性值的重分发器属于同一组。
例如,如果CommonLPIAff==2,则所有具有相同Aff3.Aff2值的gicr在同一组中。

考虑一个有四个gicr的系统,它们具有以下affinity value:

0.0.0.0
0.0.0.1
0.1.0.0
0.1.0.1
经过CommonLPIAff掩码处理后:
0.0.x.x
0.0.x.x
0.1.x.x
0.1.x.x

所以这4个gicr被分为了2组0.0.x.x和0.1.x.x

CommonLPIAff分组期望相同组的gicr在物理上更为接近。例如一个die上的gicr被分在一个组内。

CommonLPIAff的值非常重要。它表明了软件需要开辟多少地址结构并且gicr是否能被调度。

vPE Configuration Table

vPE配置表保存了所有vPE的详细信息。表的大小决定了软件可以创建多少vPE。
vPE配置表由GIC填充和维护。在内存被分配给GIC之后,软件永远不会读取或写入表。这样做会导致GIC的行为不正确。
软件必须为每个CommonLPIAff组分配一个表的副本。也就是说,如果有两个CommonLPIAff组,软件必须为表的两个副本分配足够的内存。这是一个性能优化,因为它允许redistributor使用接近它们的内存。
在创建映射vPE之前,软件必须分配所需数量的表,并填充每个Redistributor的GICR_VPROPBASER。

控制vPE调度

当前哪一个vPE运行在物理PE上是由GICR_VPENDBASER来定义的。要改变调度的vPE,软件必须:

  1. 清除GICR_VPENDBASER.Valid

    清除valid位表明gicr正在进行上下文切换。gicr在虚拟CPU interface上检索是否存在pending态的虚拟中断并且确保内存中的虚拟LPI pending table是正确的。

  2. 轮询GICR_VPENDBASER.Dirty位直到它为0

    Dirty位报告Redistributor何时完成对其内部状态的更新。这包括从vCPU接口检索旧vPE的所有挂起的虚拟中断。一个新的vPE不能被调度,直到这个位读0。Arm建议虚拟化软件在观察到Dirty为0之前不要切换ICH寄存器的上下文。

  3. 更新GICR_VPENDBASER 并且设置Valid位==1

    将Valid位设置为1通知Redistributor新的vPEID现在是有效的,并且该vPE的虚拟中断可以被转发。GICR_VPENDBASER还包含虚拟分发组enable,它控制哪些虚拟中断组可以转发到CPU接口。

  4. 轮询GICR_VPENDBASER.Dirty位直到它为0

在ITS中,vPE被映射到一个特定的Redistributor。这种映射会随着时间的推移而改变,但在任何给定的点上,都有一个vPE的单一目标gicr。然而,vPE可以被安排在与目标gicr属于同一CommonLPIAff组的任何gicr上。在属于不同组的gicr上进行调度可能导致GIC行为错误。在单芯片设计中,有可能所有的redistributor都是同一个CommonLPIAff组的一部分。在这种情况下,您将能够在任何Redistributor上调度vPE。

软件不得:

  • 在将vPE映射到ITS之前,在任何Redistributor上设置vPEID为scheduled。
  • 在多个gicr上标记相同的vPEID。

门铃中断doorbells

hypervisor通常将vPEs分为三个状态:

  • running:vPE当前由管理程序和物理PE调度。对于GIC,这意味着vPE可以接收直接注入的虚拟中断。
  • runnable or to-be-scheduled:vPE未被任何物理PE调度。管理程序知道vPE有工作要做,因此在将来的某个时间安排它。虚拟中断目前不能由GIC传送到这个vPE。
  • idle:vPE当前没有在任何物理PE上调度。虚拟机监控程序认为vPE没有工作要做,因此不会在将来安排它。

当vPE的工作可用时,vPE将从Idle变为Runnable。可能发生这种情况的一种方式是到达针对vPE的中断。但是这需要管理程序意识到中断已经到来。这种机制被称为门铃中断。
当一个虚拟中断到达时,如果目标vPE被调度,中断可以被转发到CPU接口:

Untitled

Untitled

这个门铃是一个物理中断,通常会被带到EL2并由管理程序处理。它向系统管理程序发出信号,表示未调度的vPE有一个待处理的中断,这意味着应该将其移动到Runnable队列,以便将来进行调度。
GICv4.1支持两种门铃类型:

  • 默认门铃
  • 独立的门铃(支持是可选的在GICv4.1)

默认门铃

每个vPE可以分配一个默认的门铃。当任何针对vPE的中断变为挂起并且vPE未被调度时,将生成一个默认的门铃。

该架构为默认门铃提供了几个保证:

  • vPE的默认门铃设置为pending态不超过一次。
    一旦vPE从Idle移动到Runnable,软件就不需要再为该vPE设置门铃了。vPE已经安排好了。

  • 默认门铃仅在vPE未被调度的情况下被请求时生成。
    如果系统管理程序在被设置为非调度状态时,已经将vPE标记为runnable,那么它不需要门铃。接收一个门铃中断将是低效的。

  • 默认门铃只在pending中断被启用时生成。
    软件只想知道那些将被转发到vPE的pending中断。如果中断被禁用,那么我们不需要使vPE可运行。

  • 通过调度vPE来清除pending的默认门铃中断。

    如果vPE在调度时仍然有一个未完成的默认门铃,那么该中断将被清除。因为虚拟机监控程序不再需要知道vPE正在执行哪些工作。

默认门铃生成由GICR_VPENDBASER中的两位控制:

  • GICR_VPENDBASER.PendingLast
    当vPE被设置为非调度时,这个位报告是否有未完成的挂起中断。
  • GICR_VPENDBASER.Doorbell
    软件设置这个位来指示是否需要生成门铃。

当PendingLast报告vPE有挂起的中断时,Doorbell被视为0(没有门铃)。否则就意味着必须立即生成一个门铃。
用于vPE的默认门铃的INTID是使用ITS命令设置的,我们将在后面介绍。

软件无需在创建vPE时注册默认门铃中断。设置默认门铃中断号为1023意味着当前没有门铃。

修改默认门铃中断配置

默认的门铃是物理lpi,这意味着它们的配置存储在内存中。具体来说,在物理LPI配置表中。如果软件想要更改物理LPI的配置,它将写入表,然后使用INV命令使旧配置的任何缓存无效。
虽然默认的门铃是物理lpi,但它们在缓存方面的行为与其他lpi不同。对于作为默认门铃的intid,软件必须发出一个INVDB命令。

独立的门铃中断

可以选择为每个虚拟中断设置单独的门铃,而不是为每个vPE设置。这意味着系统管理程序可能会根据针对vPE的哪个中断处于挂起状态而采取不同的操作。例如,大多数中断可以使用默认的门铃,并使vPE被标记为可运行的。高优先级中断可以分配一个单独的门铃,并立即引起重新调度。
单个门铃不具有与默认门铃相同的保证。特别是:

  • 不能保证每个门铃被设置为pending仅一次。
  • 软件不能注册一个单独的门铃,使vPE non- scheduled。如果为虚拟中断提供了一个中断,那么它是在vPE未被调度时生成的。

软件可以为多个虚拟中断分配相同的物理INTID,只要所有这些中断都属于同一个vPE。

独立门铃是可选功能,通过GITS_TYPER.nID表现

ITS

ITS负责将输入的MSIs进行翻译并且将其以虚拟中断的方式进行转发。

vPE Table:对于虚拟中断,中断翻译表(interrupt translation tables ITTs)记录了中断的目标vPE和虚拟中断号。ITS也需要记录哪一组gicr映射到了vPE上。有两种模式可以选择,GITS_TYPER.SVEPT字段表明支持哪一种模式:

  • SVEPT==0:ITS用一张私有的表记录vPE的映射信息。软件必须给这个表开辟地址空间,并且设置GITS_BASER2寄存器指向这张表
  • SVEPT==1:ITS也使用gicr的vPE configuration table。软件必须设置GITS_BASER2寄存器指向vPE configuration table

Mapping a vPE

使用VMAPP命令

VMAPP <vPEID>,<RDADDR>,<VPT size>,<VPT address>,<VCT address>,<doorbell>
  • vPEID是vPE的ID号
  • RDADDR是目标gicr
  • VPT address和VCT address分别是虚拟LPI pending表地址和虚拟LPI configuration 表地址
  • VPT size指明了vINTID的宽度
  • doorbell是指vPE的默认门铃中断的物理中断号。若为1023则意味着vPE没有门铃中断

在目标redistribution中分配并设置vPE配置表之前,软件不能使用VMAPP创建vPE。

Mapping MSI to vINTID

EventID和DeviceID组合起来映射到vINTID和vPE。VMAPI命令就是用于EventID和vINTID相同的情景下的

VMAPI <DeviceID>,<EventID>,<pINTID>,<vPEID>

VMAPTI命令是用于EventID和vINTID不相同的情景下的

VMAPTI <DeviceID>,<EventID>,<vINTID>,<pINTID>,<vPEID>

pINTID是当vPE未被调度时产生的独立门铃中断ID号。如果pINTID为1023时意味着没有独立门铃中断。

例如:一个外设设备ID为5,它能产生两个事件ID分别为0和1。这两个事件ID都被映射到了属于ID为6的vPE的vINTIDs上。

  • 事件ID为0,vINTID为8725,没有独立的门铃中断
  • 事件ID为1,vINTID为9000,没有独立的门铃中断

vPE 6 被映射到了7号gicr上,并且使用8192号中断作为默认门铃中断。

命令队列如下所示:

VMAPP 6,7,14,<pending table addr>,<config table addr>,8192
VMAPTI 5,0,8725,1023,6
VMAPTI 5,1,9000,1023,6
VSYNC 6

Remapping a vPE to different Redistributor

如果hypervisor将vPE迁移到属于不同CommonLPIAff组的Redistributor,则必须更新ITS映射,以便将虚拟中断发送到正确的位置。ITS映射使用VMOVP命令更新,然后使用VSYNC来同步上下文。

门铃中断总是被传递到映射的Redistributor,但是vPE可以被调度到同一个CommonLPIAff组中的任何Redistributor。如果软件希望将一个vPE的门铃中断传递到另一个PE,它必须发出一个VMOVP命令。

一个系统可以包含多个ITSs。如果有多个ITS具有vPE的映射,则必须将任何更改应用于包含原始映射的所有ITS。GICv4支持两个模式完成上述的同步,GITS_TYPER.VMOVP表示使用哪个模型。

  • VMOVP==1:

    VMOVP命令必须只在一个ITS上作用,而不管有多少个ITS对vPE有映射。需要硬件来传播更改和处理同步。这意味着ITS List和SequenceNumber字段不是必需的。

    VMOVP <vPE ID>,<RDADDR>

    ARM希望使用这种模式

  • VMOVP==0:

    VMOVP命令必须在所有对vPE有映射的ITS上作用

    VMOVP <vPEID>,<RDADDR>,<ITS List>,<Sequence Number>

    在这个命令中:

    • ITS List是所有对vPE有映射关系的ITS集合。这个字段是每一位bit代表一个ITS。bit0代表ITS0。ITS数量记录在GITS_CTLR.ITS_Number字段中。
    • Sequence Number为同步点。软件在向不同的ITSs发出VMOVP命令时必须使用相同的值,并且在所有ITSs上完成命令之前不得重用相同的值。

Remapping vINTIDs

VMOVI命令用于重新映射EventID和DeviceID所绑定的vINTID和vPE

VMOVI <DeviceID>,<EventID>,<vPEID>,<vINTID>,<pINTID>

GICv4.1-直接注入vSGIs

GICv4.1引入了一个新特性,即直接注入虚拟sgi (vSGI)的能力。该特性通过消除需要hypervisor介入的一些情况进一步减少了开销。

软件通过写入ITS中的gits_sgi寄存器来生成一个vSGI。软件写入目标vPE的vPEID和正在发送的SGI的INTID。ITS查找指定vPE的映射,然后将vSGI转发给目标重分发器。
发送vSGI的流程如下图所示:

Untitled

  1. 运行在虚拟机中的软件写入ICC_SGI寄存器之一以生成SGI。这个写操作包含正在发送的INTID和目标vPE的亲和性值。这个寄存器写入触发一个trap异常到EL2。
  2. 管理程序将VM写入的亲和值转换为vPEID,然后写入gits_sgir以生成虚拟中断。
  3. ITS查找指定vPEID的gicr,然后将vSGI转发给该重分发器。
  4. 如果目标vPE是被调度的,gicr检索中断的配置并将中断转发到CPU interface。CPU interface然后将vSGI发出虚拟中断异常的信号。

如果vPE没有被调度,中断将被记录为pending。可选地,可以生成一个默认的门铃。
这个过程仍然需要一定程度的hypervisor交互来将写入icc_sgir寄存器的虚拟affinity值转换为vPEID。但在此之后,GIC的直接注入机制可以处理该过程的其余部分。

vSGI配置

为了直接注入vsgi, Redistributor需要知道这些vsgi的配置(enable、priority、group)。该信息记录在虚拟LPI Pending Table中。该表的前1K用于记录特定于实现的信息。GICv4.1使用该空间的一小部分来存储vSGI配置。
与vlpi不同,软件不能直接写表来更新vsgi的配置。相反,使用一个新的ITS命令来设置配置:

VSGI <vPEID>,<vINTID>,<Enable>,<Group>,<Priority>,<Clear>

Clear位是被用于清除中断的pending状态。

发送组与接收组

当软件生成SGI时,写特定的寄存器指定要发送SGI的Group:

  • ICC_SGI0R_EL1:发送组0中断
  • ICC_SGI1R_EL1:发送组1中断

接收方还为每个SGI INTID指定一个Group。对于物理中断,这是使用GICR_IGROUPR0和GICR_IGRPMODR0寄存器指定的。

对于虚拟的sgi,正如我们刚才看到的,组是使用VSGI命令设置的。
对于物理sgi, GIC将发送的Group与接收端配置的Group进行对比。只有当它们匹配时,中断才被设置为挂起。
对于虚拟sgi, gits_sgi中没有Group字段。GIC将始终使用为接收方配置的Group。因此,由软件(通常是hypervisor)根据接收方配置的组来检查发送的组。

vSGIs和pSGIs区别

在大多数方面,虚拟和物理sgi的行为是相同的。有一个地方它们是不同的——vsgi使用与lpi相同的状态机(只有inactive和pending状态)

这降低了GIC硬件的复杂性。在大多数情况下,这种差异对软件来说是不可见的。要看到区别,VM中的软件必须使用EOImode==1。这是使用两个单独的寄存器写来执行优先级下降和停用的地方。对于pSGI,直到停用后GIC才能处理相同INTID的中断。对于vSGI,在优先级下降之后,在停用之前,GIC可以处理相同的INTID。

查询vSGI状态

有时,hypervisor需要检查vSGI是否处于挂起状态。例如,处理虚拟机对GICR_ISPENDR0寄存器的读取。
要启用此功能,需要向Redistributor添加两个新寄存器,以查询vPE的vsgi的当前挂起状态。软件的功能如下:

  1. 将vPEID写入gicr_vsgir。
  2. 轮询GICR_VSGIPENDR.busy。直到读取的值0,此时GICR_VSGIPENDR.Pending位表明vPE的sgi的挂起状态。

没有gicr的寄存器可以模拟对GICR_ISPENDR0和GICR_ICPENDR0寄存器的写操作。这些可以使用ITS进行模拟:

  • 写入GICR_ICPENDR0可以通过VSGI命令Clear==1来模拟。
  • 写GICR_ISPENDR0可以通过写gits_ssir寄存器来模拟。
博主已关闭本页面的评论功能