登录后台

页面导航

1. 中断类型

GIC700管理SPIs、SGIs、PPIs和LPIs。如果支持GICv4.1架构,那么SGIs和LPIs可以被直接注入vPEs

2. multichip操作

包含多个芯片的系统可以有多个外部连接的SoC,也可以有多个连接在单个物理封装内的SoC。在所有情况下,每个SoC都集成了GIC700。一个多芯片系统最多可以有16个芯片。 为了控制配置中所有芯片的一致性,并使GIC对操作系统显示为单个实体,GIC700使用一组寄存器来定义芯片之间的连通性。这些寄存器被称为路由表,由以下三种寄存器类型组成:

  • GICD_CHIPR(chip register):这组chip寄存器定义了路由表。它指定了chip拥有的SPI,并且chip如何被访问。这个寄存器存在于每一个chip中,所以每一个chip都会拥有路由表的一个副本。
  • GICD_DCHIPR (default chip register):指明了当前对路由表的一致性负责的chip,并指示什么时候对路由表进行更新。
  • GICD_CHIPSR (chip status register):表明当前chip状态的细节。

在复位时,多芯片系统中的每一个芯片都有一个有效的独立的全功能的GIC。GICD_CHIPSR寄存器中RTS位表明当前各个chip上的GIC处于disconnected状态

当多芯片被连接在一起之后,每32个SPI被分为一组(SPI block),每一个组都会被一个特定的chip所拥有。所以芯片之间的SPI空间是分段的。

  • 根据路由表,没有被任何芯片拥有的SPIs是不能被使用的
  • 只有芯片拥有的SPIs,其在chip上的SPI信号线才能被使用。但是基于消息的SPIs,如果被任意一个芯片拥有,那么就可以使用
  • 在某个时刻,路由表只能执行一个操作。因此,软件必须在对路由表执行任何操作前确保GICD_DCHIPR.PUP==0

3. 中断分组与安全

每一个中断都属于一个中断分组,每一个中断分组:

  • 表明中断在这个分组内的安全状态,这取决于核的异常等级
  • 拥有单独的使能开关,用于控制这个分组的中断是否能转发到核上
  • 对后续在核接口上的路由策略会有影响

安全和分组:

  • Secure group0:interrupt for EL3(Secure firmware)
  • Secure group1:interrupt for EL1(trust OS)
  • non-Secure group1:interrupt for non- Secure(OS or hypervisor, or one of both)

GICD_CTRL.DS(disable secure):

  • 0:Secure enabled
  • 1:Secure disabled

在具有安全状态的系统中,group0总是安全的。 如果一个系统有安全的概念,但一个或多个核没有,那么不能禁用安全性。每个核只能启用与它所支持的安全状态相对应的中断组。

4. 亲和路由和指派

GIC700使用亲和路由(一种分层方案)来识别连接的核,并将中断路由到特定的核。 Arm架构在核内定义了一个寄存器,用于标识核在系统中的逻辑地址。这个寄存器称为多处理器标识寄存器(multi processor identification register MPIDR),具有层次结构格式。层次结构的每一层都称为亲和级别,首先指定最高的亲和级别:

  • 对于32位Armv8处理器,MPIDR定义了三个级别的亲和性,隐含的亲和性级别3的值为0。
  • 对于64位Armv8处理器,MPIDR定义了四个亲和级别。

GIC700将支持多个硬件线程的处理器的每个硬件线程视为一个独立的内核。 核心的亲和度由4个8位字段表示,使用点十进制记数法,分别为(die number).(cluster number).(core number).(thread number),其中Affn是亲和性级别n的值。 亲和性方案匹配Armv8-A中MPIDR_EL1寄存器的格式。系统设计人员必须确保MPIDR_EL1寄存器的核报告的ID与核连接到中断控制器的方式相匹配。 GIC700可以完全灵活地分配MPIDR。但是,它有两个内置的默认赋值,它们基于aff0_thread配置参数:

  • aff0_thread == 1
  • aff0_thread == 0

image-20241215131140607

5. RAMs和ECC

GIC-700使用多个ram来存储所有类型中断的一系列状态。在典型操作中,ram对软件是透明的。 每个RAM都可以使用具有单错误校正和双错误检测(SECDED)的ECC来防止错误。 如果检测到单错误或双错误,则在软件可见的错误记录中报告。

5.1 RAM错误模拟

对于每一个RAM,软件可以用GICx_ERRINSR寄存器来模拟一个暂时的ECC单bit错误或者双bit错误。

GICR_ERRINSR寄存器对应的是GCI中的RAM。

GICD_ERRINSR寄存器对应的是以下RAM:

  • 0X0 SGI RAM
  • 0X1 SPI RAM 0
  • 0X2 SPI RAM 1
  • 0X3 SPI TGT RAM
  • 0X4 SPI LPI RAM
  • 0X5 LPI RAM BANK 0
  • 0X6 LPI RAM BANK 1
  • 0X7 LPI RAM BANK 2
  • 0X8 LPI RAM BANK 3
  • 0X9 PENDING TABLE MAP CACHE
  • 0XA VICM RAM
  • 0XB VICM SEARCH RAM
  • 0XC VTGT RESIDENCY RAM
  • 0XD VTGT STORE RAM
  • 0XE VTGT SEARCH RAM
  • 0XF CC RAM

这些寄存器导致错误被插入到相关RAM中的指定地址和位置。ECC编码器和解码器被检查,但不修改RAM内容。除非安全软件设置GICD_SACG.GICTNS为1,否则这些寄存器都只能安全访问。 软件插入错误后,与普通的ECC错误一样,GIC将该错误报告到相关的错误记录中。但是,软件注入的错误对GIC的功能没有影响,所以软件可以在运行过程中注入错误。 如果同时发生实际错误,那么GIC将报告实际错误,并触发该中断类型的正常机制。

