本文以MIPS体系架构为例介绍Linux内核中的中断处理,MIPS架构与其他体系结构的中断处理有很大区别,请注意区分。如果不关注特定体系结构,则1.1和3.1节不必太关注。
MIPS中,中断被当作一种异常(第0号异常)来处理。中断由外部设备产生,可能发生在任何时刻,每个中断都有一个编号分配给一个外部设备,这样来区分不同设备产生的中断,如果硬件和内核支持共享中断,则可以由多个设备共享一个中断编号。
在CPU得知中断发生后,它将进一步的处理委托给一个软件例程,这个软件例程是体系结构相关的,然后根据中断号来识别中断源,并进入特定的中断处理程序来处理该中断。
中断处理的软件例程大致可分为三部分:
1.切换到内核态,并保护现场,用于在中断处理后能够执行之前被打断的指令。
2.根据中断号执行中断处理程序。
3.恢复现场,内核继续进行后续的常规动作。
1. 初始化
1.1 mips中的中断号
中断初始化主要包括全局数组iqr_desc[]的初始化和中断处理函数的注册。
每个中断信号线都有一个中断描述符iqr_desc,每个iqr_desc包含了中断硬件描述符,中断处理函数链表等。
全局的中断描述符表iqr_desc[NR_IRQS]的定义在kernel/irq/handle.c中。NR_IRQS是允许最多中断号的数量,这个值是平台相关的,例如MIPS某处理器中的取值为128。
struct irq_desc irq_desc[NR_IRQS]__cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status= IRQ_DISABLED,
.chip =&no_irq_chip,
.handle_irq= handle_bad_irq,
.depth= 1,
.lock =__SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
MIPS的协处理器CP0的Cause寄存器中IP0-IP7位分别就对应了其中的0-7号中断,其中0和1用作软件产生的中断,这些中断的中断线可以直接与CPU相连。
但是MIPS允许0-127号中断,那么Cause寄存器中这几个中断号显然不够用,这可以通过硬件中断控制器的级联来达到扩展中断数量的目的,例如,用第6号中断关联一个中断控制器A,该中断控制器分派出22个中断,中断号定义为16~37,之后还可以继续分派更多的中断,只要中断号不超过127。那么,当产生2~5号中断时,CPU可直接判断是何种中断,而当CPU得知第6号中断发生后,通过中断控制器A的内部寄存器可以判断出应该进入哪个中断号对应的处理例程。
1.2 关键数据结构
iqr_desc[]数组每个元素都是一个struct irq_desc结构:
关键的两个数据结构为struct irq_desc(中断描述符)和struct irq_chip(特定于具体中断控制器的描述符),定义如下,注释中对各字段的解释也写的很清楚。
/**
* struct irq_chip - hardware interrupt chip descriptor
*
* @name: namefor /proc/interrupts
* @startup: start up the interrupt (defaults to->enable if NULL)
* @shutdown: shut down the interrupt (defaults to->disable if NULL)
* @enable: enable the interrupt (defaults tochip->unmask if NULL)
* @disable: disable the interrupt (defaults tochip->mask if NULL)
* @ack: start of a new interrupt
* @mask: mask an interrupt source
* @mask_ack: ack and mask an interrupt source
* @unmask: unmask an interrupt source
* @eoi: end of interrupt - chip level
* @end: endof interrupt - flow level
*@set_affinity: set the CPU affinity on SMPmachines
*@retrigger: resend an IRQ to the CPU
* @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) ofan IRQ
* @set_wake: enable/disable power-management wake-on ofan IRQ
*
* @release: