转了个圈,又回来了
分类: LINUX
2011-04-05 20:31:13
由前面一篇文章可以知道,其实在中断来了以后,会调用IRQ对应的struct irqdesc->handle_irq函数,这个函数又是怎么来的呢。
这里分别从系统和用户的角度来描述Linux系统对中断的处里。
一 系统角度
1. Trap_init
该函数是将系统的异常处理函数的入口地址搬移到对应的向量地址。该函数由start_kernel函数调用。
2. Init_irq
这个函数也由start_kernel函数调用,该函数就是用来给各个IRQ对应的struct irqdesc结构体中的handler_irq来赋值的。
在我所在的源代码包中,init_irq函数又调用了init_arch_irq函数。那init_arch_irq函数又在哪里定义呢,实际上这个函数指正是在setup_arch(该函数同样被start_kernel函数调用)中赋值的
init_arch_irq = mdesc->init_irq;
再看mdesc
struct machine_desc *mdesc;
mdesc = setup_machine(machine_arch_type); ---------最后会调用__lookup_machine_type,__lookup_machine_type 函数根据平台代号会找出预订义在(.arch.info)区中编译配置时确定的Linux系统所支持的各种ARM硬件平台描述结构struct machine_desc。
在.\arch\arm\mach-mx27目录下有
MACHINE_START(MX27_MDK27V0, "Morninghan i.MX27 MDK27V0")
/* maintainer: Freescale Semiconductor, Inc. */
#ifdef CONFIG_SERIAL_8250_CONSOLE
.phys_io = CS5_BASE_ADDR,
.io_pg_offst = ((CS5_BASE_ADDR_VIRT) >> 18) & 0xfffc,
#else
.phys_io = AIPI_BASE_ADDR,
.io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
#endif
.boot_params = PHYS_OFFSET + 0x100,
.fixup = fixup_mxc_board,
.map_io = mxc_map_io,
.init_irq = mxc_init_irq,
.init_machine = mxc_board_init,
.timer = &mxc_timer,
MACHINE_END
其中
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__attribute_used__ \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
上面就是定义了该硬件平台的struct machine_desc结构体。其中就包括
.init_irq = mxc_init_irq,也就是上面所说的mdesc->init_irq。
再看mxc_init_irq -------set_irq_handler(i, do_level_IRQ);
do_level_IRQ ------- handle_level_irq 这就调到了我们前面文章中提到的函数了。
Linux系统对中断的软件处理就是这样的:
首先需要将硬件平台的结构体struct machine_desc的成员init_irq赋值,并且将该结构体放到(.arch.info)区。然后的动作都在start_kernel函数里执行:
Setup_arch:在struct machine_desc中找出mxc_init_irq。
Trap_init: 搬移异常处理函数入口到中断向量表。
Init_IRQ: 执行mxc_init_irq,为各个irq对应struct irqdesc结构体的handler_irq赋值。
二 用户角度
从用户的角度看,就是需要给各个irq对应的struct irqdesc . action.handler赋值,就是实现各个中断具体的处理函数,这个过程是有request_irq函数实现的。