Linux内核-中断和中断处理

Posted by keys961 on March 21, 2019

1. 中断

本质是一种特殊的电信号,由硬件发给处理器,处理器向OS反映信号到来,然后处理信号。

中断需要有唯一标识以区分,这样OS才能执行对应的中断处理程序。

中断不需考虑与处理器时钟同步,可随时产生,内核可被新来的中断而打断。

异常:要考虑与处理器时钟同步,因此叫同步中断(如除以0,缺页等),处理方式和处理中断类似。

如系统调用处理程序异常,通过软中断int 0x80指令实现。

2. 中断处理程序

每种中断对应一个中断处理程序(Interrupt handler),在Linux中就是普通的C函数,但要按照特定的类型声明。

上下文:处于中断上下文(原子上下文)中,执行的代码不可阻塞。

3. 上半部与下半部

把中断处理切成2个部分:

  • 上半部:即中断处理程序,接收中断,立刻执行,不过工作要有严格时限
  • 下半部:允许稍后完成的工作推到这里运行(如处理数据等)

4. 注册与实现中断处理程序

中断处理程序是驱动程序的一部分,需要向内核注册,调用request_irq()函数。该函数可能会阻塞,因此不能再中断上下文或其它不允许阻塞的地方使用。

request_irq() --> proc_mkdir() create /proc/irq/xx --> proc_create() --> kmalloc() sleep here

卸载时,调用free_irq()释放中断线。

实现时,需要声明为类似的签名:static irqreturn_t xx_handler(int irq, void* dev)

实现时不考虑重入,因为中断正在执行时,对应中断线在所有处理器上都会被屏蔽,防止同一中断线线上接收另一个新中断。

5. 中断上下文

中断处理程序运行时,进入中断上下文。

关于中断上下文:

  • current无意义(虽然指向被中断的进程)
  • 不可以睡眠或放弃CPU,时间限制严格
  • 不能占用互斥体
  • 不能访问用户虚拟内存空间
  • 不可重入
  • 能被更高等级的IRQ中断
  • 处理程序要尽量简洁迅速,尽量把复杂工作放入下半部

6. 中断处理机制的实现

流程是:

  1. 设备产生中断,传给中断控制器
  2. 若中断线是被激活的,则将中断发给处理器
  3. 处理器停止正在做的事情,关闭中断系统,跳转到一个预定义中断程序的入口(根据中断线,得到IRQ号,然后可跳转到对应的中断处理程序)
  4. 判断中断线上有没有对应的中断处理程序,且没有正在运行,若有,运行中断处理程序
  5. 从中断代码返回,恢复

7. /proc/interrupts

procfs:一个虚拟的文件系统,只存于内核内存,一般挂载在/proc下。对于该文件系统下的读写都要调用内核函数,模拟真实文件的读写。

/proc/interrupts:存放系统中断的统计信息(包括中断线、中断在不同CPU核心的计数、对应的设备等)

8. 中断控制

Linux提供一组接口,能让我们禁止系统的中断系统,或屏蔽某条中断线,定义可在<asm/system.h><asm/irq.h>找到。