一、前言

OpenAtom OpenHarmony(以下简称“OpenHarmony”)采纳多内核架构,反对Linux内核的规范零碎、LiteOS-A的小型零碎、LiteOS-M的轻量零碎。

其中LiteOS-A要求设施具备肯定的解决能力,比照LiteOS-M,LiteOS-A反对以下个性:
(1)MMU反对:通过MMU反对内核态和用户态拆散,反对虚构单元;
(2)反对独立过程:调度对象别离为过程、线程;
(3)反对文件系统:包含虚构文件和块设施等;
(4)反对更简单的IPC:包含LiteIPC等;
(5)反对多核调度:反对双核MCU,反对双核调度;
(6)反对POSIX3接口:为APP开发提供更多帮忙。

LiteOS-A内核个性都是建设在CPU硬件的根底上,而中断控制器在反对LiteOS-A内核的CPU中施展着微小的作用:它治理和管制可屏蔽中断并对可屏蔽中断进行优先权断定,缩小CPU的负载,使得CPU更加专一于计算。

在嵌入式畛域,ARM公司提供的芯片目前是市场的支流,OpenHarmony LiteOS-M内核目前反对的ARM公司的Cortex-M系列的芯片,而LiteOS-A内核反对的则是ARM公司性能更弱小的Cortex-A/R系列的芯片,GIC是ARM公司给Cortex-A/R系列芯片提供的一个中断控制器,在移植OpenHarmony LiteOS-A内核到特定板子的实际中,咱们遇到了很多GIC中断控制器相干的技术问题,所以须要深刻理解ARM体系架构下GIC中断控制器的原理和应用办法,特此总结并共享给各位网友。

二、GIC控制器概述

1、GIC简介
GIC是ARM公司给Cortex-A/R核提供的一个中断控制器,相似Cortex-M中的NVIC。目前GIC有4个版本:V1~V4:V1是最老的版本,曾经被废除了;V2~V4目前正在被大量地应用。

GIC V2是给ARMv7-A架构应用的,比方Cortex-A5,Cortex-A7、Cortex-A9、Cortex-A15等,V3和V4是给ARMv8-A/R架构应用的,也就是64位芯片应用的。GIC V2最多反对8个核。ARM会依据GIC版本的不同研发出不同的IP核,半导体厂商间接购买对应的IP核即可,比方ARM针对GIC V2就开发出了GIC400中断控制器IP核。留神,具体产品是GIC400,设计规范是V2。当GIC接管到内部中断信号当前汇报给ARM内核,然而ARM内核只提供四个信号给GIC来汇报中断状况:VFIQ、VIRQ、FIQ和IRQ,他们之间的关系如图所示:

在图中,GIC接管泛滥的内部中断,并对其进行解决,最终只通过四个信号报给 ARM 内核,这四个信号的含意如下:
● VFIQ: 虚构疾速 FIQ
● VIRQ: 虚构内部 IRQ
● FIQ:  疾速中断 IRQ
● IRQ:  内部中断 IRQ

2、GIC整体实现

下图左侧局部是中断源,两头局部是GIC控制器,最右侧是中断控制器向处理器内核发送中断信息。咱们重点要看的是两头的 GIC 局部,GIC 将泛滥的中断源分为三类: ①SPI(Shared Peripheral Interrupt),共享中断,即所有Core共享的中断,内部中断都属于SPI中断。比方按键中断、串口中断等,这些中断所有的Core都能够解决,不限定特定Core。

在图中,每个SPI设计是共享的,在SMP零碎中每个SPI都须要连贯一个线到各个CPU中。 
②PPI(Private Peripheral Interrupt),公有中断,GIC是反对多核的,每个核有本人独有的中断,须要指定的外围解决。

在图中,每个CPU都有属于本人的PPIs,对应关系是1对1。
 ③SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR写入数据来触发,零碎应用SGI中断来实现多核之间的通信。

在图中,SGI是软件(软件运行在CPU上)触发,所以SGI中断源头是各个CPU上的利用,另外SGI和PPI一样,每个CPU都有属于本人的SGI,所以必须指定CPU。

3、中断 ID