5.2 Scrub

GIC700在RAM中保存重要的编程和中断状态,这是由单错误纠正和双错误检测(SECDED)保护的。 但是,有些RAM内容可能在很长一段时间内是静态的,如果不定期访问某个特定地址,就有可能累积错误。为了防止这种情况的发生,软件可以通过设置GITS_FCTLR.SIP、GICR_FCTLR.SIP、GICD_FCTLR.SIP周期性地触发对RAM的低优先级清理。这个过程触发一次检查,如果必要的话,会触发一次所有有效RAM条目的回写。在清理过程中发现的任何错误也会在相关的RAS错误记录中报告。

6. 直接注入

GIC700支持将vSGIs和vLPIs直接注入到虚拟机中,不需要处理器在虚拟环境中改变状态去执行hypervisor。

为了将vPEs与GIC之间映射起来,软件必须执行ITS中的VMAPP命令。

GIC700需要在VMAPP命令中使用Valid(V)和Allocate(A)两个bit位。以下操作会导致不可预测的行为:

  • 当vPE上已经存在映射关系时,使用VMAPP(V1A1)命令
  • 在VSYNC命令完成前,在VMAPP(V1A1)命令之后,针对同一个vPE使用VMAPP(V1A0)
  • 当任何其它ITS与当前vPE存在映射关系时,使用VMAPP(V0A0)
  • 针对vPE的VMAPP命令的有效数据字段除了RDbase以外都不相同

为了维护有关映射vPE的信息,GIC为每个芯片使用单个vPE表,该表在芯片上的所有redistributor和ITSs之间共享。

6.1 Doorbells

门铃中断是物理的LPIs中断,用于向hypervisor表明有一个中断发给vPE。

每一个vPE都可以通过ITS的VMAPP或者VMOVP命令指定一个独特的门铃中断。当给vPE的第一个vLPI或者vSGI中断处于pending状态时,GIC为vPE产生一个门铃中断。门铃中断在vPE变成resident状态时被屏蔽

GIC700有以下门铃中断特征:

  • 门铃中断ID必须是独特的,它不能被映射到任何ITS上的任何DeviceID和EventID
  • GIC700不支持单独的门铃中断,所以GITS_TYPER.nID == 1
  • 只有当vPE上一次resident时相应的虚拟中断分组是enable的,才会产生门铃中断。在被映射之后vPE没有被resident
  • GIC会忽略VMAPP和VMOVP命令中门铃中断ID超出GICR_PROPBASER.IDbits范围的命令

门铃属性在第一次创建映射时被缓存。可以通过更新LPI Configuration表并从任何映射了vPE的ITS发出VINVDBL命令来更改属性。 门铃属性不会在芯片之间传输,如果VMOVP将vPE移动到远程芯片,则会重新获取门铃属性。 当vPE映射存在时,软件不能禁用GICR_CTLR.EnableLPIs位,因为这样会阻止门铃中断获取属性,并且它们被缓存为禁用。

6.2 Resident和VMOVP

使用ITS VMOVP命令,软件可以在本地和远程芯片上的PE之间自由移动vPE。

GIC700只支持GITS_TYPER.VMOVP == 1。因此,VMOVP命令必须只在GIC的单个ITS(映射到vPE)上运行,以确保系统中的所有ITS能够无缝地继续向vPE发送中断。GIC只在下次访问vPE时更新ITS。 门铃中断被传送到vPE映射到的PE。但是,GIC支持使vPE驻留在同一芯片上的任何PE上(以交付中断),因为当前的映射没有VMOVP。也就是说,在使vPE驻留之前不需要发出VMOVP,除非移动芯片或在不同PE之间平衡门铃。

为了将中断传递给一个vPE,它必须驻留在PE上,这是通过使用相关PE的GICR_VPROPBASER并轮询GICR_VPROPBASER.Dirty == 0来完成的。在dropping GICR_VPROPBASER.Dirty之前,GIC尝试向PE交付任何中断。

建议在创建vPE驻留之前设置CPU虚拟组启用。这是为了确保GIC可以强制中断到达PE,从而防止在中断交付之前与GuestOS到达WFI的竞争。如果软件试图做以下任何一件事,行为是不可预测的:

  • 让vPE驻留在多个PE上
  • 当vPE没有映射到芯片上的PE时,让vPE驻留
  • 对一个驻留的vPE执行VMOVP命令

GIC的设计是为了确保最高优先级的中断总是准备就绪,等待vPE驻留。然而,在GICD_FCTLR2中有两个比特控制是否在某些条件下延迟驻留更改:

  • GICD_FCTLR2.RWC——resident wait during command
  • GICD_FCTLR2.RWS——resident wait during search

建议正常操作时不设置RWC和RWS位。 当通过写入GICR_VPENDBASER.Valid == 0使vPE非驻留时,GICR_VPENDBASER.PendingLast表示是否有vPE的剩余中断。如果在写入GICR_VPENDBASER.Dirty== 0,那么门铃仍然被屏蔽,软件必须在将来的某个时候使vPE再次驻留。 如果在GICR_VPENDBASER.Valid被清除时,写GICR_VPENDBASER.PendingLast == 1,那么GIC会优化驻留握手并且在不检查vPE是否还有中断的情况下屏蔽门铃中断。

7. SGIs

软件生成中断(Software Generated Interrupts, sgi)是一种处理器间中断,即从一个内核产生的中断发送到其他内核。系统中的每个核(包括vPE)都独立于其他核来处理一个SGI。SGI的优先级和其他设置对于每个核也是独立的。物理SGI是通过写入产生中断的核心的CPU接口中的系统寄存器来生成的。SGI是边沿触发的。

