当前位置: 首页 > news >正文

【Linux驱动-快速回顾】一文快速理解GIC内部寄存器对中断的控制

第一部分:GIC的功能和组成

1. GIC要解决的根本问题
在一个复杂的片上系统(SoC)中,有非常多的硬件模块(如定时器、串口、按键、DMA等),它们都需要在完成任务或遇到特定事件时通知CPU。同时,系统里可能有多个CPU核心。因此,必须有一个统一的、专门的硬件来管理这些中断请求。它需要解决:

  • 来源管理:管理成百上千个中断源。
  • 优先级仲裁:当多个中断同时发生时,决定哪个更重要,应该先被处理。
  • 中断路由:决定将一个中断发送给哪个CPU核心去处理。
  • 状态同步:确保CPU和中断控制器之间的状态是一致的,比如一个中断正在被处理时,就不应该再次打扰CPU。

GIC (Generic Interrupt Controller) 就是 ARM 定义的用来解决以上所有问题的标准硬件模块。

2. GIC的核心组件
根据文档,GIC 主要由两个功能模块组成,它们的职责划分非常清晰:

  • 分发器 (Distributor)

    • 职责:作为整个系统的中断“管理中心”和“仲裁中心”。
    • 具体工作
      1. 接收所有中断:系统中所有外设的中断信号线都连接到 Distributor。
      2. 配置中断属性:软件通过 Distributor 的寄存器来配置每个中断的属性,包括:
        • 优先级 (Priority):定义中断的重要程度。
        • 目标CPU (Target):指定这个中断可以发送给哪些CPU核心。
        • 触发方式 (Configuration):是电平触发还是边沿触发。
        • 使能/禁用 (Enable/Disable):控制一个中断是否被允许。
      3. 仲裁:在所有已触发且被使能的中断中,找出优先级最高的那一个。
      4. 转发:将这个最高优先级的中断,转发给其目标CPU对应的“CPU接口”。
  • CPU接口 (CPU Interface)

    • 职责:作为 Distributor 和单个CPU核心之间的“信使”。每个CPU核心都有一个自己专属的 CPU Interface。
    • 具体工作
      1. 接收中断:从 Distributor 接收已经仲裁过的、最高优先级的中断。
      2. 优先级过滤 (Masking):CPU Interface 内部可以设置一个优先级阈值。如果接收到的中断的优先级不够高(低于这个阈值 ),它就不会去打扰CPU。
      3. 通知CPU:如果中断通过了优先级过滤,CPU Interface 会向其对应的CPU核心发出一个物理的中断信号(IRQ 或 FIQ)。
      4. 提供中断信息:当CPU响应中断后,软件可以通过读取 CPU Interface 的寄存器来获知当前中断的ID号。
      5. 处理完成通信:当软件处理完中断后,通过写入 CPU Interface 的寄存器来通知 GIC。

Distributor 负责多对多(多个中断源到多个CPU)的管理和决策;
CPU Interface 负责一对一(Distributor 到单个CPU)的通信和执行。

好的,我们完全按照要求,用更直接、无修饰的语言来重新讲解第二部分。我们将严格遵循硬件和软件的交互行为,来描述一个中断从产生到处理完成的全过程。


第二部分:从中断触发到CPU处理,发生了什么?

第1步:中断源触发与Pending状态的设置
  • 物理层:外部设备(如GPIO)的信号线电平发生变化,该信号被送入GIC Distributor。
  • GIC Distributor的行为
    1. Distributor硬件逻辑检测到输入信号。
    2. 硬件查询该中断ID对应的使能寄存器(GICD_ISENABLERn)。
    3. 若该中断ID被使能,Distributor在内部状态寄存器中,将该中断ID的标志位设置为 Pending (挂起)
  • Pending状态的定义:表示一个有效的中断请求已经由GIC记录,正在等待GIC的后续处理。
第2步:优先级仲裁
  • 内部事件:Distributor的仲裁逻辑被触发。这可能在有新的中断变为Pending状态时发生。
  • GIC Distributor的行为
    1. 硬件逻辑扫描所有处于Pending状态的中断ID。
    2. 对于每一个Pending的中断ID,硬件会读取其对应的优先级寄存器(GICD_IPRIORITYRn)中的值。
    3. 硬件比较所有这些优先级值,并选择值最小(即优先级最高)的中断ID作为本次处理的目标。
  • 仲裁结果:Distributor确定了当前应该被处理的、优先级最高的中断请求。