中断源有很多,为了辨别不同的中断源要给它们调配惟一ID,也就是中断ID。每一个CPU最多反对1020个中断ID,中断ID号为ID0~ID1019。1020 个ID蕴含了PPI、SPI和SGI,那么这三类中断是如何调配这 1020 个中断 ID 的呢?调配如下:
● ID0~ID15:这16个ID调配给SGI
● ID16~ID31:这16个ID调配给PP
● ID32~ID1019:这988个ID调配给SPI,像GPIO中断、串口中断等这些内部中断

至于具体到某个ID对应哪个中断,那就由半导体厂商依据理论状况去定义。比方 I.MX6U 的总共应用了128个中断ID,加上后面属于PPI和SGI的32个ID,I.MX6U的中断源共有128+32=160个。

4、GIC逻辑模块

GIC架构分为了两个逻辑块:Distributor和CPU Interface,也就是散发器端和CPU接口端。Distributor(散发器端):参考GIC整体实现的图,此逻辑块负责解决各个中断事件的散发问题,确定中断事件应该发送到哪个CPU Interface下来。散发器收集所有的中断源,能够管制每个中断的优先级,它总是将优先级最高的中断事件发送到CPU接口端。散发器端要做的次要工作如下:
① 全局中断使能管制
② 管制每一个中断的使能或者敞开
③ 设置每个中断的优先级
④ 设置每个中断的指标处理器列表
⑤ 设置每个内部中断的触发模式:电平触发或边际触发
⑥ 设置每个中断属于组0还是组1,此设置波及到另外一个畛域平安畛域

CPU Interface(CPU接口端):CPU接口端和CPU Core相连接,因而每个CPU Core都能够在GIC中找到一个与之对应的CPU Interface。CPU接口端是散发器和CPU Core之间的桥梁,CPU接口端次要工作如下:
① 使能或者敞开发送到CPU Core的中断请求信号
② 应答中断
③ 告诉中断解决实现
④ 设置优先级掩码,通过掩码来设置哪些中断不须要上报给CPU Core
⑤ 定义抢占策略
⑥ 当多个中断到来的时候,抉择优先级最高的中断告诉给CPU Core

三、GIC400原理

1、整体框架图
GIC-400实现了以下的中断类型:
● 16个软件产生的中断(SGI)
● 每个处理器有6个内部公有外设中断(PPI)
● 每个处理器有1个外部PP
● 可配置的共享外设中断(SPI)的数量

GIC-400的BD如下图所示,GIC-400从中断输出信号中检测PPI和SPI。每个处理器的每个PPI中断ID都有一个信号。每个SPI中断ID只有一个输出信号,与SoC中处理器的数量无关。SGI没有输出信号,在GIC-400中应用AXI编程接口生成。

2、输出信号

上图中右边就是来自外设的interrupt source输出信号。分成两种类型,别离是PPI(Private Peripheral Interrupt)和SPI(Shared Peripheral Interrupt)。PPI中断信号是CPU公有的,每个CPU都有其特定的PPI信号线。而SPI是所有CPU之间共享的。通过寄存器GICD_TYPER能够配置SPI的个数(最多480个)。GIC-400反对多少个SPI中断,其输出信号线就有多少个SPI interrupt request signal。同样的,通过寄存器GICD_TYPER也能够配置CPU interface的个数(最多8个),GIC-400反对多少个CPU interface,其输出信号线就提供多少组PPI中断信号线。一组PPI中断信号线包含6个理论的signal:

(1)nLEGACYIRQ信号线。对应interrupt ID 31,在bypass mode下(这里的bypass是指bypass GIC functionality,间接连贯到某个processor上),nLEGACYIRQ能够间接连到对应CPU的nIRQCPU信号线上。在这样的设置下,该CPU不参加其余属于该CPU的PPI以及SPI中断的响应,而是特地为这一根中断线服务。

(2)nCNTPNSIRQ信号线。来自Non-secure physical timer的中断事件,对应interrupt ID 30。
(3)nCNTPSIRQ信号线。来自secure physical timer的中断事件,对应interrupt ID 29。
(4)nLEGACYFIQ信号线。对应interrupt ID 28。概念与nLEGACYIRQ信号线雷同。
(5)nCNTVIRQ信号线。对应interrupt ID 27。Virtual Timer Event,和虚拟化相干,这里不予形容。
(6)nCNTHPIRQ信号线。对应interrupt ID 26。Hypervisor Timer Event,和虚拟化相干,这里不予形容。