每一个核或者vPE最多可以拥有16个SGI。每一个SGI都有不同的中断号,范围是从0到15.

7.1 SGI编程

  • 物理SGI:控制物理的SGI需要使用每一个核对应的GICR中的寄存器
  • 虚拟SGI:控制虚拟的SGI,软件可以使用vSGI的ITS命令。软件也可以通过写vPE的virtual pending table来控制vSGI,然后发送一个VMAPP命令给GIC开辟对应的地址空间。在发送VMAPP命令后,软件不能向virtual pending table发起写请求用于尝试产生一个虚拟SGI。

7.2 SGI直接注入

通过将vPE和SGI-INTID写入gits_sgi寄存器,软件可以直接注入sgi。 gits_sgir寄存器总是使用GICD ACE5-Lite从属接口访问,即使在分布式系统中也是如此。 与物理sgi不同,vsgi没有活动状态,因此不需要去激活。如果vPE没有映射到GIC用来生成vSGI的ITS上,则该GIC生成调试错误。

7.3 SGI multichip

当芯片被连接时,物理sgi将根据目标亲和路由值,路由到目标芯片。虚拟sgi被路由到目标vPE,与vPE当前映射到的芯片无关。

8. PPIs

私有外设中断(PPI private peripheral interrupt)标识一个中断源,例如定时器,它是内核私有的,并且独立于另一个内核的相同源。ppi通常用于与特定核紧密耦合的外设。

连接到与一个核相关的PPI输入源的中断只被发送到该核。每个核独立于其他核处理一个PPI。PPI的设置对于每个核也是独立的。

一个PPI对一个核是唯一的。但是,其他核的ppi可以具有相同的INTID。每个目标核最多可拥有48个PPI,其中每个PPI在ID16-ID31或ID1056-ID1087范围内具有不同的INTID。要使用ID1056-ID1087范围,核必须支持GICv3.1扩展。

PPI信号默认为active-LOW电平敏感。但是,可以使用GICR_ICFGR1、GICR_ICFGR2E和GICR_ICFGR3E将PPI信号设置为电平敏感或边缘触发。

8.1 PPI信号

每个PPI都是一个物理中断信号,可以配置为电平敏感中断或边缘触发中断。物理PPI信号的两种配置是:

  • 电平敏感:当中断输入被断言时,中断处于挂起状态。Arm架构下PPI默认为active-LOW。但是可以更改这些默认设置。
  • 边沿触发:中断输入上的上升边界导致中断成为挂起。当中断被CPU接口激活时,挂起的位稍后被清除。

为使系统正确设置,必须对GICR_ICFGR1、GICR_ICFGR2E和GICR_ICFGR3E寄存器进行编程。

8.2 PPI编程

控制物理的PPI需要使用处理器核对应的GICR的寄存器

9. SPIs

共享外设中断(SPI shared peripheral interrupt)是由整个系统可访问的外设(如USB接收器)生成的,并且可以连接到多个核。SPI通常用于与特定核没有紧密耦合的外设。 可以对每个SPI进行编程,以针对特定核或任何核。激活一个核上的SPI将激活所有核的SPI。也就是说,GIC-700最多允许一个核激活SPI(不能由多个内核激活)。每个SPI的设置也在所有核之间共享。 SPI可以通过连接输入生成,也可以通过写入ACE5-Lite附属编程接口生成。GIC-700可以支持多达1984个spi,对应于spi Collators上的spi输入信号。每个SPI Collator有1024个信号的限制。可用spi的数量取决于实现的配置。第一个SPI的ID号是32。允许的ID值为32步,取值范围如下:

  • ID32-ID991
  • ID4096-ID5119

在配置GIC时,可以将部分或全部SPI分配为基于消息的SPI,也可以将所有SPI设置为物理SPI信号。如果将SPI ID分配为物理SPI输入信号,则软件仍然可以使用该SPI ID作为基于消息的SPI,前提是硬件确保SPI信号保持在表示非活动状态的逻辑级别。

可以配置每个SPI是在上升沿触发还是高电平敏感。

SPI Collator将基于线的中断转换为消息,以减少系统布线,并允许更积极的GIC时钟门控,以降低功耗。

SPI通过GICD寄存器地址空间进行编程,该地址空间一致地分布在所有已配置的芯片上,以向操作系统(OS)提供单一视图。

可以通过使用GICD_SETSPI_NSR或GICD_SETSPI_SR寄存器触发有效的SPI。

9.1 SPI信号

每个SPI都是一个物理中断信号,可以配置为电平敏感中断或边缘触发中断。

  • 电平敏感:当中断输入被断言时,中断正在挂起。SPI在默认情况下是active-HIGH的,但是可以更改这些默认设置
  • 边沿触发:中断输入上的上升边界导致中断成为挂起。当中断被CPU接口激活时,挂起的位稍后被清除。

要为系统设置正确的设置,必须对GICD_ICFGRn或GICD_ICFGRnE寄存器进行编程。 GIC-700在每个中断线输入上提供可选的同步器。GIC还提供返回信号spi_r,以便在跨域边界发送边缘触发中断时启用脉冲扩展器。

9.2 SPI路由以及1 of N模式

