linux中断处理流程?linux内核视频教程

各位老铁们好,相信很多人对linux中断处理流程都不是特别的了解,因此呢,今天就来为大家分享下关于linux中断处理流程以及linux内核视频教程的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

Linux内核中断上半部处理程序

硬件中断--异步中断中断本质上是一种电信号,由硬件设备发出,用于通知处理器特定事件。不同设备对应不同中断,每个中断通过唯一的数字标识,称为中断请求(IRQ)线。处理器内部对其编号,也称为中断号。

异常--同步中断异常不同于中断,产生时必须考虑与处理器时钟同步。异常常称为同步中断,是处理器执行时由于编程失误而导致的错误指令(如除0),或者执行期间出现特殊情况(如缺页),必须靠内核来处理时,处理器就会产生一个异常。我们通常所说的是中断,是指由硬件产生的异步中断。

软中断工作方式类似于异步中断,区别是它是通过软件引起的中断,异步中断是由硬件引起的。

中断处理程序中断处理程序(interrupt handler)或中断服务例程(interrupt service routine,ISR)响应一个特定中断时执行的函数。设备产生的每个中断,都有一个中断处理程序关联。一个设备可能产生多种不同的中断,那么该设备就可以对应多个中断处理程序。相应地,设备驱动程序就需要准备多个这样的函数。

Linux中断处理程序特点 Linux中,中断处理程序看起来像普通C函数,按特定类型声明,以便内核能以标准的方式传递处理程序的信息。中断处理程序与其他内核函数的区别:中断处理程序是被内核调用来响应中断的,而它们运行于被称为中断上下文的特殊上下文中。由于中断随时可能产生,因此中断处理程序必须随时、尽快执行,这样才能尽快响应中断,同时恢复中断代码的执行。

上下半部的对比一般把中断处理切分为2个部分或两半:1)上半部(top half)中断处理程序是上半部,接收到一个中断,就立即开始执行,但只做严格时限的工作。如对接收中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的。2)下半部(bottom half)中断处理程序中,能被允许稍后完成的工作会推迟到下半部。Linux提供下半部的各种机制。

编写中断处理程序一个典型的中断处理程序声明:其签名必须与request_irq()中参数handler所要求函数类型一致。参数说明:返回值:返回值是一个特殊类型:irqerturn_t。实际是int类型,为了与早期内核兼容,因为2.6以前实际是void类型。可能返回2个特殊值:IRQ_NONE和IRQ_HANDLED。当中断处理程序检测到一个中断,但该中断并非注册处理函数时指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,而且确实是它所对应的设备产生的中断时,返回IRQ_HANDLED。返回值也可以用宏IRQ_RETVAL(x):x为非0,宏返回IRQ_HANDLED;x为0,返回IRQ_NONE。定义说明:中断处理程序通常标记为static,因为从来不会在其他文件被直接调用。可重入性 Linux中中断处理程序无需重入。当一个给定的中断处理程序正在执行时,相应的中断线在所有处理器上都会被屏蔽,以防在同一个中断线上接收另一个新的中断。也就是说,同一个中断线,同一个中断处理程序,在执行完毕之前不可能同时在2个处理器上执行,加上中断处理程序不能休眠,因此无需考虑可重入性。

中断控制 Linux内核提供一组接口用于操作机器上的中断状态:能用于禁止当前处理器的中断系统,屏蔽整个机器的一条中断线。例程与体系结构相关,位于。

禁止内核抢占:preempt_disable、preempt_enable等;禁止和激活中断用于禁止当前处理器上的本地中断,随后由激活:。由于flags包含具体体系结构的数据,即中断系统的状态,因此,flags不能传递给另一个函数,必须驻留在同一栈帧中。基于此,local_irq_save和restore的调用必须在同一个函数中。

中断系统的状态如何了解中断系统的状态,如中断当前是禁止的还是激活的?或者当前是否正处于中断上下文的执行状态中?本小节提供这方面回答。中 irqs_disable()如果本地处理器上的中断系统被禁止,则返回非0;否则,返回0。中 in_interrupt()如果内核处于中断上下文,则返回非0;如果在进程上下文,返回0。in_irq()如果当前正在执行中断处理程序,则返回非0;否则,返回0.

中断处理机制的实现中断处理系统的实现依赖于体系结构。中断的入口点是:硬件产生了中断,处理器开始跳转到对应的一个唯一位置,在栈中保存这个号,并存放当前寄存器的值(被中断任务),开始处理中断。中断产生到内核处理中断的步骤:1)硬件产生中断。2)处理器跳转到中断向量表对应的中断处理程序,栈中保存中断号及打断任务保存线程。3)内核调用do_IRQ()。之后,大多数中断处理代码用C编写。do_IRQ()提取中断号,对应x86代码:计算出中断号后,do_IRQ()对所接收的中断进行应答,禁止这条线上的中断传递。这些操作通过调用mask_and_ack_8259A()来完成。4)处理中断如果中断线上已安装中断处理程序,就调用handle_IRQ_event()处理;如果没有,就直接调用ret_from_intr(),返回内核运行中断的代码。x86上,handle_IRQ_event():5)调用ret_from_intr()类似于初始入口代码,用汇编编写。用于检查重新调度释放正在挂起(意味着设置了need_resched)。如果重新调度正在挂起,并且内核正在返回用户空间(i.e.中断了用户进程),那么schedule()被调用。如果内核正在返回内核空间(i.e.中断了内核本身),只有preempt_count(抢占计数器)为0时,schedule()才会被调用(否则,抢占内核便是不安全的)。schedule()返回后,或者如果没有挂起的工作,那么原来的寄存器被恢复,内核恢复到曾经中断的点。