3、输入信号

所谓输入信号,就是GIC和各个CPU间接的接口,这些接口包含:
(a)触发CPU中断的信号。nIRQCPU和nFIQCPU信号线,次要用来触发ARM  CPU进入IRQ mode和FIQ mode。
(b)Wake up信号。nFIQOUT和nIRQOUT信号线,帮助ARM CPU的电源治理模块,用来唤醒CPU。
(c)AXI slave interface signals。AXI(Advanced eXtensible Interface)是一种总线协定,属于AMBA标准的一部分。通过这些信号线,ARM CPU能够和GIC硬件block进行通信(例如寄存器拜访)。

4、触发门路

上面总结下SGI、PPI、SPI三种类型中断的触发门路:
SGI(ID0-ID15):是由CPU外部软件触发,所以从CPU CORE-->CPU interface-->Distributor-->CPU Interface-->CPU CORE。

PPI(ID16-ID31):是由内部器件触发,从Peripheral-->Distributor-->CPU interface-->CPU  CORE。

SPI(ID32-ID1019):也是内部器件触发,从Peripheral-->Distributor-->CPU interface-->CPU  CORE。

5、中断状态迁徙图

对于每一个中断而言,有以下4个状态:
inactive:中断处于有效状态。
pending:中断处于无效状态,然而cpu没有响应该中断。
active:cpu在响应该中断。
active and pending:cpu在响应该中断,然而该中断源又发送中断过去。
PS:对于电平触发的中断而言,一个中断的解决阶段也会有active and pending的阶段,这是比拟非凡的。

上面是官网提供中断迁徙的条件和场景阐明,要留神的是文中either示意转移条件满足其一即可:

四、GIC400寄存器

1、GIC-400寄存器地图
所有GIC-400寄存器都有短名称。在这些名称中,前三个字符是GIC,第四个字符示意 GIC-400 的功能块:
● GICD_     分配器
● GICC_     中央处理器接口
● GICH_     虚构接口管制块
● GICV_     虚构CPU接口。
GIC-400寄存器是内存映射的,下表列出了地址范畴: 

内存映射的含意:对于ARM体系架构而言,IO和内存是对立编制,寄存器会占用内存的地址范畴。至于GIC-400寄存器首地址映射在哪个内存地址上,这是硬件厂商设计,并通过CP15协处理器来获取。

2、具体寄存器

上面解释几个经典的寄存器,更多的寄存器请参考ARM出品的官网文档。

(1)GICD_CTRL寄存器

寄存器GICD_CTRL各个位的含意如下:

GICD_CTRL_reserved_0:保留。

EnableGrp1:Global enable for forwarding pending Group 1 interrupts from the Distributor to the CPU interfaces:

EnableGrp0:Global enable for forwarding pending Group 0 interrupts from the Distributor to the CPU interfaces:

个人见解:第一,EnableGrp1和EnableGrp0是全局开关,第二,这是Distributor侧的开关,至于CPU interfaces侧持续参考其它寄存器。

(2)2 GICD_TYPER


GICD_TYPER_reserved_0:个人见解:保留字段,不应用

LSPI:If the GIC implements the Security Extensions, the value of this field is the maximum number of implemented lockable SPIs, from 0 (0b00000) to 31 (0b11111), see Configuration lockdown on page 4-82. If this field is 0b00000 then the GIC does not implement configuration lockdown. If the GIC does not implement the Security Extensions, this field is reserved.

 个人见解:在不使能ARM平安体系的性能前提下,此处保留,平安体系的性能临时不应用。

SecurityExtn:
Indicates whether the GIC implements the Security Extensions.0 Security Extensions not implemented.1 Security Extensions implemented.

个人见解:ARM平安体系的性能,使能后,0组和1组含意不一样,具体须要另外篇幅来论述

GICD_TYPER_reserved_1:

CPUNumber:Indicates the number of implemented CPU interfaces. The number of implemented CPUinterfaces is one more than the value of this field, for example if this field is 0b011, thereare four CPU interfaces. If the GIC implements the Virtualization Extensions, this is also the number of virtual CPU interfaces.

