前一篇博文中:linux内核初始化阶段通过early_trap_init()函数完成了把异常向量拷贝到0xFFFF0000开始的地方,这些异常向量大部分指向通过vector_stub宏定义的那段代码,这段代码完成的主要工作是计算异常返回地址、保存现场、切换到svc模式、跳转执行汇编异常处理函数,汇编异常处理函数工作在svc模式,先接管上一异常模式保存的现场,然后调用C处理函数,C函数返回后执行一段汇编代码完成异常返回工作。这一系列的工作就是基于arm9处理器的内核异常处理的体系架构。
linux内核irq中断也是异常事件的一类,但是irq中断发生源不止一个,arm920t只有一个irq中断信号接收引脚,对具体的中断源的判断还需要依赖片外的中断控制器,再者,irq中断引脚是和外设上的中断引脚相连,外设的种类千奇百态,具体的外设有中断事件时需要处理器执行特殊的处理工作,我想基于这种背景,必须要专门的一套中断处理体系结构来管理中断事件才能让处理器高效工作。
内核中断处理体系结构的搭建任务主要落在init_IRQ()函数,他直接由srart_kernel()函数来调用,定义于arch/arm/kernel/irq.c。
void __init init_IRQ(void)
{
int irq; //中断号
for (irq = 0; irq < NR_IRQS; irq++)
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE; //通过把每一个中断号对应结构体成员“status”状态字段设置成未请求和未探测状态
init_arch_irq(); //init_arch_irq实际上是一个函数指针,最初由setup_arch()函数来设置这个指针
}
函数分析:
①内核将所有的中断统一编号,习惯叫“中断号”,同时定义了irq_desc[NR_IRQS]结构体数据用来描述每一个中断,中断号就是用来在这个数组里面定位对应的中断描述结构体的。irq_desc结构体后面再进行分析,现在先放一边。
②探索init_arch_irq()函数:找了一下发现他在start_kernel-->setup_arch函数中被初始化
void __init setup_arch(char **cmdline_p)
{
.....
init_arch_irq = mdesc->init_irq; //将void型指针init_arch_irq强制指向struct machine_desc结构体的init_irq成员
.....
}
好,问题又来了:什么时候事先把“mdesc->init_irq”这个成员填充了初始?struct machine_desc {
......
void (*init_irq)(void); //是个函数指针,在sourceinside里边搜一搜。
......
};
init_irq成员在文件arch/arm/mach-s3c2440/mach-tq2440.c中被赋值为s3c24xx_init_irq函数MACHINE_START(S3C2440, "TQ2440")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq, //终于找到了!! init_IRQ()函数中通过函数指针init_arch_irq调用的真正内容了!!!分析这个函数,看看究竟做了些真么。
.map_io = tq2440_map_i