/proc/interrupts查看中断统计信息 procfs是一个虚拟文件系统,只存在于内核内存,一般安装于/proc目录下。在procfs中读写文件都要调用内核函数,这些函数模拟从真实文件中读或写。/proc/interrupts文件存放系统中与中断相关的统计信息。

中断处理程序实例一个来自RTC驱动程序的中断处理程序,可在drivers/char/rtc.c中找到。RTC用于设置系统时钟,提供alarm或周期性定时器。

Linux内核中断之中断调用流程

本文基于 RockPI 4A单板Linux4.4内核介绍中断调用流程。

ARMv8包括两种运行状态:AArch64和AArch32。

AArch64中不再使用AArch32中的7种特权模式,而是提出了Exception Levels的概念,包括:

1)EL0:用于用户态程序,权限最低

2)EL1:给内核使用,权限稍高

3)EL2:虚拟化相关,权限更高

4)EL3:安全相关,权限最高

Linux内核中一般只使用EL0和EL1。

AArch64异常向量表中的异常包括:

1)Synchronous exception(同步异常)

2)SError

3)IRQ

4)FIQ

注:SError、IRQ和FIQ属于异步异常。

在Linux内核中,在 arch/arm64/kernel/entry.S文件中定义了异常向量表,内容如下:

选取 el1_irq()函数介绍Linux内核中断的调用流程。

文件: arch/arm64/kernel/entry.S,调用流程如下:

1、handle_irq()初始化

在 DTS解析阶段完成 handle_irq()函数的初始化,流程如下:

gic_irq_domain_map()函数中完成了 handle_irq()函数的赋值,具体执行如下:

2、handle_irq()实现

以共享外设中断 SPI的中断处理函数 handle_fasteoi_irq()为例,继续跟踪中断的执行过程。

handle_irq_event_percpu()函数会调用已经注册的中断处理函数,同时唤醒 irq_thread线程。

3、中断处理线程

在使用 request_threaded_irq()函数申请中断时,会创建一个 irq_thread线程,调用流程如下:

irq_thread线程平时在睡眠状态,等待 handle_irq_event_percpu()函数唤醒,进一步执行已注册的中断处理线程函数。

使用 DRM框架中 HDMI中断验证中断调用流程。

文件: drivers\gpu\drm\bridge\synopsys\dw-hdmi.c

在中断处理函数 dw_hdmi_hardirq()和中断处理线程函数 dw_hdmi_irq中增加 dump_stack()调用(注:仅限于调试验证)。

插入 HDMI线,系统启动后,显示中断调用流程的日志如下:

linux中断子系统 - linux 中断处理流程

当硬件触发中断时,中断信号直接导致处理器执行跳转至中断向量表,进入中断模式(IRQ模式),随后再次跳转至系统模式(svc模式),进行具体的中断处理操作。这一系列模式转换和现场保存操作主要由晦涩难懂的汇编代码实现。在做好必要的准备工作后,调用`handle_arch_irq`函数,最终进入C语言环境进行中断处理。

解释`handle_arch_irq`函数,这是一个平台相关的函数指针。通过`set_handle_irq`函数将其设置为`gic_handle_irq`。在中断发生后,中断处理流程会调用`gic_handle_irq`函数。

`gic_handle_irq`函数包含关键代码逻辑,处理三种类型中断:软件触发中断(SGI)、硬件触发中断(PPI)、以及外部硬件中断(SPI)。SGI用于CPU之间的通信,PPI是CPU独立触发的,典型例子是时钟中断,而SPI是最常见的外部中断。

SGI中断处理相对简单,仅涉及软件处理。PPI和SPI中断则需要考虑GIC的级联问题。系统中存在多个GIC时,需要递归处理。对于PPI和SPI,它们共享处理部分,但SPI处理需要考虑GIC的级联,而PPI处理直接进入SPI处理框架。

中断源信息记录在GIC的`GIC_CPU_INTACK`寄存器中,包括CPU ID和中断ID。SGI中断中CPU ID具有意义,而PPI/SPI中断中CPU ID无意义,仅读取低10位获取hwirq。

在处理中断号时,代码执行在一个死循环中,确保中断处理过程中产生的额外中断可以立即处理,而无需重新跳转至中断向量表。当从`GIC_CPU_INTACK`读取的中断号大于等于1020时,中断处理退出。

处理外设中断如PPI和SPI,调用`handle_domain_irq`函数,传入当前GIC所属domain、hwirq以及pt_regs。内核中存在中断编号(irq),与GIC的interrupt ID不同,存在映射关系,由domain保存。

进一步调用`__handle_domain_irq`函数处理中断,涉及设置中断状态、跳转至中断处理程序、执行软中断和退出中断环境等步骤。中断状态位在进入中断处理阶段时被设置,而非中断结束时。在特定条件下,中断环境会通过`tick broadcast`更新`jiffies`以防止软中断唤醒的误判。

通用中断处理函数`generic_handle_irq`实现核心处理逻辑,通过`irq_to_desc`获取中断描述信息,调用`desc->handle_irq()`回调函数进行处理。

中断回调函数`handle_fasteoi_irq`处理共享中断和级联中断,确保正确执行中断处理程序并进行中断线程化。对于SGI中断,处理流程直接进入IPI中断的特定处理。

IPI中断的响应与触发机制涉及GIC驱动初始化代码中的`set_smp_cross_call`函数,用于配置发送SGI中断的机制。例如,发送唤醒IPI中断时,调用路径涉及`arch_send_wakeup_ipi_mask`、`__smp_cross_call`,最终调用`gic_raise_softirq`函数。

中断处理流程涉及多种中断类型和机制,包括硬件触发、软件触发、级联处理、中断线程化等,确保系统能够高效响应中断,进行必要的操作并恢复至正常执行状态。

参考资料和链接提供进一步学习中断处理流程的资源。

阅读剩余
THE END