一、前言
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个版本:V1V4:V1是最老的版本,已经被废弃了;V2V4目前正在被大量地使用。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)的数量