如果GICD_TYPER.No1N==0,则GIC700支持1 of N类型SPI中断。可以将SPI编程为针对多个核心,并且GIC700可以选择哪些核心接收SPI。 当相关的GICD_IROUTERn.Interrupt_Routing_Mode == 1, GIC为SPI选择合适的核心。 当GICD_IROUTERn.Interrupt_Routing_Mode == 0,则SPI路由到GICD_IROUTERn剩余字段指定的核心。 GIC700只发送SPI到已上电并启用相关中断组的内核。GIC700优先考虑被认为是活动的核,但如果没有活动的内核,则选择非活动的内核。 GIC700所做的选择由1 of N 模式的特点所控制或影响:

  • cpu_active signal:cpu_active信号是对应于特定核对应的GICR的输入。当cpu_active信号为LOW时,它向GIC表明该核处于透明的低功耗状态,并且如果没有其他可能的选项,则将其选择为SPI的目标。理想情况下,如果没有明确的软件干预,低功耗状态的核不会被唤醒,这样核就会在低功耗状态上花费更多的时间。通常,电源控制器或电源控制逻辑产生cpu_active信号。如果该信号在系统中不可用,则输入必须为高电平。

  • GICR_CTLR.DPGxx(disabled processor group):设置DPG位可以防止特定组的1 of N中断被发送到该核。尚未到达核的任何中断都将被GIC召回并重新确定优先级。

  • processor and GICD group enables and GICR_WAKER.ProcessorSleep:一个1 of N类型的中断在以下情况出现时,不会发给核:

    • 核处于asleep状态,通过GICR_WAKER.ProcessorSleep表明
    • 在核上,该SPI的中断分组被禁用
  • 中断类:这是GIC-700提供的具体实现中定义的特性。通过写入相关的GICR_CLASSR寄存器,可以将每个核分配给class 0或class 1。一个由GICD_IROUTERn.Interrupt_Routing_Mode编程为1 of N类型的SPI,可以通过GICD_ICLARn寄存器编程为类0,类1或二者兼有。缺省情况下,1 of N类型的spi是二者兼有的,因此中断类特性在缺省情况下是关闭的。系统可以将此分区用于任何目的,例如在Arm biglitletm系统中,所有的大核都可以在class 1中,而小内核可以在class 0中,允许根据它们需要的处理量对1 of N类型SPI进行分区。

  • GICD_CTLR.E1NWF:GICD_CTLR.E1NWF位控制如果没有其他可用的1 of N SPI目标,GIC700是否唤醒核心。GIC试图唤醒尽可能少的核心,只有在没有其他可能的目标唤醒能够接受1 of N中断时才唤醒一个核心。因此,GIC使用GICR_CTLR.DPG和GICR_CLASSR.Class位来确定是否有可以接受中断的内核处于唤醒状态。如果一个合适的核没有处于唤醒状态,那么GIC就唤醒一个核心。ARM强烈建议使用GICD_CTLR。在这种情况下,还必须设置GICR_CTLD.DPGx位用来指定一个核心是否可能及时接受一个特定的中断组。在找到一个核之前,GIC不会继续唤醒核。GIC-700使用两个通道来尝试找到1 of N中断的最佳位置,通过在以下之间使用轮询仲裁器:

    • 任何具有cpu_active信号为高的核,且对于中断是完全启用的,并且没有其他挂起的中断。
    • 为中断完全启用且没有高于1 of N中断优先级的中断正在处理的任何核.

    如果1 of N中断都没有可用的选项,中断将被分配给任何合法的目标,并定期重新评估,以确保它不会被其他具有相同优先级的spi排除在外。

9.3 multichip下SPI拥有者

SPI block的所有者是由GICD_CHIPR寄存器定义的。 可以在操作期间,通过重新编程相关的GICD_CHIPR寄存器,从芯片中删除SPI块并将它们添加到另一个芯片中。与所有路由表操作一样,必须轮询GICD_DCHIPR.PUP位以检查操作是否完成。在更改SPI块的所有者之前,必须确保GICD_CTLR组启用已清除,GICD_CTLR.RWP已经返回到0,并且SPI块在添加到另一个芯片之前从芯片中移除。

当从芯片中移除或添加SPI块时,所有与SPI块相关的编程都返回到重置状态。 不能更改在线芯片的SPI_BLOCK_MIN,因为结果是不可预测的。修改SPI_BLOCK_MIN需要以下步骤:

  1. 通过设置GICD_CHIPR.SocketState = 0使芯片脱机。
  2. 当芯片重新连接时修改SPI_BLOCK_MIN。

9.4 multichip下SPI操作

当建立路由表时,可以通过任何连接的芯片对spi进行编程,并且可以通过拥有spi的芯片的跨芯片接口对更新的存储值进行访问。 spi可以通过编程相关的GICD_IROUTERn寄存器路由到远程芯片。使用Affinity2或Affinity3来定位远程芯片,并且可以使用GICD_CFGID.AFSL来发现亲和级别。

如果SPI块中的SPI被发送到多个芯片,建议不要读写GICD_ISACTIVERn(E), GICD_ICACTIVERn(E), GICD_ISPENDRn(E)和GICD_ICPENDRn(E)寄存器。这些操作是低效的,这些寄存器不需立即操作。

可以通过写入GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR和GICD_CLRSPI_SR来设置SPI中断进入pending状态。为了高效操作,建议将源代码编写其芯片拥有的SPI id。如果您统中拥有其他SPI,则支持这些SPI id。

默认情况下,GIC700不保证写入中断pending bit的顺序。这种行为意味着在bresp信号断言后,正在设置的挂起位和正在由GIC处理的激活位之间存在竞争。要确保写操作总是传播到序列化点,需要设置GICD_FCTLR.POS = 1。


SPI Collator的SPI线总是连接到芯片上最低拥有的SPI。

例如,如果GICD_CHIPRn.SPI_BLOCK_MIN = 4, SPI Collator连接到芯片x驱动的SPI id从160开始(由(4 × 32) + 32 = 160计算)。

10. ITS

GIC700在每个芯片上最多支持32个ITS。每个ITS用于将外设发出的基于消息的中断转换成LPIs或者vLPIS。每个ITS都符合GICv3和GICv4.1体系结构,并负责将带有EventID和DeviceID的翻译请求映射到INTID和目标。如下图所示为物理INTID(pINTID)的ITS流程。

image-20241215131209561

