在uClinux初始化的过程中,就会配置好相应的中断向量表,并根据用户的配置来设置外部中断的优先级。
/* init/main.c */
asmlinkage void __init start_kernel(void)
{
…
sort_main_extable();
trap_init();
rcu_init();
init_IRQ();
pidhash_init();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
…
}
其中的trap_init函数只是简单地设置了中断3(Exception)的中断向量(trap,汇编代码),实际上在后面的init_IRQ函数中又设置了一道。其作用是防止rcu_init出错时可以捕捉到。需要注意的是,此时uClinux还没有打开中断,即IMASK还是bf561复位以后的默认值,但是在复位后Exception中断默认是打开的,因此才有可能捕捉到rcu_init的异常。
init_IRQ是一个主要的中断初始化函数,包括中断向量的写入,中断优先级的配置等等。不过很奇怪的是,init_IRQ居然不处理中断1,即Reset中断!
bf561支持64个外部中断,后4个保留,其余60个可以通过宏来控制它们的优先级,这些宏的值可以介于[7-15]之间,uClinux将根据这60个值来配置SIC_IAR。
#define CONFIG_IRQ_PLL_WAKEUP 7
#define CONFIG_IRQ_DMA1_ERROR 7
#define CONFIG_IRQ_DMA2_ERROR 7
#define CONFIG_IRQ_IMDMA_ERROR 7
#define CONFIG_IRQ_PPI0_ERROR 7
#define CONFIG_IRQ_PPI1_ERROR 7
#define CONFIG_IRQ_SPORT0_ERROR 7
#define CONFIG_IRQ_SPORT1_ERROR 7
#define CONFIG_IRQ_SPI_ERROR 7
#define CONFIG_IRQ_UART_ERROR 7
#define CONFIG_IRQ_RESERVED_ERROR 7
#define CONFIG_IRQ_DMA1_0 7
#define CONFIG_IRQ_DMA1_1 7
#define CONFIG_IRQ_DMA1_2 7
#define CONFIG_IRQ_DMA1_3 7
#define CONFIG_IRQ_DMA1_4 7
#define CONFIG_IRQ_DMA1_5 7
#define CONFIG_IRQ_DMA1_6 7
#define CONFIG_IRQ_DMA1_7 7
#define CONFIG_IRQ_DMA1_8 7
#define CONFIG_IRQ_DMA1_9 7
#define CONFIG_IRQ_DMA1_10 7
#define CONFIG_IRQ_DMA1_11 7
#define CONFIG_IRQ_DMA2_0 7
#define CONFIG_IRQ_DMA2_1 7
#define CONFIG_IRQ_DMA2_2 7
#define CONFIG_IRQ_DMA2_3 7
#define CONFIG_IRQ_DMA2_4 7
#define CONFIG_IRQ_DMA2_5 7
#define CONFIG_IRQ_DMA2_6 7
#define CONFIG_IRQ_DMA2_7 7
#define CONFIG_IRQ_DMA2_8 7
#define CONFIG_IRQ_DMA2_9 7
#define CONFIG_IRQ_DMA2_10 7
#define CONFIG_IRQ_DMA2_11 7
#define CONFIG_IRQ_TIMER0 7
#define CONFIG_IRQ_TIMER1 7
#define CONFIG_IRQ_TIMER2 7
#define CONFIG_IRQ_TIMER3 7
#define CONFIG_IRQ_TIMER4 7
#define CONFIG_IRQ_TIMER5 7
#define CONFIG_IRQ_TIMER6 7
#define CONFIG_IRQ_TIMER7 7
#define CONFIG_IRQ_TIMER8 7
#define CONFIG_IRQ_TIMER9 7
#define CONFIG_IRQ_TIMER10 7
#define CONFIG_IRQ_TIMER11 7
#define CONFIG_IRQ_PROG0_INTA 7
#define CONFIG_IRQ_PROG0_INTB 7
#define CONFIG_IRQ_PROG1_INTA 7
#define CONFIG_IRQ_PROG1_INTB 7
#define CONFIG_IRQ_PROG2_INTA 7
#define CONFIG_IRQ_PROG2_INTB 7
#define CONFIG_IRQ_DMA1_WRRD0 7
#define CONFIG_IRQ_DMA1_WRRD1 7
#define CONFIG_IRQ_DMA2_WRRD0 7
#define CONFIG_IRQ_DMA2_WRRD1 7
#define CONFIG_IRQ_IMDMA_WRRD0 7
#define CONFIG_IRQ_IMDMA_WRRD1 7
#define CONFIG_IRQ_WDTIMER 7
下表简要列出了各个中断处理的功能,如无特别说明,其入口均位于arch/blackfin/mach-common/interrupt.s文件中。
中断
|
入口
|
功能
|
EMU
|
evt_emulation
|
保存当前各寄存器的值
调用irq_panic输出这些值并终止运行
|
RST
|
未处理
|
|
NMI
|
evt_evt2
|
保存寄存器的值
调用asm_do_IRQ(arch/blackfin/mach-kernel/irqchip.c)
恢复寄存器的值并从发生异常的位置继续执行
|
EVX
|
trap
|
此入口代码位于arch/blackfin/mach-common/entry.s。
它将根据SEQSTAT_EXCAUSE寄存器中的异常原因调用_extable中提供的回调函数,在entry.s中定义了64个入口,主要是以下几个处理函数:
ex_syscall:/* 0x00 – Linux系统调用异常 */
ex_soft_bp:/* 0x01 – 软件断点异常 */
ex_trap_c:/* 所有未经特殊处理的异常都将由它处理 */
ex_spinlock:/* 0x04 - User Defined */
ex_single_step:/* 0x10 – 单步执行时中断异常 */
ex_dcplb:/* 0x23 – Data CPLB异常 */
ex_icplb:/* 0x2B - Instruction CPLB异常 */
|
Reserved
|
保留
|
|
IVHW
|
evt_ivhw
|
保存当前各寄存器的值
调用irq_panic输出这些值并终止运行
|
IVTMR
|
evt_timer
|
全部跳转到__common_int_entry,在此处保存各寄存器的值,然后调用do_irq,再调用return_from_int,最后恢复各寄存器的值并返回到中断之前的位置继续执行。
|
IVG7
|
evt_evt7
| |
IVG8
|
evt_evt8
| |
IVG9
|
evt_evt9
| |
IVG10
|
evt_evt10
| |
IVG11
|
evt_evt11
| |
IVG12
|
evt_evt12
| |
IVG13
|
evt_evt13
| |
IVG14
|
evt14_softirq
|
此入口代码位于arch/blackfin/mach-common/entry.s。
它将IMASK保存到R0中,并将IMASK设置为0。然后返回到中断之前的位置继续执行。
|
IVG15
|
evt_system_call
|
保存当前各寄存器的值
调用system_call
恢复各寄存器的值并返回到中断之前的位置继续执行
|