ARM GIC(四) GIC V3 中断线映射&关键寄存器配置 分析笔记。

中断生命周期

在这里插入图片描述

  • generate:外设发起一个中断
  • distribute:distributor对收到的中断源进行仲裁,然后发送给对应的cpu interface
  • deliver:cpu interface将中断发送给core
  • activate:core通过读取 GICC_IAR 寄存器,来对中断进行认可
  • priority drop: core通过写 GICC_EOIR 寄存器,来实现优先级重
  • deactivation:core通过写 GICC_DIR 寄存器,来无效该中断

整个中断生命周期,distribute和deliver分发机制依赖于中断配置,从activate到deactivation均为中断处理函数工作内容。上几篇博文已经详细介绍了GIC 架构基础,稍微有些抽象。接下来尝试从源码和寄存器手册分解TF-A GIC V3驱动源码,进一步理解arm gic中断生命周期全流程,理解中断分组,FIQ和IRQ中断区别。

GIC寄存器

gicv3中,多了很多寄存器,而且对寄存器,提供了2种访问方式,一种是memory-mapped的访问另一种是系统寄存器访问

memory-mapped访问的寄存器:

  • GICC: cpu interface寄存器
  • GICD: distributor寄存器
  • GICH: virtual interface控制寄存器,在hypervisor模式访问
  • GICR: redistributor寄存器
  • GICV: virtual cpu interface寄存器
  • GITS: ITS寄存器

系统寄存器访问的寄存器:

  • ICC: 物理 cpu interface 系统寄存器
  • ICV: 虚拟 cpu interface 系统寄存器
  • ICH: 虚拟 cpu interface 控制系统寄存器

下图是gicv3中,各个寄存器,所在的位置。

在这里插入图片描述
对于系统寄存器访问方式的gic寄存器,是实现在core内部的。而memory-mapped访问方式的gic寄存器,是在gic内部的。

gicv3架构中,没有强制,系统寄存器访问方式的寄存器,是不能通过memory-mapped方式访问的。也就是ICC, ICV, ICH寄存器,也是可以实现在gic内部,通过memory-mapped方式去访问。但是一般的实现中,是没有这样的实现的。

下图是ICC的系统寄存器,和memory-mepped方式寄存器的对应关系的一部分,更多的就要查看gicv3的spec。
在这里插入图片描述
那么,问题来了,gicv3中,为什么选择将cpu interface,从gic中抽离,实现在core内部?为什么要将cpu interface的寄存器,增加系统寄存器访问方式,实现在core的内部?这样做,是有什么好处?

我认为,gicv3的上述安排,第一是为了软件编写能够简单,通用;第二是为了让中断响应能够更快。

首先要先了解,在gic的寄存器中,哪一些寄存器,是会频繁被core所访问的,哪一些寄存器,是不会频繁被core所访问的。毫无疑问,cpu interface的寄存器,是会频繁被core所访问的,因为core需要访问cpu interface的寄存器,来认可中断,来中断完成,来无效中断。而其他的寄存器,是配置中断的,只有在core需要去配置中断的时候,才用访问得到。有了这个认识,那么理解之后我所讲述的,就比较容易了。

在gicv2中,cpu interface的寄存器,是实现在gic内部的,因此当core收到一个中断时,会通过axi总线(假设memory总线是axi总线),去访问cpu interface的寄存器。而中断在一个soc系统中,是会频繁的产生的,这就意味着,core会频繁的去访问gic的寄存器,这样会占用axi总线的带宽,总而会影响中断的实时响应,而且core通过axi总线去访问cpu interface寄存器,延迟,也比较大

在gicv3中,将cpu interface从gic中抽离出来,实现在core内部,而不实现在gic中。core对cpu interface的访问,通过系统寄存器方式访问,也就是使用msr,mrs访问,那么core对cpu interface的寄存器访问,就加速了,而且还不占用axi总线带宽。这样core对中断的处理,就加速了

cpu interface与gic之间,是通过专用的AXI-stream总线,来传输信息的,这样也不会占用AXI总线的带宽。

GIC V2和V3差别

GIC,是arm为了实现复杂的中断控制,而定义的一套架构。版本也历经了多个变化,从最初的GICv1到现在最新的GICv4。每一个新的版本,都增加了一些新的功能。
在这里插入图片描述
目前最新的GIC-600 IP,支持GICv4。

不过从GICv3开始,架构就和之前的架构,变化就比较大了。

一、变化一:cpu interface

下图是GICv2架构,cpu interface是实现在gic内部,而且gic的寄存器,都是memory-mapped方式访问。

2.png
下图是GICv3架构,cpu interface从gic内部剥离,实现在PE的内部。并且将cpu interface的寄存器,提供了系统寄存器访问方式,从而实现中断的快速响应。
3.png

二、变化二:core的标识

GICv3中,对于core的标识,使用了属性层次的方式,来进行标识,从而可以支持更多的core。