为了减少内存流量并将中断延迟保持在最低限度,GIC-700在每个ITS中有三个双向集关联缓存:

  • DeviceID cache
  • EventID cache
  • Collection cache

如果缓存不需要ECC保护,可以将ECC从每个RAM中单独移除。

DeviceID通常是一个从PCIe RequestorID派生出来的不连续数字。为了确保这不会导致稀疏的DeviceID表和浪费内存,GIC700支持间接设备表(GITS_BASERn.Indirect = 1),其中第一级表指向可以在运行时分配的子表。

GIC700只使用内存支持的集合,这意味着在通过写入GITS_CTLR.Enable来启用ITS之前。启用后,必须为Device表、Collection表和ITS命令队列分配内存。为了遵从这个体系结构,软件必须预先将这些表清除为0,除了指向已清除的二级设备表的指针,除非这些表先前已被GIC-700填充。

当软件使用GICv4.1命令时,它必须在启用ITS之前提供一个指向芯片范围vPE表的指针。

对于所有配置,GITS_TYPER.PTA都是0,这意味着ITS命令中对处理器核的所有引用都是通过gicr_type.ProcessorNumber字段实现的。

10.1 ITS cache的控制、锁和测试

GIC700可以在EventID缓存中锁定某些中断转换。如果在缓存中丢失了翻译,则可能需要多次内存读取才能从内存中获取所需的数据。这种行为可能导致某些LPI无法接受的延迟范围。GIC700可以将某些翻译锁定到ITS缓存中,并提供以下保证:•锁定在ITS缓存中的中断总是命中且不需要任何翻译。

在更新GITS_BASERn寄存器时,自动管理ITS缓存并根据需要使其失效。因此,不需要软件干预。但是,为了帮助调试和集成测试,可以通过在GITS_FCTLR寄存器中设置相关位来强制适当的缓存失效。事件缓存的强制无效将放弃所有锁定项。

当软件提供DeviceID、EventID和正确的GITS_OPR.LOCK_TYPE(ITS lock =2)时,GITS_OPR和GITS_OPSR寄存器控制cache锁定。GIC会尝试执行cache锁定行为,并且在GITS_OPR寄存器中报告当前的状态。如果执行锁定成功,GITS_OPSR.REQUEST_COMPLETE == 1并且GITS_OPSR.REQUEST_PASS == 1。

每个缓存集都是双向关联的。每个缓存集中只能锁定一个条目。在GITS_OPSR中,任何试图在一个集合中同时锁定这两种方式的尝试都会报告为失败。还可以使用GITS_OPR寄存器来解锁被锁定的条目。

GITS_OPR寄存器有两个测试特性:

  • trial:通过向GITS_OPR写入DeviceID和EventID来测试映射当GITS_OPR.LOCK_TYPE = 1 (Trial)时。这导致ITS转换提供的DeviceID和或EventID对,并在GITS_OPSR中报告生成的翻译数据。GIC还报告翻译是否失败——GITS_OPSR.REQUEST_PASS == 0,如果遇到锁定的表项,则为GITS_OPSR.ENTRY_LOCKED。中断不会设置为挂起。
  • track:可以用来检测某个EventID和或DeviceID对的到达,GIC通过对GITS_OPSR.REQUEST_COMPLETE字段的设置来报告这些。

当任何GITS_OPR操作(除了Track)正在进行时,GIC 会设置GITS_OPSR.REQUEST_IN_PROGRESS位,并且不接受对GITS_OPR的更新,直到前一个操作完成。为了确保该操作被接受,建议在写入后读取GITS_OPR值。可以通过写入GITS_OPR.LOCK_TYPE ==track abort,来中止track操作。

10.2 MSI-64

MSI-64 Encapsulator可用于将DeviceID合并为ITS中GITS_TRANSLATER寄存器的单个内存访问写操作。

ITS将DeviceID/EventID对转换为LPI物理intid。

正常的MSI/MSI64写操作在低16位或32位数据中包含EventID。但是,必须使用不同的方法传输DeviceID。DeviceID通常直接派生自PCIe RequestorID或系统内存管理单元(SMMU)流。如果EventID大于16位,则16位MSI写入用零填充。

GIC700 ITS支持两种机制:

  • awuser_*_s signal:DeviceID通过边带用户信号到达。但是必须确保恶意软件不能直接或间接地使用与真实设备匹配的DeviceID对GITS_TRANSLATER寄存器执行访问。

  • MSI-64:当支持MSI-64时,ITS期望DeviceID位于对GITS_TRANSLATER寄存器64位写操作的高32bit。为了防止恶意软件访问GITS_TRANSLATER寄存器并欺骗任何设备,ARM建议将GITS_TRANSLATER寄存器移动到由管理程序保护的任意页面。GIC700使用两种方法来支持这一点:

    • MSI-64 Encapsulator将访问GITS_TRANSLATER地址的页面地址(由msi_translator_page绑定信号设置)修改为由msi64_translator_page信号设置的系统定义页面。

    • 当ITS共享一个ACE5-Lite附属端口时,its_transr_page_offset绑定信号允许GITS_TRANSLATER寄存器页移动到地址映射中的任何位置,以匹配与GICD地址映射重置无关的msi64_translator_page信号值。msi64_translator_page和its_transr_page_offset信号,或其中之一,不得位于任何其他GIC寄存器页的顶部。为了确保对软件隐藏这种映射方法,对GITS_TRANSLATER寄存器的所有访问都必须通过encapsulator或类似的嵌入式功能。

      image-20241215131231982

10.3 ITS命令和错误

需要测试一下unused的命令,cmd会停在这个unused cmd地方,无法继续往下执行,只能从新建立cmd queue

10.3.1 VMAPP命令

将vPEID对应的vPE表项与目标GICR以及虚拟LPI pending table映射起来。