个人见解:the number of implemented CPU interfaces = CPUNumber+1,域值是从0开始,含意却是从1开始。

ITLinesNumber:Indicates the maximum number of interrupts that the GIC supports. If ITLinesNumber=N, the maximum number of interrupts is 32(N+1). The interrupt ID range is from 0 to (number of IDs - 1).

For example: 0b00011 Up to 128 interrupt lines, interrupt IDs 0-127.

The maximum number of interrupts is 1020 (0b11111). See the text in this section for more information. Regardless of the range of interrupt IDs defined by this field, interrupt IDs 1020-1023 are reserved for special purposes.

个人见解:最大的中断数量是32*(ITLinesNumber +1)

(3)GICD_IDDR

ProductID:

个人见解:值0x020意味着GIC-400

GICD_IDDR_reserved_0:

个人见解:reserved

Variant:An IMPLEMENTATION DEFINED variant number. Typically, this field is used to distinguishproduct variants, or major revisions of a product.

个人见解:产品主版本号,0x2代表版本为2.0

Revision:An IMPLEMENTATION DEFINED revision number. Typically, this field is used to distinguish minor revisions of a product.

个人见解:产品小版本号,0x1代表修订版为r0p1。

Implementer:Contains the JEP106 code of the company that implemented the GIC Distributor: Bits [11:8] The JEP106 continuation code of the implementer. For an ARM implementation, this field is 0x4. Bits [7] Always 0. Bits [6:0] The JEP106 identity code of the implementer. For an ARM implementation, bits[7:0] are 0x3B.

个人见解:实现CPU接口的公司代码,0x43B代表ARM公司。

(4)GICD_IGROUPn_0


Group_Status_Bits:The GICD_IGROUPR registers provide a status bit for each interrupt supported by the GIC.

Each bit controls whether the corresponding interrupt is in Group 0 or Group 1. Accessible by Secure accesses Only.

For each bit:
0 The corresponding interrupt is Group 0.
1 The corresponding interrupt is Group 1.

For interrupt ID m, when DIV and MOD are the integer division and modulo operations:
a. the corresponding GICD_IGROUPRn number, n, is given by n = m DIV 32
b. the offset of the required GICD_IGROUPR is (0x080 + (4*n))
c. the bit number of the required group status bit in this register is m MOD 32.

个人见解:
① 组状态位,对于每个位:“0”示意相应的中断为Group 0;“1”示意相应的中断为Group 1。
② 问:对于一个中断,如何设置它的Group?答:首先找到对应的GICD_IGROUPRn寄存器,即n是多少?还要确定应用这个寄存器里哪一位。对于interrtups ID m,如下计算:n = m DIV 32,GICD_IGROUPRn里的n就确定了;
③ GICD_IGROUPRn在GIC外部的偏移地址是多少?答:0x080+(4*n),这个信息是为了定位到具体寄存器。
④ 应用GICD_IPRIORITYRn中哪一位来示意?答:bit = m mod 32。

⑤ GICD_IGROUPn_0只是GICD_IGROUPn寄存器组的第一个,总共有4个寄存器:GICD_IGROUPn_0到GICD_IGROUPn_3

(5)GICD_ISENABLER0


Set_Enable_Bits:
The GICD_ISENABLERs provide a Set-enable bit for each interrupt supported by the GIC. For SPIs and PPIs, each bit controls the forwarding of the corresponding interrupt from the Distributor to the CPU interfaces:

Reads:
0 Forwarding of the corresponding interrupt is disabled.
1 Forwarding of the corresponding interrupt is enabled.

Writes:
0 Has no effect.
1 Enables the forwarding of the corresponding interrupt.

After a write of 1 to a bit, a subsequent read of the bit returns the value 1. For interrupt ID m, when DIV and MOD are the integer division and modulo operations:
a.the corresponding GICD_ISENABLER number, n, is given by n = m DIV 32
b.the offset of the required GICD_ISENABLER is (0x100 + (4*n))
c.the bit number of the required Set-enable bit in this register is m MOD 32.

