首页 > 系统相关 >Linux 中断机制(二)之中断子系统框架

Linux 中断机制(二)之中断子系统框架

时间:2024-08-14 21:55:26浏览次数:8  
标签:控制器 函数 中断 irq GIC Linux 子系统 外设

目录


一、概述

一个完整的中断子系统框架可以分为四个层次, 由上到下分别为:用户层、 通用层、 硬件相关层和硬件层, 每个层相关的介绍如下所示:

  • 用户层:用户层是中断的使用者,主要包括各类设备驱动。 这些驱动程序通过中断相关的接口进行中断的申请和注册。 当外设触发中断时, 用户层驱动程序会进行相应的回调处理,执行特定的操作。
  • 通用层:通用层也可称为框架层,它是硬件无关的层次。 通用层的代码在所有硬件平台上都是通用的,不依赖于具体的硬件架构或中断控制器。 通用层提供了统一的接口和功能, 用于管理和处理中断, 使得驱动程序能够在不同的硬件平台上复用。
  • 硬件相关层:硬件相关层包含两部分代码。 一部分是与特定处理器架构相关的代码,比如 ARM64 处理器的中断处理相关代码。 这些代码负责处理特定架构的中断机制, 包括中断向量表、 中断处理程序等。 另一部分是中断控制器的驱动代码, 用于与中断控制器进行通信和配置。这些代码与具体的中断控制器硬件相关。
  • 硬件层:硬件层位于最底层, 与具体的硬件连接相关。 它包括外设与 SoC(系统片上芯片)的物理连接部分。 中断信号从外设传递到中断控制器, 由中断控制器统一管理和路由到处理器,硬件层的设计和实现决定了中断信号的传递方式和硬件的中断处理能力。

二、中断控制器 GIC

中断控制器(Interrupt Controller)是中断子系统框架硬件中的一个关键组件,用于管理和分发系统中的中断信号。其中,GIC(Generic Interrupt Controller)是一种通用的中断控制器,常用于 ARM 架构的处理器系统中。

不同的架构有不同的中断控制器,STM32 中的中断控制器叫做 NVIC,ARM 架构中的中断控制器一般为 GIC。

GIC 的主要功能是接收来自各种外部设备或内部事件的中断请求,并根据优先级和预设规则,将这些中断请求分发给相应的中断处理器或 CPU 核心。GIC 通常包含多个中断输入通道和多个中断输出通道,以支持多个设备同时触发中断。

GIC采用了多级中断架构,其中包括SGI(Software Generated Interrupts)、PPI(Private Peripheral Interrupts)和 SPI(Shared Peripheral Interrupts)等级别的中断。SGI 是由软件产生的中断,PPI 是针对单个处理器核心的私有中断,SPI 是针对多个处理器核心的共享中断。

每个 GIC 版本及相应特性如下表所示:

版本关键特性常用核心
GICV1支持最多八个处理器核心(PE)
支持最多 1020 个中断 ID
ARM Cortex-A5 MPCore
ARM Cortex-A9 MPCore
ARM Cortex-R7 MPCore
GICV2GICv1 的所有关键特性
支持虚拟化
ARM Cortex-A7 MPCore
ARM Cortex-A15 MPCore
ARM Cortex-A53 MPCore
ARM Cortex-A57 MPCore
GICV3GICv2 的所有关键特性
支持超过 8 个处理器核心
支持基于消息的中断
支持超过 1020 个中断 ID
CPU 接口寄存器的系统寄存器访问
增强的安全模型,分离安全和非安全的 Group1中断
ARM Cortex-A53 MPCore
ARM Cortex-A57 MPCore
ARM Cortex-A72 MPCore
GICV4GICv3 的所有关键特性
虚拟中断的直接注入
ARM Cortex-A53 MPCore
ARM Cortex-A57 MPCore
ARM Cortex-A72 MPCore

下面以 GICV3 讲解其结构功能,GIC V3.0 逻辑图组成如下所示:



GIC 中断控制器可以分为 Distributor 接口Redistributor 接口CPU 接口,下面是每个部分的说明:

1、Distributor 接口