VMAPP vPEID, RDbase, VPT_addr,VPT_size, V

10.3.2 VMAPI命令

将DeviceID和EventID定义的事件与vPEID定义的ITT表项映射起来(vINTID=EventID)

VMAPP DeviceID, EventID, Dbell_pINTID

需要注意的点:

  • vINTID=EventID ≥ 0x2000(有效的LPI中断)
  • 该命令等价于VMAPTI DeviceID, EventID,EventID, pINTID, vPEID
  • Dbell_pINTID要么是1023号中断要么是≥0x2000号中断(有效的LPI中断),如果门铃中断号是1023,则不会产生物理门铃中断

10.3.3 VMAPTI命令

将DeviceID和EventID定义的事件与vPEID定义的ITT表项映射起来

VMAPTI DeviceID, EventID, vINTID, Dbell_pINTID,vPEID

与VMAPI命令类似,只是EventID与vINTID可以不强制相同。

10.3.4 VINVALL命令

该命令用于确保vPEID相关的cache GICR信息与在内存中的LPI config table中的信息是一致的

VINVALL vPEID

10.3.5 VSYNC命令

该命令用于确保,所有针对vPEID的未完成的ITS操作,在其它ITS命令执行之前,都是全局可见的。在执行VSYNC之后,之前所有命令的效果必须应用于后续对GITS_TRANSLATER的写操作。

VSYNC vPEID

**硬件在这个地方不使用vPEID这个参数

10.3.6 VMOVP命令

这个命令用于更新vPEID和目标RDbase相应的在vPE表中的表项。软件必须使用SequenceNumber和ITSList,在多个ITS之间对VMOVP命令进行同步。

软件必须确保该命令不会执行在正在目标GICR上调度的vPEID,否则系统的行为将不可预测。

  • SequenceNumber:用于指定ITSList中包含的每个 ITS 所使用的同步点的标识
    • 如果GITS_TYPER.VMOVP == 0,那么SequenceNumber指定ITSList中包含的所有ITSs所使用的同步点的标识
    • 如果GITS_TYPER.VMOVP == 1,那么SequenceNumber全都保留为0
  • ITSList:用于指定包含在同步操作中的ITS实例:
    • ITSList中bit n代表ITS n
    • 如果相应的bit位为1,那么对应的ITS就包含在内

VMOVP vPEID, RDbase, SequenceNumber, ITSList


如果多个 ITS 控制同一 vPE 的中断,则必须在不同 ITS 之间协调移动该 vPE。这可以通过软件进行控制,使用本文详述的两种方法之一:

  • 当GITS_TYPER.VMOVP == 0时:
    • 必须为每个控制移动 vPE 中断的 ITS 发布 VMOVP 命令。每条命令都必须有一个共同的SequenceNumber。在所有 ITS 处理完之前使用该SequenceNumber的所有命令之前,该SequenceNumber不能用于其他 VMOVP 命令。
    • 为每个 ITS 发出的 VMOVP 命令包含受移动 vPE 影响的所有 ITS 的列表。这就是 ITS 列表。
    • 每个 ITS 收到的序列号必须与其他 ITS 收到的序列号顺序一致。
  • 当GITS_TYPER.VMOVP == 1时:
    • VMOVP 命令必须只在控制被移动 vPE 中断的一个 ITS 上发出。
    • 具体的设计实现负责传播更新的映射。

10.3.7 VMOVI命令

该命令更新 由 DeviceID 和 EventID 对应的ITT表项中的 vPEID 字段。它还将由 EventID 和 DeviceID 定义的事件转换为 vPEID 和 pINTID,并指示相应的GICR将中断的挂起状态移至由新 vPEID 对应的GICR,同时更新与事件相关的 ITE 以使用新 vPEID。

VMOVI DeviceID, EventID, vPEID,[Dbell_pINTID]

10.3.8 ITS命令错误

每个ITS检测各种命令错误和翻译错误,并在GICD中Armv8.2 ras的兼容错误记录中报告它们。 ITS记录错误综合征包括四组,每组在GITS_FCTLR寄存器中都有单独的启用项。下表显示ITS记录错误综合征组。

group control
ACE5-Lite subordinate interface write translation errors. Only when the ITS has a separate ACE5- Lite subordinate port. GITS_FCTLR.AEE (access error enabel)
Translation errors on incoming writes to GITS_TRANSLATER GITS_FCTLR.UEE (unmapped error enable)
Errors during commands GITS_FCTLR.CEE (command error enable)
Other errors such as memory system, or memory allocation errors None

11. LPIs

特定位置的外设中断(LPI locality-specific Peripheral interrupts)总是基于消息的,可以来自外设,也可以来自PCIe根复合体。 一个LPI只针对一个核。LPI是在外设写入ITS时生成的。ITS包含寄存器来控制LPI的生成和维护。ITS提供INTID转换,如果外设也存在SMMU,则允许这些外设由虚拟机直接拥有。

如果使用GICv3,ITS允许将中断转换为hypervisor的ID空间,而不是直接转换给虚拟机。如果使用GIC体系结构版本4.1,则hypervisor可以将ITS配置为直接发送中断。

11.1 LPI直接注入

当LPI被映射到一个vPE并且ITS使用一个VMAPI或者VMAPTI命令时,ITS可以直接注入一个LPI给vPE。

11.2 LPI multichip操作

GIC700不使用物理目标地址,所以GITS_TYPER.PTA == 0。因此,GIC-700使用GICR_TYPER.ProcessorNumber的值将所有LPI和命令路由到它们的目标。