第3步:向CPU接口转发与优先级过滤
  • 事件:Distributor已选出最高优先级的中断ID。
  • GIC Distributor的行为
    1. 硬件读取该中断ID的目标处理器寄存器(GICD_ITARGETSRn),确定目标CPU。
    2. Distributor通过内部总线,将这个最高优先级的中断ID及其优先级信息,发送给目标CPU的专属CPU Interface。
  • GIC CPU Interface的行为
    1. CPU Interface接收到来自Distributor的中断请求。
    2. 硬件执行优先级过滤:它将收到的中断的优先级,与CPU Interface内部的优先级屏蔽寄存器(GICC_PMR)的值,以及当前正在处理的中断的优先级组(如果有的话)进行比较。
    3. 只有当新中断的优先级严格高于过滤阈值时,该中断才被接受。
    4. 若中断被接受,CPU Interface会驱动连接到CPU核心的物理IRQ(或FIQ)信号线,使其变为有效电平。
第4步:CPU响应与中断确认 (Acknowledge)
  • 事件:CPU核心检测到其IRQ信号线变为有效。

  • CPU硬件的行为

    1. 若CPU的中断屏蔽位(CPSR寄存器中的I/F位)未置位,CPU将暂停当前指令的执行。
    2. 硬件自动将程序计数器(PC)和相关寄存器压入当前模式的堆栈。
    3. 硬件强制将PC设置为中断向量表中预定义的IRQ异常向量地址。
  • 软件(异常处理程序)的行为

    1. 位于异常向量地址的程序开始执行。其首要任务是执行对CPU Interface的 GICC_IAR (Interrupt Acknowledge Register) 的读操作
  • GICC_IAR的直接后果

    1. 对软件而言:该读操作返回一个32位值,其中包含了触发本次中断的硬件中断ID
    2. 对GIC硬件而言:GIC检测到对GICC_IAR的读访问,会原子地更新该中断ID的状态:清除其Pending标志位,并设置其Active标志位。
  • Active状态的定义:表示该中断已被CPU获知,并且其对应的服务程序即将或正在执行。GIC将不会再次向CPU转发同一个处于Active状态的中断请求。

    • 并发情况:若一个中断在Active期间再次被外设触发,它的状态将变为Active and Pending
第5步:中断服务程序执行
  • 事件:软件已从GICC_IAR获取了硬件中断ID。
  • 软件(操作系统)的行为
    1. 软件使用该硬件中断ID作为索引,在中断分派表中查找对应的中断服务程序(ISR)的地址。
    2. 调用该ISR。
    3. ISR执行与中断源设备相关的特定操作。