Distributor(中断仲裁器)用于 SPI(Shared peripheral interrupts)中断的管理,具有仲裁和分发的作用,会将中断发送给 Redistributor

Distributor 提供了一些编程接口或者说是寄存器,我们可以通过 Distributor 的编程接口实现如下操作。下面是Distributor 主要功能:

  • 启用和禁用 SPI。
  • 设置每个 SPI 的优先级级别。
  • 每个 SPI 的路由信息。
  • 将每个 SPI 设置为电平触发或边沿触发,生成基于消息的 SPI。
  • 控制 SPI 的活动和挂起状态。
  • 用于确定在每个安全状态中使用的程序员模型的控制(亲和性路由或遗留模型)。

2、Redistributor 接口

GICv3 中,Redistributor(重新分配器) 管理 SGI,PPI,LPI 中断,然后将中断发送给 CPU 接口,包括下面功能:

  • 启用和禁用 SGI(软件生成的中断)和 PPI(处理器专用中断)设置 SGI 和 PPI 的优先级级别。
  • 将每个 PPI 设置为电平触发或边沿触发。
  • 将每个 SGI 和 PPI 分配给一个中断组。
  • 控制 SGI 和 PPI 的状态。
  • 对支持关联 LPI(低功耗中断)的中断属性和挂起状态的内存中的数据结构进行基址控制。
  • 支持与连接的处理器核心的电源管理。

3、CPU 接口

CPU 接口为链接到 GIC 的处理器提供接口,与 Distributor 类似它也提供了一些编程接口,我们可以通过 CPU 接口实现以下功能:

  • 通用控制和配置,用于启用中断处理。
  • 确认中断。
  • 执行中断的优先级降低和停用。
  • 为处理器核心设置中断优先级屏蔽。
  • 定义处理器核心的抢占策略。
  • 确定处理器核心最高优先级的挂起中断。

三、中断类型

GIC-V3 支持四种类型的中断,分别是 SGIPPISPILPI,每个中断类型的介绍如下:

  • SGISoftware Generated Interrupt,软件生成中断): SGI 是通过向 GIC 中的 SGI 寄存器 写入来生成的中断。 该类型中断并没有实际的物理连线,而是由软件通过写寄存器方式触发,它只支持边沿触发。它通常用于处理器之间的通信, 允许一个 PE 发送中断给一个或多个指定的 PE, 中断号 ID0-ID15 用于 SGI
  • PPIPrivate Peripheral Interrupt, 私有外设中断): 针对特定 PE 的外设中断。 不与其他 PE 共享,因为 PPI 是 PE 私有的,所以每个 PE 都可以使用相同一段范围的 PPI。因为 PPI 是 PE 私有的,所以每个 PE 都可以使用相同一段范围的PPI。中断号 ID16-ID31 用于 PPI
  • SPIShared Peripheral Interrupt,共享外设中断):全局外设中断,可以路由到指定的 PE 或一组 PE, 它允许多个 PE 接收同一个中断。SPI 由设备连接至 Distributor 中断控制器的硬件中断连线触发。该类型中断不与特定的 CPU 绑定,可以根据 affinity 配置被路由到任意 CPU 或一组特定的 CPU 上。中断号 ID32-ID1019 用于 SPI
  • LPILocality-specific Peripheral Interrupt,特定局部外设中断):LPI 是 GICv3 中引入的一种中断类型与其他类型的中断有几个不同之处。LPI 总是基于消息的中断,也称作基于内存地址的中断, 由外设写一个内存地址产生,这个内存地址一般映射至 GIC ITS 内部的 translator 寄存器。ITS 接收外设写入的数据后进行翻译,然后再向特定 redistributor 产生一个中断。其配置存储在内存表中, 而不是寄存器中。
INTID 范围中断类型备注
0 - 15SGI(软件生成中断)每个核心分别存储
16 - 31PPI(私有生成中断)每个核心分别存储
32 - 1019SPI(共享外设中断)
1020 - 1023特殊中断号用于表示特殊情况
1024 - 8191保留
8192 及更大LPI(特定局部外设中断)上限由实现定义

  • Inactive(非活动状态):中断源当前未被触发。
  • Pending(等待状态):中断源已被触发,但尚未被处理器核心确认。
  • Active(活动状态):中断源已被触发,并且已被处理器核心确认。
  • Active and Pending(活动且等待状态):已确认一个中断实例, 同时另一个中断实例正在等待处理。