GIC700拆分GITS_TYPER.ProcessorNumber值分为两个字段,Chip_ID和填充的线性片上核心编号。填充的片上核心数字段的宽度由max_pe_on_chip配置参数定义。该参数设置单个芯片上的最大内核或线程数通过GICD_CFGID.PEW可以发现线性片上核数域的宽度。例如,max_pe_on_chip = 17,则片上核数字段的下半部分的宽度为ceil[log2(17)] = 5位。因此,芯片1上第一个核的ProcessorNumber值为0x20,芯片1上第二个核的值为0x21,芯片2上第一个核的值为0x40。 下图显示了带有典型值的ProcessorNumber字段。

image-20241215131251546

如果软件试图访问不存在的芯片、offline或访问不存在的核,请求将被丢弃并通过ITS命令和翻译错误记录报告。

11.3 LPI caching

如果支持LPI,则GIC700支持每个芯片的单个LPI缓存,最多可达4个banks。

LPI缓存是基于LPI INTID的最低位的双向集合关联,并存储LPI属性表中的LPI属性。当每个LPI到达系统时,将检查相关集合的有效属性。如果选择了多个banks,那么GIC使用核心vPE号码的较低位来选择bank。

缓存对于挂起的LPI是完全关联的,这意味着在将任何内容发送到Pending表之前,LPI系统将填充几乎所有的cache line。GIC700没有针对具有相同INTID的lpi进行优化。然而,随着时间的推移系统对缓存进行重新排序。在某些情况下,这种行为可能导致无法有效地整理重复的中断。但是,减少Pending表的使用,可以在负载下获得更好的延迟边界。

这种缓存方法意味着优先级与传入的LPI相关联,并一直保持到它被服务为止。GIC不接受LPI属性表中的更改,直到相关的INV和SYNC命令通过ITS、GICR_INVLPIR或GICR_INVALLR执行。

最多可以同时运行16个INV命令。一旦INV的执行受到影响,并且任何匹配的中断已经从目标PE中被召回,GIC设置GICR_SYNCR.BUSY==0

在GIC发现中断在缓存中不存在之后,命令槽变得空闲,这可能需要根据负载和缓存内容进行线性搜索。如果缓存溢出,那么可能还需要检查Pending表中无效的ID。

GIC700在选择要保留在缓存中的数据时考虑优先级和启用。挂起的中断总是优先于未挂起的中断,因此不能保证最高优先级的中断数据始终存储在缓存中。

有关软件如何使用利用率引擎来优化LPI缓存内容的信息,请参阅GICD_UTILR寄存器。

12. 内存访问和属性

LPI和ITS的翻译和属性位于内存表中,这些内存表的位置在寄存器中定义,寄存器指定了它们的基址、大小和访问属性。ARM建议将所有表放在普通内存中。所有ITS表都是私有的,在分配之后,只有GIC访问它们。但是,LPI属性表和ITS命令队列由内核写入,由GIC读取。 下表显示了用于GIC生成的内存事务的acache和adomain信号映射。

访问类型 寄存器 映射控制位
LPI property table GICR_PROPBASER GICD_FCTLR2.DCC
LPI pending table GICR_PENDBASER GICD_FCTLR2.DCC
LPI virtual property table ITS VMAPP GICD_FCTLR2.DCC
LPI virtual pending table ITS VMAPP GICD_FCTLR2.DCC
vPE configuration table GICR_VPROBASER and GITS_BASER2 GICD_FCTLR2.DCC
ITS device table GITS_BASER0 GITS_FCTLR.DCC
ITS translation table GITS_BASER0 GITS_FCTLR.DCC
ITS collection table GITS_BASER1 GITS_FCTLR.DCC
ITS command queue GITS_CBASER GITS_FCTLR.DCC

13. 电源管理

GIC700可以通过系统电源控制器下电。GIC还支持电源控制器为GIC服务的核下电。GICR_WAKER和GICR_PWRR寄存器为与电源管理相关的函数提供控制位。

13.1 Redistributor电源管理

在复位时,GICR默认是下电的。为了让GICR上电,软件需要使用GICR_PWRR寄存器。

GICR_PWRR可以被核或者GICR操作,用于控制GICR的电源管理。

如果是核进行操作,每一个核必须将它对应的GICR_PWRR.RDPD=0 并且 GICR_PWRR.RDAG = 0,用于确保GICR上电。除此之外,单个核也可以帮连接在一个GICR上的所有核来上电GICR。它需要写GICR_PWRR.RDPD=0 并且 GICR_PWRR.RDAG = 1。

// 下电操作序列
power off:
    //check group not transitioning
    repeat
    until(GICR_PWRR.RDGPD == GICR_PWRR.RDGPO)

    // write to power the CPU off
    GICR_PWRR.RDPD = 1
// 上电操作序列
power on:
    repeat
        // check group not transitioning
        repeat
        until(GICR_PWRR.RDGPD == GICR_PWRR.RDGPO)

        // write to power the CPU on
        GICR_PWRR.RDPD = 0

        //check access, if RDPD == 0 then powered on
    until(GICR_PWRR.RDPD == 0)

13.2 处理器核电源管理

GIC架构定义了一个编程序列用于安全的将连接到GIC700的核进行下电。

这个下电流程会用到GICR_WAKER.ProcessorSleep控制位。当cluster中所有的核都使用架构定义的流程进行下电操作之后,可以对cluster的GIC stream接口进行power gate。

在核下电之前,必须设置GICR_WAKER.ProcessorSleep位为1。核必须轮询GICR_WAKER.ChildrenAsleep位,确保在核的GIC stream接口上没有未完成的传输。

为了确保在核下电的过程中没有中断,通常下电的流程如下:

  1. 在核内启用中断屏蔽
  2. 禁用CPU interface
  3. 禁用CPU interface的中断旁路bypass功能

当一个核被下电并且GICR_WAKER.ProcessorSleep位为1时,如果GIC700接收到一个中断,并且该中断的目标就是当前被下电的核,那么Wake request模块会断言对应核的wake_request信号。wake_request信号必须连接到系统电源控制器。