4.png

而GICv2中,支持最大8个core。

三、变化三:消息中断

GICv3中,加入了LPI中断类型,来实现消息中断。并且提供了ITS,来实现中断的转换。

四、变化四:SGI处理

对于SGI的处理,有如下的变化。

5.png

中断线的映射

当gic架构,使用gicv3后,中断的传递,和gicv2有所区别。

gicv3中,将cpu interface从gic中抽离,放入到了cpu中,cpu interface通过gic stream接口,与gic进行通信。

当gic要发送中断,gic通过gic stream接口,给cpu interface发送中断命令,cpu interface收到中断命令后,根据中断线映射配置,决定是通过IRQ还是FIQ管脚,向cpu发送中断。

而中断线映射配置,要根据中断的分组以及当前cpu所处的EL以及seucre状态,来决定。

2种安全状态中断线映射

当gic支持2种安全状态,EL3是AArch64和AArch32,映射情况不同。

一、EL3是AArch64,中断线映射配置

当EL3是AArch64时,映射如下:
在这里插入图片描述

  • 对于group0中断,中断线均映射到FIQ
  • 对于group1安全中断,secure EL1或EL0,中断线映射到IRQ,其他EL映射到FIQ
  • 对于group1非安全中断,secure EL1或EL0以及EL3,中断线映射到FIQ,其他EL映射到IRQ

二、EL3是AArch32,中断线映射配置

当EL3是AArch32时,映射如下:
在这里插入图片描述

  • 对于group0中断,中断线均映射到FIQ。
  • 对于group1安全中断,secure EL0和EL3,中断线映射到IRQ,其余EL映射到FIQ。
  • 对于group1非安全中断,secure EL0和EL3,中断线映射到FIQ,其余EL映射到IRQ。

GICD寄存器配置

在GICD中的GICR_CTLR寄存器的DS bit,表示是否支持2种安全模式。
该bit描述如下,如果0,表示支持2种安全状态,为1,表示不支持。

在这里插入图片描述

1、支持2种安全模式下GICD_CTLR

在支持2种安全模式下,GICD中寄存器会进行备份成2份,一份提供给secure访问,。一份提供给non-secure访问。

比如对于GICD_CTLR寄存器,secure访问,寄存器描述如下:
在这里插入图片描述而如果是non-secure访问,其寄存器描述如下:
在这里插入图片描述

以下是GIC400寄存器配置的基本步骤: 1.初始化GIC CPU接口 首先,要初始化GIC CPU接口。这可以通过写入GICC_CTLR寄存器来实现。具体来说,将GICC_CTLR寄存器设为0,然后使能GICC_CTLR寄存器的使能位。 2.初始化GIC Distributor 其次,要初始化GIC Distributor。这可以通过写入GICD_CTLR寄存器来实现。具体来说,将GICD_CTLR寄存器设为0,然后使能GICD_CTLR寄存器的使能位。 3.配置中断 接下来,要配置中断。这可以通过写入GICD_ICFGR寄存器来实现。具体来说,将GICD_ICFGR寄存器的相应位设置为边沿触发或电平触发。 4.使能中断 最后,要使能中断。这可以通过写入GICD_ISENABLER寄存器来实现。具体来说,将GICD_ISENABLER寄存器的相应位使能。 下面是一个GIC400寄存器配置的例程: ```c #include <stdint.h> #define GICD_BASE 0x08000000 #define GICC_BASE 0x08010000 /* GIC Distributor registers */ #define GICD_CTLR (*(volatile uint32_t *)(GICD_BASE + 0x000)) #define GICD_ICFGR (*(volatile uint32_t *)(GICD_BASE + 0x0C0)) #define GICD_ISENABLER (*(volatile uint32_t *)(GICD_BASE + 0x100)) /* GIC CPU interface registers */ #define GICC_CTLR (*(volatile uint32_t *)(GICC_BASE + 0x000)) void gic_init(void) { /* Initialize GIC CPU interface */ GICC_CTLR = 0; GICC_CTLR |= 1; /* Initialize GIC Distributor */ GICD_CTLR = 0; GICD_CTLR |= 1; /* Configure interrupts */ GICD_ICFGR = 0; GICD_ICFGR |= (1 << 9); /* Set interrupt 9 to be level triggered */ /* Enable interrupts */ GICD_ISENABLER = 0; GICD_ISENABLER |= (1 << 9); /* Enable interrupt 9 */ } ``` 在这个例程,我们首先定义了GIC Distributor和GIC CPU接口的基地址,然后定义了一些相关的寄存器。 在gic_init()函数,我们首先初始化了GIC CPU接口和GIC Distributor。然后,我们配置中断,将中断9设置为电平触发。最后,我们使能了中断9。 注意,这只是一个简单的例程,实际需要根据具体的硬件平台和需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂奔的乌龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值