第6步:中断处理完成与中断结束 (End of Interrupt)
  • 事件:中断服务程序(ISR)已执行完毕。

  • 软件(异常处理程序)的行为

    1. 在从异常处理流程返回前,软件必须执行对CPU Interface的 GICC_EOIR (End of Interrupt Register) 的写操作,写入的值是第4步中获取的那个硬件中断ID。
  • GICC_EOIR的直接后果

    1. 对GIC硬件而言:GIC检测到对GICC_EOIR的写访问,会清除该中断ID的Active标志位。
    2. 状态转移:
      • 如果该中断状态之前是单纯的Active,现在将变为Inactive(非活动)。
      • 如果该中断状态之前是Active and Pending,现在Active位被清除后,状态将变回Pending。GIC的仲裁逻辑会立刻将这个新的Pending中断纳入下一轮仲裁。
  • CPU恢复:软件执行异常返回指令(如SUBS PC, LR, #4),CPU从堆栈中恢复之前保存的上下文,并从被中断的指令处继续执行。


省流版本

1.中断发生,Distributor检测到输入信号,提取中断ID号,使能寄存器(GICD_ISENABLERn),将该中断状态寄存器设置为挂起Pending

2.Distributor找出当前触发的优先级最高的中断

3.Distributor提取当前最高优先级中断ID的目标CPU,转发给CPU专属的CPU Interface

4.CPU Interface接收到来自Distributor中断请求,将其优先级与优先级屏蔽寄存器的值比较,符合条件则:驱动连接到CPU核心的物理IRQ(或FIQ)信号线,使其变为有效电平

5.CPU核心检测到其IRQ信号线变为有效,且CPU的中断屏蔽位未置位:
停止当前指令执行,压栈:将程序计数器(PC)和相关寄存器压入当前模式的堆栈;

6.强制将PC设置为中断向量表中预定义的IRQ异常向量地址;

7.执行对CPU Interface的 GICC_IAR (Interrupt Acknowledge Register) 的读操作
原子地更新该中断ID的状态:清除其Pending标志位,并设置其Active标志位

8.执行对应对应中断,完成后执行对CPU Interface的 GICC_EOIR (End of Interrupt Register) 的写操作

9.软件执行异常返回指令(如SUBS PC, LR, #4),CPU从堆栈中恢复之前保存的上下文,并从被中断的指令处继续执行


第三部分:上文提到的中断寄存器专讲

我们继续按照触发顺序讲解这些寄存器
这样更能清晰一些

第1步:了解GIC硬件能力 (可选,但良好驱动的实践)

在配置之前,软件可以先读取一些只读寄存器,了解当前GIC的规格。

**GICD_TYPER 了解GIC一些基础信息

(Interrupt Controller Type Register)**
作用: 读取此寄存器,可以知道:
这个GIC最多支持多少个中断 (ITLinesNumber)、
实现了多少个CPU接口 (CPUNumber)、
是否支持安全扩展 (SecurityExtn) 等。
这让驱动可以动态适应不同的硬件。
在这里插入图片描述

位域读写描述
15:11LSPIR如果GIC实现了安全扩展,则此字段的值是已实现的可锁定SPI的最大数量,范围为0(0b00000)到31(0b11111)。 如果此字段为0b00000,则GIC不会实现配置锁定。 如果GIC没有实现安全扩展,则保留该字段。
10SecurityExtnR表示GIC是否实施安全扩展: 0未实施安全扩展; 1实施了安全扩展
7:5CPUNumberR表示已实现的CPU interfaces的数量。 已实现的CPU interfaces数量比该字段的值大1。 例如,如果此字段为0b011,则有四个CPU interfaces。
4:0ITLinesNumberR表示GIC支持的最大中断数。 如果ITLinesNumber = N,则最大中断数为32*(N+1)。 中断ID的范围是0到(ID的数量– 1)。 例如:0b00011最多128条中断线,中断ID 0-127。 中断的最大数量为1020(0b11111)。 无论此字段定义的中断ID的范围如何,都将中断ID 1020-1023保留用于特殊目的
第2步:对每一个“计划使用”的中断进行单独配置
1.GICD_ICFGRn :设置中断的触发方式

(Interrupt Configuration Registers)
置该中断是电平触发 (Level-sensitive) 还是边沿触发 (Edge-triggered)。这个必须根据外设的硬件手册来设置,否则中断会行为异常
在这里插入图片描述
这里两位代表一个中断,一个GICD_ICFGRn 寄存器能配置16个中断
已知硬件中断号m怎么知道GICD_ICFGRn 的n是多少?用m整除16即可得到n
然后是哪个字段?(两位等于一个字段)
假设中断号34,34/16=2,余2,所以F=2,所以寄存器位是【22,22+1】
也就是【4,5】
Int_config[1] (高位,即 bit[5]):0 = 电平触发, 1 = 边沿触发。
Int_config[0] (低位,即 bit[4]):保留位,通常写0。

2.Distributor (分组 , GICD) GICD_IGROUPRn

(GICD_ Interrupt GROUP Registers)

在这里插入图片描述
一位即可表示是否为安全中断,一个寄存器能给32个中断置位
某一位
置位 0(通常是安全中断,FIQ)
置位 1(通常是非安全中断,IRQ)的中断分发

非安全中断:给主操作系统(如Linux)用的常规中断

  • 是什么?
    • 处理普通任务的中断。
  • 谁产生?
    • 普通的、非敏感的硬件设备。比如:网卡、普通按键、串口、触摸屏。
  • 谁处理?
    • 主操作系统,比如你手机上的Android系统或电脑上的Linux/Windows系统。
  • 有什么用?
    • 让主操作系统知道硬件发生了事。比如网卡收到数据了,Linux内核就去处理这个数据。
  • 在GIC里怎么设置?
    • 通过 GICD_IGROUPRn 寄存器,把这个中断对应的位设置为 1。

安全中断 (Secure Interrupt / Group 0 Interrupt)
安全中断是给一个独立的安全系统用的特殊中断,主操作系统(如Linux)不能处理它,也通常不知道它的存在

  • 是什么?
    • 处理高度敏感和机密任务的中断。
  • 谁产生?
    • 受保护的、敏感的硬件设备。比如:指纹传感器、加密芯片、安全定时器。
  • 谁处理?
    • 一个独立于主操作系统之外的、微型的安全系统(常被称为TEE,Trusted Execution Environment)。这个安全系统和Linux是隔离的。
  • 有什么用?
    • 处理那些绝对不能让主操作系统(比如Linux)接触到的数据。比如,指纹识别过程中的数据,必须由安全系统处理,以防被Linux上的恶意软件窃取。
  • 在GIC里怎么设置?
    • 通过 GICD_IGROUPRn 寄存器,把这个中断对应的位设置为 0。
3.优先级 (Priority) - GICD_IPRIORITYRn

在这里插入图片描述
因为设置了256个优先级,所以描述一个中断的优先级需要8位
一个寄存器32位可以设置四个中断的优先级

目标CPU (Targeting) - GICD_ITARGETSRn (主要用于SPI)

在这里插入图片描述
这个是GICV2版本下,采用位图方式(每一位代表一个目标CPU),最多只支持8核CPU。

第3步:使能/禁用中断
1.GICD_ISENABLERn (Set-Enable) / GICD_ICENABLERn (Clear-Enable)

(中断分发)
( Interrupt Set-Enable Registers)
在这里插入图片描述
每一位控制一个中断的转发,如果没有
向 GICD_ISENABLERn 的 bit 位写1来使能中断。
向 GICD_ICENABLERn 的 bit 位写1来禁用中断。
“转发” = 传递中断信号给CPU核心

中断首先由GIC接收。但GIC是否会将该中断传递(转发)给CPU核心,取决于以下条件
1.中断是否使能(由2.ICD_ISENABLERn/GICD_ICENABLERn控制)。 中断的优先级、目标CPU核心等其他配置是否满足。

第4步:配置CPU接口
1.优先级屏蔽:GICC_PMR

Interrupt Priority Mask Register
作用: 设置当前CPU的优先级“门槛”。CPU将只处理优先级高于此寄存器值的中断(即优先级数值小于PMR值)。
32位寄存器,只有前八位有效,因为前面的也是八位优先级在这里插入图片描述

2.优先级分组-GICC_BPR

Binary Point Register
在这里插入图片描述
GICC_BPR 寄存器里那3位 [2:0] 的值 (0到7),就定义了拆分的“分割点”。
这个分割点 BPR_Value 的含义是:8位优先级中,有多少位属于子优先级。
8位优先级: [ bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0 ]
在这里插入图片描述

第4步:打开总开关 (最后一步)
GICD_CTLR (Distributor Control Register)

作用: 分发器总开关。
在这里插入图片描述

把它理解为整个GIC分发器的“总电源开关”就对了。
在你把所有中断都精心配置好(设置好优先级、目标CPU、触发方式等)之后,最后一步就是打开这个总开关,GIC才能正式开始工作。

  • [0] - EnableGrp0 (使能组0)

    • 作用:控制 Group 0 中断的转发。
    • 0关闭。所有属于Group 0的中断,即使已经触发(处于pending状态),也会被GIC分发器拦住,不会被发送给任何CPU接口。就像闸门A关闭了。
    • 1打开。GIC分发器会根据优先级规则,将处于pending状态的Group 0中断正常转发给CPU接口。就像闸门A打开了。
  • [1] - EnableGrp1 (使能组1)

    • 作用:控制 Group 1 中断的转发。
    • 0关闭。所有属于Group 1的中断都会被拦住,不会被发送出去。就像闸门B关闭了。
    • 1打开。GIC分发器会根据优先级规则,将处于pending状态的Group 1中断正常转发给CPU接口。就像闸门B打开了。
GICC_CTLR (CPU Interface Control Register)

作用: 当前CPU接口的总开关。
GICC_CTLR 就是每个CPU核心自己的“中断接收器开关”。

主要功能:它到底控制了什么?

它主要控制两件大事:

  1. 全局开关:决定当前这个 CPU 核心是否要开始处理中断。
  2. 高级行为配置:微调一些中断处理的细节,比如如何结束中断、如何处理被屏蔽的信号等。

位域讲解 (Bit Fields)

我们直接按功能块来讲解最重要的几个位,这比按数字顺序更容易理解。

1. 最重要的全局开关

  • EnableGrp0 (位 0)

    • 功能Group 0 (安全中断, 通常是 FIQ) 的总开关。
    • 设置为 1: 允许当前 CPU 核心接收并处理来自 GIC 的 Group 0 中断。
    • 设置为 0: 屏蔽当前 CPU 核心的所有 Group 0 中断。即使 GIC 已经把中断信号发过来了,到这里也会被挡住。
  • EnableGrp1 (位 1)

    • 功能Group 1 (非安全中断, 通常是 IRQ) 的总开关。
    • 设置为 1: 允许当前 CPU 核心接收并处理来自 GIC 的 Group 1 中断。
    • 设置为 0: 屏蔽当前 CPU 核心的所有 Group 1 中断。

使用要点:在系统初始化时,必须根据你需要处理的中断类型,将这两位或其中一位设置为 1。这是让中断系统工作的最基本前提。

2. 中断结束行为的配置

  • EOImode (位 9)
    • 功能:控制**“中断结束”** (GICC_EOIR 寄存器) 的行为模式。
    • 背景:当你向 GICC_EOIR 写入一个值表示中断处理完毕时,GIC 硬件内部会做两件事:
      1. 优先级降低 (Priority Drop):允许其他中断可以抢占。
      2. 中断去激活 (Deactivation):将中断状态从“Active”移除。
    • EOImode = 0 (默认模式):写一次 GICC_EOIR,硬件自动完成上面两件事。简单直接。
    • EOImode = 1 (分离模式):写一次 GICC_EOIR,硬件只做第一件事(降低优先级)。你需要再向另一个寄存器 GICC_DIR 写入相同的值,才能完成第二件事(去激活)。这是一种性能优化手段,用于复杂的嵌套中断,普通应用用不到。

3. 中断信号传递的微调

  • FIQEn (位 3)

    • 功能:决定 GIC 的 CPU 接口是否要将 Group 0 的中断信号物理地传递给 CPU 的 FIQ 引脚。
    • 设置为 1: 正常传递,触发 FIQ 异常。
    • 设置为 0: 不传递。等于在软件层面掐断了 FIQ 信号线。
  • CBPR (位 4) - Control Bypass and Priority Register

    • 功能:控制 Group 0 和 Group 1 中断的优先级处理方式。
    • CBPR = 0: Group 0 和 Group 1 的中断共享同一个优先级寄存器 (GICC_PMR)。
    • CBPR = 1: Group 0 和 Group 1 使用各自独立的优先级处理逻辑。这允许你为安全中断和非安全中断设置不同的优先级屏蔽策略。

文章转载自:
http://allethrin.aaladrg.cn
http://bawbee.aaladrg.cn
http://appraisement.aaladrg.cn
http://arica.aaladrg.cn
http://acetonaemia.aaladrg.cn
http://alkene.aaladrg.cn
http://banish.aaladrg.cn
http://brachydactylic.aaladrg.cn
http://ami.aaladrg.cn
http://cannabinoid.aaladrg.cn
http://articulatory.aaladrg.cn
http://absorptiometer.aaladrg.cn
http://broider.aaladrg.cn
http://cantankerous.aaladrg.cn
http://buddhahood.aaladrg.cn
http://assuming.aaladrg.cn
http://absolution.aaladrg.cn
http://blastosphere.aaladrg.cn
http://bargain.aaladrg.cn
http://backkward.aaladrg.cn
http://antinational.aaladrg.cn
http://begum.aaladrg.cn
http://bathos.aaladrg.cn
http://broomie.aaladrg.cn
http://antehuman.aaladrg.cn
http://bmj.aaladrg.cn
http://beheld.aaladrg.cn
http://bharal.aaladrg.cn
http://alleyway.aaladrg.cn
http://chiasm.aaladrg.cn
http://www.dtcms.com/a/280955.html

相关文章:

  • Claude技术全景解读:从安全聊天机器人到自主智能体的演进之路
  • 数据结构自学Day7-- 二叉树
  • 项目总体框架(servlet+axios+Mybatis)
  • ue4 houdini pivot painter 学习笔记
  • 可微分3D高斯溅射(3DGS)在医学图像三维重建中的应用
  • OpenCV 对数变换函数logTransform()
  • ubuntu22.04 软创建 RAID1 与配置流程
  • pytest快速上手指南【pytest】
  • LED 照明应用提供高性价比方案?会是你的首选吗?
  • C++ 中两个类之间的通信方式
  • labview关于OOP
  • labview生成exe应用程序常见问题
  • Java行为型模式---责任链模式
  • redis集群的部署
  • 渭河SQL题库-- 来自渭河数据分析
  • JavaScript与Vue:现代前端开发的完美组合
  • King’s LIMS:实验室数字化转型的智能高效之选
  • AWS S3事件通知实战:从配置到生产的完整指南
  • 云蝠智能赋能呼入场景——重构企业电话服务
  • JVM——为什么Java8移除了永久代(PermGen)并引入了元空间(Metaspace)?
  • 订单初版—7.支付和履约实现的重构文档
  • 域名备案是否可以加急
  • DirectX12(D3D12)基础教程九 间接绘制
  • Dynadot邮箱工具指南(十二):删除域名邮箱
  • 学习软件测试的第十六天
  • C++ Qt插件开发样例
  • Git Bash 实战操作全解析:从初始化到版本管理的每一步细节
  • 读取和写入json,xml文件
  • Kubernetes 架构原理与集群环境部署
  • Codeforces Round 907 (Div. 2) F. A Growing Tree(2000,子树修改)