正常情况下不能直接设置GICR_WAKER.ProcessorSleep位为1,除非核进入的电源状态无法使用GIC stream接口来唤醒,只能让GIC700通过电源控制器来唤醒。

中断可以让执行WFI或者WFE指令进入低功耗状态的核离开低功耗状态。

13.3 P-channel和电源控制

可以使用P-channel将chip从系统中隔离出来

p-channle有如下几个状态:

  • RUN(pstate信号==0x0):正常功能模式
  • CONFIG(pstate信号==0x9):GIC不会发送任何跨chip消息。它会接收发送来的消息但是不会处理它们
  • OFF(pstate信号==0xf):GIC不会发送任何跨chip消息,并且不会接收任何发送来的消息。icrdtready信号被拉低,用于阻止任何对GIC的访问

在CONFIG和OFF状态下,通常发送到另一个芯片的寄存器访问会在本地进行。因此,路由表寄存器读取本地版本,而不是路由表所有者的副本。对于远程拥有的spi也是如此。因此,在这两种P-Channel状态下保存和恢复GICD寄存器值是安全的。 通过设置pstate信号的初始值,GIC可以在RUN或OFF状态下退出复位。如果已经保存了寄存器值并打算恢复它们,那么在尝试恢复任何SPI寄存器之前,必须使用OFF状态并首先恢复路由表。

13.4 SPI RAM保存

如果GIC经常掉电和复位,那么在spi很多的情况下,保存和恢复状态会非常耗时。在reset退出时,spi_ram_retained信号使GIC能够信任ram中包含的SPI编程状态。

u_spi_ram0和u_spi_ram1会保存以下寄存器的状态:

  • GICD_IGROUPRn(E)
  • GICD_ISENABLERn(E)
  • GICD_ISPENDRn(E)
  • GICD_ISACTIVERn(E)
  • GICD_IPRIORITYRn(E)
  • GICD_ICFGRn(E)
  • GICD_IGRPMODRn(E)
  • GICD_NASCRn(E)
  • GICD_IROUTERn(E)
  • GICD_IERR

GIC700不会驱动spi_ram_retained信号。因此在GIC进入QSTOPPED状态之后,必须有其它逻辑驱动RAM retention信号


进入SPI RAM保存步骤:

  1. 确保GIC处于IDLE状态:
    1. 所有的PEs完成GICR_WAKER.ProcessorSleep握手
    2. 给所有的中断分组清除GICD_CTLR中的使能位,并且轮询直到GICD_CTLR.RWP == 0
  2. 将所有的SPI Collators设置为Q-STOPPED状态。这一步确保没有更多的中断从SPI Collators发送出来。SPI Collators拒绝任何不在空闲状态的中断。根据系统配置,系统可能需要设置一些外部中断屏蔽。
  3. 通过GICD的Q-channel接口将GIC设置进入Q_STOPPED状态
  4. 系统驱动必要的信号到SPI ram,将它们放入retention。系统可以使用RAM I/O边带信号将保留信号连接到RAM实例。

从SPI RAM保存中恢复的步骤:

  1. GIC上电
  2. 在退出复位前驱动spi_ram_retained信号为高。只有在复位时才能改变spi_ram_retained信号状态
  3. GICD退出复位
  4. 像正常一样重新编程GIC,除了所有与spi相关的寄存器都保留其值。软件必须对所有GICR和通用的非缩放寄存器(如GICD_CTLR)进行编程。
  5. 通过GICD的Q-channel接口将GIC设置进入Q-RUN状态
  6. 将SPI Collator设置为Q-RUN状态
  7. 给所有的中断分组设置GICD_CTLR中的使能位,并且轮询直到GICD_CTLR.RWP == 0
  8. 唤醒所有的PEs

14. 性能检测单元(PMU)

GIC700包含了一个PMU用于计数主要的GIC事件,主要包括GICD的事件和对ITS block的任何配置。PMU不会追踪GCI的事件。软件可以通过记录核中断服务的调用的次数来计数PPI和SGI中断。

PMU有5个计数器,拥有快照功能和溢出中断。

安全和非安全中断会被一起计数。因此非安全的软件默认情况下不能访问GICP(PMU)的寄存器空间,安全的软件可以访问。想要让非安全的软件可以访问GICP(PMU)寄存器空间可以有以下两种方式:

  • 将GICD_SAC.GICPNS位置1
  • 将gicp_allow_ns信号拉高

软件可以通过设置GICP_INTENSET0的相关比特位来使能和禁用每个计数器的溢出中断。

当溢出中断使能时,在以下情况下会产生溢出中断:

  • 对任意计数器写GICP_OVSSET0寄存器
  • 任意一个使能的计数器发生了溢出

GICP_OVSSET0寄存器和GICP_OVSCLR0寄存器可以用于保存和恢复操作以及测试pmu中断线是否正确连接。

pmu_int信号可以用于触发外部逻辑,例如,触发捕获数据的读取。 或者,通过将有效的SPI ID编程到GICP_IRQCR.SPIID字段,pmu_int信号SPI按照正常的SPI编程在内部交付。


每个PMU计数器GICP_EVCNTRn都有相应的GICP_SVRn快照寄存器。 在快照事件中,所有五个计数器都被复制到它们的备份寄存器中,以便在较长的时间内复制所有一致的数据。

快照事件是:

  • 在4阶段sample_req / sample_ack信号外部握手上的握手
  • 对GICP_CAPR.CAPTURE位写入1
  • 当GICP_EVTYPERn.OVFCAP置位时,被启用的计数器的溢出。

只有一组快照寄存器,因此数据在多个捕获事件中被替换。

博主已关闭本页面的评论功能