每个外设中断可以是以下两种类型之一:

  • 边沿触发(Edge-triggered
    这是一种在检测到中断信号上升沿时触发的中断,然后无论信号状态如何,都保持触发状态,直到满足本规范定义的条件来清除中断。
  • 电平触发(Level-sensitive
    这是一种在中断信号电平处于活动状态时触发的中断, 并且在电平不处于活动状态时取消触发。

中断类型控制:

GICV3 支持通过软件控制中断的状态,如将某个中断设置为 pending 状态、active 状态或清除其 pendingactive 状态。它可以通过配置以下几个寄存器实现:

寄存器功能
GICD_SETSPI_NSR设置特定的 non secure 中断的 pending 状态。
若该中断当前为 inactive 状态,则转换为 pending 状态。
若当前为 pending 状态,则转换为 pending and active 状态
GICD_CLRSPI_NSR清除特定 non secure 中断的 pending 状态
GICD_SETSPI_SR设置特定的 secure 中断的 pending 状态。
若该中断当前为 inactive 状态,则转换为 pending 状态。若当前为 pending 状态,则转换为 pending and active 状态
GICD_CLRSPI_SR清除特定 secure 中断的 pending 状态
GICD_ISPENDR设置一个或一组中断为 pending 状态。
若该中断当前为 inactive 状态,则转换为 pending 状态。
若当前为 pending 状态,则转换为 pending and active 状态。
该寄存器的每一个 bit 代表一个中断号
GICD_ICPENDR清除一个或一组中断为 pending 状态,该寄存器的每个 bit 代表一个中断号
GICD_ISACTIVE设置一个或一组中断为 active 状态。
若该中断当前不处于 active 状态,则转换为 active 状态。
若当前为 active 状态,则该操作被忽略。
该寄存器的每一个 bit 代表一个中断号
GICD_ICACTIVE清除一个或一组中断为 active 状态。
该寄存器的每一个 bit 代表一个中断号

四、中断号

在 Linux 内核中, 我们使用 IRQ numberHW interrupt ID 两个 ID 来标识一个来自外设的中断:

  • IRQ number:CPU 需要为每一个外设中断编号,我们称之 IRQ Number。 这个 IRQ number 是一个虚拟的 interrupt ID,和硬件无关,仅仅是被 CPU 用来标识一个外设中断。
  • HW interrupt ID:对于 GIC 中断控制器而言,它收集了多个外设的 interrupt request line 并向上传递,因此, GIC 中断控制器需要对外设中断进行编码。 GIC 中断控制器用 HW interrupt ID 来标识外设的中断。 如果只有一个 GIC 中断控制器, 那 IRQ numberHW interrupt ID 是可以一一对应的,如下图所示:


但如果是在 GIC 中断控制器级联的情况下, 仅仅用 HW interrupt ID 就不能唯一标识一个外设中断, 还需要知道该 HW interrupt ID 所属的 GIC 中断控制器(HW interrupt ID 在不同的 Interrupt controller 上是会重复编码的)。

五、中断申请函数

1、request_irq 函数

request_irq 函数是在 Linux 内核中用于注册中断处理程序的函数。 它用于请求一个中断号(IRQ number)并将一个中断处理程序与该中断关联起来。下面是对 request_irq 函数的详细介绍:

#include <linux/interrput.h>

int request_irq(unsigned int irq, 
				irq_handler_t handler, 
				unsigned long flags, 
				const char *name, 
				void *dev);
  • 参数含义
    • irq:要请求的中断号(IRQ number
    • handler:指向中断处理程序的函数指针。
    • flags:标志位,用于指定中断处理程序的行为和属性,如中断触发方式、中断共享等。
    • name:中断的名称,用于标识该中断。
    • dev:指向设备或数据结构的指针,可以在中断处理程序中使用。
  • 返回值:
    • 成功:0 或正数,表示中断请求成功。
    • 失败:负数,表示中断请求失败,返回的负数值表示错误代码,

下面是常用的标志:

标志描述
IRQF_SHARED多个设备共享一个中断线,共享的所有中断都必须指定此标志。如果使用共享中断的话, request_irq 函数的 dev 参数就是唯一区分他们的标志
IRQF_ONESHOT单次中断,中断执行一次就结束
IRQF_TRIGGER_NONE无触发
IRQF_TRIGGER_RISING上升沿触发
IRQF_TRIGGER_FALLING下降沿触发
IRQF_TRIGGER_HIGH高电平触发
IRQF_TRIGGER_LOW低电平触发

2、request_threaded_irq() 函数

中断线程化的作用与工作队列类似,先在中断处理函数中处理重要紧急的任务,然后使用线程来处理耗时复杂的任务。函数原型如下:

request_threaded_irq(unsigned int irq, 
					 irq_handler_t handler,
		     		 irq_handler_t thread_fn,
		     		 unsigned long flags, 
		     		 const char *name, 
		     		 void *dev);

request_irq() 函数相比 request_threaded_irq() 函数仅多了一个入参 thread_fnthread_fn() 为在线程中运行的函数。

3、gpio_to_irq 函数

gpio_to_irq 函数用于将 GPIO 引脚的编号(GPIO pin number)转换为对应的中断请求号(interrupt request
number
)。

#include <linux/gpio.h>

unsigned int gpio_to_irq(unsigned int gpio);
  • 参数说明
    • gpio:要映射的 GPIO 引脚号。
  • 返回值
    • 成功:返回值为该 GPIO 引脚所对应的中断号。
    • 失败:返回值为负数,表示映射失败或无效的 GPIO 引脚号。

4、free_irq 函数

free_irq 函数用于释放之前通过 request_irq 函数注册的中断处理程序。 它的作用是取消对中断的注册并释放相关的系统资源。下面是关于该函数的详细解释:

#include <linux/interrupt.h>

void free_irq(unsigned int irq, void *dev_id)
  • 参数说明
    • irq:要释放的中断号。
    • dev_id:设备标识,用于区分不同的中断请求。它通常是在 request_irq 函数中传递的设备特定数据指针。

六、中断服务函数

中断处理程序是在中断事件发生时自动调用的函数。 它负责处理与中断相关的操作, 例如读取数据、 清除中断标志、 更新状态等。

irqreturn_t handler(int irq,void *dev_id) 是一个典型的中断服务函数的函数原型。下面对该函数原型及其参数进行详细解释:

irqreturn_t handler(int irq,void *dev_id)

handler 函数是一个中断服务函数,用于处理特定中断事件。它在中断事件发生时被操作系统或硬件调用,执行必要的操作来响应和处理中断请求。

  • 参数说明
    • irq:表示中断号或中断源的标识符。它指示引发中断的硬件设备或中断控制器。
    • dev_id:是一个 void 类型的指针,用于传递设备特定的数据或标识符。它通常用于在中断处理程序中区分不同的设备或资源。
  • 返回值
    • irqreturn_t 是一个特定类型的枚举值,用于表示中断服务函数的返回状态。它可以有以下几种取值:
      • IRQ_NONE:表示中断服务函数未处理该中断,中断控制器可以继续处理其他中断请求。
      • IRQ_HANDLED:表示中断服务函数已成功处理该中断,中断控制器无需进一步处理。
      • IRQ_WAKE_THREAD:表示中断服务函数已处理该中断,并且请求唤醒一个内核线程来继续执行进一步的处理。这在一些需要长时间处理的中断情况下使用。

在处理程序中, 通常需要注意以下几个方面:

  1. 处理程序应该尽可能地快速执行,以避免中断丢失或过多占用 CPU 时间。
  2. 如果中断源是共享的, 处理程序需要处理多个设备共享同一个中断的情况。
  3. 处理程序可能需要与其他部分的代码进行同步,例如访问共享数据结构或使用同步机制来保护临界区域。
  4. 处理程序可能需要与其他线程或进程进行通信,例如唤醒等待的线程或发送信号给其他进程。

标签:控制器,函数,中断,irq,GIC,Linux,子系统,外设
From: https://blog.csdn.net/Teminator_/article/details/141198896

相关文章

  • Linux驱动入门实验班——SR501红外模块驱动(附百问网视频链接)
    目录 一、工作方式二、接口图三、编写思路1.构造file_operations结构体2.实现read函数3.编写入口函数4.编写中断处理函数5.编写出口函数6.声明出入口函数以及协议四、源码五、课程链接一、工作方式SR501人体红外感应模块有两种工作模式:        通过......
  • 视觉SLAM ch3补充——在Linux中配置VScode以及CMakeLists如何添加Eigen库
            ch3中的所有代码,除了在kdevelop中运行,还可以在VScode中运行。下面将简要演示配置过程,代码不再做解答,详细内容在下面的文章中。(这一节中的pangolin由于安装过程中会出现很多问题,且后续内容用不到该平台,所以暂时不进行安装)视觉SLAMch3—三维空间的刚体运动http......
  • 第一阶段复习 --Python、Linux、Shell、MySQL
    文章目录第一阶段复习总结python1.python是面向对象的解释型动态数据语言的高级程序设计语言2.变量3.基础数据类型4.数据类型之间的转换5.str类型字符串方法序列6.运算符7.选择循环结构8.数据容器9.函数参数10.类11.正则12.文件读写13.异常处理tryexc......
  • OpenCloudOS 8.10 发布:全面兼容企业级 Linux 生态 ,引入更多新 module
    2024年8月,OpenCloudOS社区年度新版本OpenCloudOS8.10正式发布。全面兼容RHEL 8.10用户态包,引入Python3.12软件包,更新GCCToolset13、LLVMToolset17,RustToolset1.75.0,GoToolset1.21.0等编译器和开发工具。OpenCloudOS8.10采用Kernel5.4LTS版本(内核小......
  • 【WEB系列】快速识别目标站点:Windows Linux服务器探秘
    一、利用大小写敏感性差异二、分析HTTP响应头信息三、利用系统命令探测四、分析网页内容和脚本五、总结在网络安全工作中,快速判断目标站点的操作系统类型至关重要,这可以帮助安全人员制定针对性的攻击策略或防御措施。传统的方法依赖于端口扫描、指纹识别等工具,但这些方法......
  • Linux Web项目部署过程命令 Tomcat组件
    LinuxWeb项目部署过程命令Tomcat,本文涉及的是打成jar包方式的前后端分离项目,打成war包的方式也有解释介绍。1.连接服务器2.利用lsof命令查看web后端部署端口进程,然后kill杀死进程,                            ......
  • 国产linux系统(银河麒麟,统信uos)使用 PageOffice 国产版获取word指定位置的值
    PageOffice国产版:支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)、龙芯longarch芯片架构。查看本示例演示效果本示例关键代码的编写位置,请参考“开始-快速上手”里您所使用的开发语言框架的最简集成代码注意本文中展示的......
  • 【Linux入门】账号安全、系统安全以及应用相关基础命令
    文章目录账号安全系统账号限制相关命令密码安全控制系统安全以及应用pam-权限管理一、PAM体系概述二、PAM认证原理三、PAM配置方式四、PAM控制标记visudo-组账号控制一、visudo的基本作用二、使用visudo控制组账号的sudo权限1.编辑/etc/sudoers文件2.添加组......
  • 【OS_Linux】删除日志文件中某个时间节点之前的内容
    在Linux中,可以使用sed命令命令来删除日志文件中某个时间点之前的内容。假设有一个名为logfile.log的日志文件,想删除2024年8月14日15:30:00之前的所有内容。首先,需要确定日志文件的日期格式。如果日志文件中的日期格式是YYYY-MM-DDHH:MM:SS,你可以使用以下命令:sed-i'/2024-08-1......
  • Linux Shell常用命令
    命令说明举例常用字符串运算符-a并且-n 检测检测字符串长度是否不为0,不为0返回true。[-n"$a"]返回true。-z检测字符串长度是否为0,为0返回true。[-z$a]返回false。$检测字符串是否为空,不为空返回true。[$a]返回 true。=检测两个字符串是否相等,相等返......