中断处理 - 上半部(硬中断) 由于 APIC中断控制器 有点小复杂,所以本文主要通过 8259A中断控制器 来介绍Linux对中断的处理过程。 注册中断处理入口 在内核中,可以通过 setup_irq() 函数来注册一个中断处理入口。 处理中断请求 当一个中断发生时,中断控制层会发送信号给CPU,CPU收到信号会中断当前的执行,转而执行中断处理过程。 处理完中断后,调用 do_softirq() 函数来对中断下半部进行处理(下面会说)。 中断处理 - 下半部(软中断) 由于中断处理一般在关闭中断的情况下执行,所以中断处理不能太耗时,否则后续发生的中断就不能实时地被处理。
edge 触发中断的基本处理过程: 电压跳变触发中断===>中断控制器接收中断,记IRR寄存器===>中断控制器置ISR寄存器===>CPU屏蔽本CPU中断===>CPU处理中断,发出EOI===>中断控制器确认可以处理下一次中断 ===>ISR清中断源,电压归位===>中断源可以发起下一次中断===>CPU中断处理完成,执行完现场处理后执行IRET,不再屏蔽本CPU中断。 那么在ISR处理开始的时候,A会告诉ISR,不是它干的,然后ISR处理B的中断,完成后通过清理中断源把B的电压归位,但是由于A的中断没有得到处理,电压没有归位,这个共享的中断就不能得到再次触发了。 注册的中断处理接口。 4、 在外设/驱动中断处理函数层次往往也有中断使能的功能,比如启用了NAPI的网卡,在中断处理函数开始执行的时候,往往会通过硬件功能关闭该中断,要在对应的软中断完成处理后才通过硬件功能使能该中断。
正在处理同一中断的那个CPU完成一次处理后, 会再次检查”触发”标记, 如果设置, 则再次触发处理过程. 于是, 中断的处理是一个循环过程, 每次循环调用handle_IRQ_event来处理中断. 注册的中断处理函数有个中断开关属性, 一般情况下, 中断处理函数总是在关中断的情况下进行的. 而调用request_irq注册中断处理函数时也可以设置该中断处理函数在开中断的情况下进行, 这种情况比较少见, 因为这要求中断处理代码必须是可重入的. 于是, 一个中断处理过程被分成了两部分, 第一部分在中断处理函数里面关中断的进行, 第二部分在软中断处理函数里面开中断的进行. 极端情况下,嵌套发生的软中断可能非常多,全部处理完可能需要很长的时间,于是内核会在处理完一定数量的软中断后,将剩下未处理的软中断推给一个叫ksoftirqd的内核线程来处理,然后结束本次中断处理过程。
在之前的ARMv8-A的异常文章中提到,ARMv8-A将中断也当做一种异常,中断分为IRQ和FIQ 假设当前在EL0运行一个64位的应用程序,触发了一个EL0的IRQ中断,则处理器会做如下的操作 将CPU msr daifclr, #(8 | 4 | 1) .endm 跳转到irq_handler去处理中断 当中断处理完毕后,就会通过ret_to_user返回到用户空间 /* * Interrupt ,每一个cpu都会存在一个中断栈的。 isb(); err = handle_domain_irq(gic_data.domain, irqnr, regs); //处理中断 ,调用generic_handle_irq_desc去处理中断,后面会涉及到irq domain的知识了。
2.中断门(Interrupt gate) 其类型码为110,中断门包含了一个中断或异常处理程序所在段的选择符和段内偏移量。 当控制权通过中断门进入中断处理程序时,处理器清IF 标志,即关中断,以避免嵌套中断的发生。 13),因为中断处理程序的特权级不能低于引起中断的程序的特权级。 这种情况发生的可能性不大,因为中断处理程序一般运行在内核态,其特权级为0。 若中断发生时CPU运行在用户空间,而中断处理程序运行在内核态,特权级发生了变化,所以会引起堆栈的更换。也就是说,从用户堆栈切换到内核堆栈。
在这里简单记录一下目前DragonOS中的中断处理的设计吧。 * @param irq_num 中断向量号 * @param arg 传递给中断安装接口的参数 * @param handler 中断处理函数 * @param paramater 中断处理函数的参数 可作为中断下半部使用,任务处理实时性低于硬中断。 软中断模块设计与硬中断的设计类似。其包括了一个软中断向量表及一些函数模型。 2.1软中断向量表表项定义 表项类型定义为softirq_t 成员 类型 参数 返回值 描述 action 函数 void*data void 软中断处理函数 data void* – – 传递给软中断处理函数的数据 unregister_softirq * @param irq_num 软中断号 2.4软中断处理程序do_softirq 在该函数中,先检测软中断是否正在被处理,如果空闲,则发起处理并置位标志位。
现代处理器大部分都有MMU,除了一些小型嵌入式设备。 缺页中断处理一般流程: 1.硬件陷入内核,在堆栈中保存程序计数器,大多数当前指令的各种状态信息保存在特殊的cpu寄存器中。 2.启动一个汇编例程保存通用寄存器和其他易丢失信息,以免被操作系统破坏。 7.当磁盘中断发生时,表明该页已经被装入,页表已经更新可以反映他的位置,页框也标记位正常状态。 8.恢复发生缺页中断指令以前的状态,程序计数器重新指向这条指令。 9.调度引发缺页中断的进程,操作系统返回调用他的汇编例程 10.该例程恢复寄存器和其他状态信息,返回到用户空间继续执行,就好像缺页中断没有发生过。 ,这样不会导致死循环中断,内核设计很安全。
要处理中断,需要有一个中断处理函数。 很多中断处理程序将整个中断要做的事情分成两部分,称为上半部和下半部,或者成为关键处理部分和延迟处理部分。 在中断处理函数中,仅仅处理关键部分,完成了就将中断信号打开,使得新的中断可以进来,需要比较长时间处理的部分,也即延迟部分,往往通过工作队列等方式慢慢处理。 有了中断处理函数,接下来要调用 request_irq 来注册这个中断处理函数。 每一个中断处理动作的结构 struct irqaction,都有以下成员:中断处理函数 handler;void *dev_id 为设备 id;irq 为中断信号;如果中断处理函数在单独的线程运行,则有
以s3c2440 ARM9核为例: 一:s3c2440 ARM处理器特性: 1、S3C2440支持60个中断源,含子中断源; 2、ARM9采用五级流水线方式; 3、支持外部中断和内部中断 EINTMASK:这个简单,是屏蔽中断用的,也就是说位为1时,此次中断无效。 2.2 内部中断寄存器 内部中断有8个寄存器。 INTPND:中断优先级仲裁器选出优先级最高中断后,这个中断在INTPND寄存器中的相应位被置1,随后,CPU进入中断模式处理它。同一时间内,此寄存器只有一位被置1。 三、中断处理流程 1、中断控制器汇集各类外设发出的中断信号,然后通知CPU。 2、CPU保存当前程序的运行环境,然后调用中断服务程序(ISR),来处理中断。 3、在ISR中通过读取外设的相关的寄存器来识别中断的类型,并进行相应的处理。 4、清除中断:通过读写相关中断控制寄存器和外设相关寄存器来实现。
优先级高的中断可能打断优先级低的中断处理,形成中断嵌套。系统根据中断优先级进行调度处理,确保紧急和重要事件优先得到处理,从而保证系统稳定、安全、高效地运行。 中断延迟指从中断发生到开始执行中断处理程序的时间间隔,响应时间则包括整个中断处理过程的持续时间。优化中断处理可以显著减少延迟,提高系统响应速度。2.中断频率与系统负载中断频率对系统负载有直接影响。 主要的优化策略包括:中断合并:将多个中断请求合并处理,减少上下文切换次数批处理:累积多个事件后一次性处理,降低中断频率硬件辅助:利用硬件特性加速中断识别和响应中断屏蔽:在关键区域屏蔽中断,保证原子性操作三 (DPC)的机制,类似地实现了中断处理的分级处理。 :中断亲和性:将特定中断绑定到特定CPU核心负载均衡:均匀分配中断处理负载中断合并与聚合:减少中断总数NUMA感知:考虑非统一内存访问架构四、中断处理编程实践1.编写中断处理程序的原则编写高质量的中断处理程序需要遵循以下原则
由于在处理硬件中断服务时会关闭硬件中断,所以在处理硬件中断服务的过程中,如果发生了其他的硬件中断,也不能得到有效的处理,从而导致硬件中断丢失的情况。 为了避免这种情况出现,Linux 内核把中断处理分为:中断上半部 和 中断下半部,上半部在关闭中断的情况下进行,而下半部在打开中断的情况下进行。 由于中断上半部在关闭中断的情况下进行,所以必须要快速完成,从而避免中断丢失的情况。而中断下半部处理是在打开中断的情况下进行的,所以可以慢慢进行。 一般来说,网卡驱动向内核注册的中断处理服务属于 中断上半部,如前面介绍的 NS8390网卡驱动 注册的 ei_interrupt 中断处理服务,而本文主要分析网卡 中断下半部 的处理。 对于 Linux 内核的中断处理机制可以参考我们之前的文章 Linux中断处理,这里就不详细介绍了。在本文中,我们只需要知道网络中断下半部处理例程为 net_rx_action 函数即可。
中断服务程序(ISR)是一个小的程序,用来处理具体的数据,其具体的处理方式依赖于造成中断请求(IRQ)的原因。之前正在运行的进程在中断服务程序(ISR)运行结束前都会被中断。 在过去,中断请求由单独的芯片处理(中断控制器芯片 PIC),I/O 设备直接与中断控制器(PIC)相连。中断控制器(PIC)管理着多种硬件的中断请求(IRQ),并且可以直接与 CPU 通信。 现如今,中断请求(IRQ)由 CPU 中的 高级可编程中断控制器(advanced programmable interrupt controller)(APIC)部分来处理。 硬件中断 当一个硬件设备想要告诉 CPU 某一需要处理的数据已经准备好后(例如:当键盘被按下或者一个数据包到了网络接口处),它将会发送一个中断请求(IRQ)来告诉 CPU 数据是可用的。 这是最严重的中断,终止将会调用系统的终止异常处理程序来结束造成异常的进程。 动手实践 中断请求按照高级可编程中断控制器(APIC)中的优先级高低排序(0是最高优先级)。
Linux 中,当外设触发中断后,大体处理流程如下: a -- 具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler; control(处理中断的嵌套、抢占等),当然最终会遍历该中断描述符的IRQ action list,调用外设的specific handler来处理该中断; d -- 具体CPU architecture 相关的模块会进行现场恢复; 总结下来,整个过程可以分为三部分:1、硬件处理部分;2、汇编处理部分;3、C 处理部分; 下面我们来追踪一下代码,了解当中断发生时,Linux 是如何处理的,前面的一些中断初始化部分就不再这里详述了 ,下面开始具体分析: 一、硬件处理部分 当一切准备好之后,一旦打开处理器的全局中断就可以处理来自外设的各种中断事件了。 现在处理中断中我们就看到了调用了我们自己的中断处理函数来处理中断了。
编程处理0号中断 1.1 效果演示 现在我们考虑改变一下0号中断处理程序的功能,即重新编写一个0号中断处理程序,它的功能是在屏幕中间显示“overflow!”然后返回到操作系统,如下图所示。 可见 ,当中断 0 发生时,CPU将转去执行中断处理程序。 前面讲到,内存0000:0000~0000:03FF,大小为1KB的空间是系统存放中断处理程序入口地址的中断向量表。8086支持256个中断,但是,实际上,系统中要处理的中断事件远没有达到256个。 1.5 从CPU的角度看中断处理程序 现在,我们在反过来从CPU的角度看一下,什么是中断处理程序? ,即do0 的代码,就变成了0号中断的中断处理程序。
处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。此后,处理器会通知 OS 已经产生中断。这样,OS 就可以对这个中断进行适当的处理。 中断处理 - 上半部(硬中断) 由于 APIC中断控制器 有点小复杂,所以本文主要通过 8259A中断控制器 来介绍Linux对中断的处理过程。 处理中断请求 当一个中断发生时,中断控制层会发送信号给CPU,CPU收到信号会中断当前的执行,转而执行中断处理过程。 处理完中断后,调用 do_softirq() 函数来对中断下半部进行处理(下面会说)。 中断处理 - 下半部(软中断) 由于中断处理一般在关闭中断的情况下执行,所以中断处理不能太耗时,否则后续发生的中断就不能实时地被处理。
在上一篇如何优雅地取消线程任务中提到了通过中断可以取消线程正在进行的任务,现在针对中断这件事情再来简单聊聊。 return true; } finally { lock.unlock(); } } } 传递中断 如果捕获到一个中断异常不知道怎么处理它 ,因为这件事只有一个人来处理就够了,所以抛出异常后会清除中断状态,比如Thread,sleep()。 false 可有人想中断我?false 可有人想中断我? 非中断”,但被我设为中断了 可有人想中断我?
理解它们之间的优先级关系以及特殊的中断处理机制,如中断延迟处理,对于开发高效、稳定且具有良好实时性的嵌入式系统至关重要。本文将详细探讨这些概念,并提供相关代码示例以加深理解。 当一个中断发生时,无论当前正在执行的任务优先级多高,处理器都会立即暂停任务执行,转而进入中断服务程序(ISR)处理中断。 只有在中断处理完成后,才会根据任务优先级来决定是继续执行高优先级任务还是低优先级任务。 三、中断的延迟处理 (一)理论概述 在某些情况下,硬件中断的处理可能非常耗时。 为了解决这个问题,FreeRTOS 采用了中断延迟处理机制。该机制将中断处理分为两部分:在中断服务程序(ISR)中,尽快完成一些必要的清理和记录工作,然后触发一个任务来处理更复杂、耗时的操作。 这样可以保证中断响应的及时性,同时也不会影响系统的整体性能和任务的执行。 (二)代码示例 以下是一个中断延迟处理的代码示例。假设我们有一个串口接收中断,接收大量数据并进行处理。
外设的中断信号被送到“通用的中断信号处理模块”和“特定中断信号接收模块”。 正常工作的时候,我们会turn on“通用的中断信号处理模块”的处理逻辑,而turn off“特定中断信号接收模块” 的处理逻辑。 一旦唤醒,我们最好是turn off“特定中断信号接收模块”,让外设的中断处理回到正常的工作模式,同时,也避免了系统suspend-resume模块收到不必要的干扰。 ),而普通中断由于其IRQ被disable了,因此无法唤醒idle状态中的处理器。 整个过程和将系统从suspend状态中唤醒一样,唯一不同的是:将系统从freeze状态唤醒走的中断处理路径,而将系统从suspend状态唤醒走的唤醒处理路径,需要电源管理HW BLOCK中特别的中断处理逻辑的参与
系统初始化的时候,定义和初始化了中断向量表。并初始化8259的工作方式。 linux0.11分为中断、系统、陷阱门。系统在启动的时候设置idt。 for (i=17;i<48;i++) set_trap_gate(i,&reserved); set_trap_gate(45,&irq13); // 允许8259接收中断 在这里插入图片描述 还有一些是键盘,软盘等也设置中断。下面看一个异常处理程度。 具体的处理可以见内存管理分析那篇文件。
中断响应模块目前使用了8259A PIC芯片进行中断处理。使用两块8259A芯片级联,并采用AEOI、FNM全嵌套、无缓冲模式进行处理。 级联结构: 中断引脚与外部设备对照表 8259A PIN 中断请求源 主芯片 IR0 timer时钟 IR1 键盘 IR2 级联从8259A芯片 IR3 串口2 IR4 串口1 IR5 并口 2 IR6 软驱 IR7 并口1 从芯片 IR0 CMOS RTC实时时钟 IR1 重定向到主芯片的IR2引脚 IR2 保留 IR3 保留 IR4 PS/2鼠标 IR5 协处理器 IR6 SATA主硬盘 IR7 SATA从硬盘 初始化中断处理模块 定义了保存寄存器的宏定义 使用Build_IRQ宏,创建每个中断号的中断入口函数。 初始化中断门(使用ist=2) 设置主、从芯片的ICW1-4以及OCW1. 中断处理流程 在中断入口处,保存寄存器 将返回地址压入堆栈 跳转到do_IRQ()函数 发送EOI到PIC,结束中断。