个人见解:
① 对于SPI和PPI类型的中断,每一位管制对应中断的转发行为:从Distributor转发到CPU interface:读:“0”示意以后是禁止转发的;“1”示意以后是使能转发的;写:“0”示意有效;“1”示意使能转发。
② 对于一个中断,如何找到GICD_ISENABLERn并确定相应的位?
答:对于interrtups ID m,如下计算:n = m DIV 32,GICD_ISENABLERn里的n就确定了;

GICD_ISENABLERn在GIC外部的偏移地址是多少?计算方法为0x100+(4*n),因为一个寄存器大小为4个字节。

应用GICD_ISENABLERn中哪一位来示意?计算方法为?bit = m mod 32。

③ 这里的开关也是Distributor侧的开关,GICV硬件设计思维和软件设计思维相似。

④ GICD_ISENABLER0是此类寄存器组的第一个,总共是4个。

(6)GICD_ICFGR0


Int_Config:
The GICD_ICFGRs provide a 2-bit Int_config field for each interrupt supported by the GIC.

For Int_config[1], the most significant bit, bit [2F+1], the encoding is:
0 Corresponding interrupt is level-sensitive.
1 Corresponding interrupt is edge-triggered.

Int_config[0], the least significant bit, bit [2F], reservedFor
For SGIs: Int_config[1] Not programmable, RAO/WI.
For PPIs: Int_config[1] Not programmable, RAZ/WI.
For SPIs: Int_config[1] this bit is programmable.

A read of this bit always returns the correct value to indicate whether the corresponding interrupt is level-sensitive or edge-triggered.

For interrupt ID m, when DIV and MOD are the integer division and modulo operations:
a. the corresponding GICD_ICFGR number, n, is given by n = m DIV 16
b. the offset of the required GICD_ICFGRn is (0xC00 + (4*n))
c. the required Priority field in this register, F, is given by F = m MOD 16, where field 0 refers to register bits [1:0], field 1 refers to bits [3:2], up to field 15 that refers to bits [31:30].

个人见解:对于每一个中断,都有对应的2位数据用来形容:它的边际触发,还是电平触发。对于Int_config [1](即高位[2F + 1]),含意为:“0”示意相应的中断是电平触发;“1”示意相应的中断是边际触发。对于Int_config [0],即低位[2F],是保留位,这一位就是当前才应用。


五、问题与倡议

1、ARM芯片设计了FIQ和IRQ的2个解决模式,移植过程中没有用到FIQ。
2、虚构中断相干的性能也没有用到。
3、平安相干的中断性能后期咱们也没有用到,后续在可信执行环境中会用到。
4、如果代码对中断爱护写得不好的话,会呈现Systick产生屡次中断,中断状态为active &pending,在移植过程中OpenHarmony版本不反对嵌套中断。
5、中断解决分为边际触发解决和电平触发解决。这就给咱们不同的利用性能提供了抉择,使得咱们能够在不同个工作下抉择适宜的模式,边际触发实用于对工夫要求高的,比方中断中有计数之类的(GATE门控地位1时),而电平触发则适宜报警装置。
6、在基于ARM的嵌入式应用零碎中,存储系统通常是通过系统控制协处理器CP15实现的。ARM处理器应用协处理器15(CP15)的寄存器来管制cache、TCM和存储器治理。CP15蕴含16个32位的寄存器,其编号为0~15,具体请参考ARM官网文档。
7、givc2将中断分成了group0和group1,默认状况下,所有中断都是组0中断,并应用IRQ向连贯的处理器发送信号中断请求。集体了解如果都改为组1也是没有问题的,然而没有验证。
8、GIC-400通用初始化流程:
(1)设置distributor和CPU interface寄存器组的基地址;
(2)读取GICD_TYPER寄存器,计算以后GIC最大反对多少个中断源;
(3)初始化distributor:
a.disable distributor;
b.设置中断分组;
c.设置SPI中断的路由;
d.设置SPI中断的触发类型;
e.disactive和disable所有中断源;
f.enable distributor;
(4)初始化CPU Interface:
a.设置GIC_CPU_PRIMASK,设置中断优先级mask level;
b.enable CPU interface;

六、总结

本篇文章从GIC控制器概述、GIC400原理、GIC400寄存器等方面介绍了OpenHarmony内核之根底硬件——中断控制器GIC400的内容,心愿开发者能从中学有所获,学以致用。