
Linu中断处理流程.docx
13页Linux中断处理流程先从函数注册引出问题吧一、 中断注册方法在linux内核中用于申请中断的函数是reques t_irq (),函数原型在 Kernel/irq/manage.c 中定义:int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)irq是要申青的硬件中断号handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调 用这个函数,dev_id参数将被传递给它irqflags是中断处理的属性,若设置了 IRQF_DISABLED(老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序 是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程 序不屏蔽;若设置了 IRQF_SHARED(老版本中的SA_SHIRQ ),则表示多个设备共享中断,若设置了 IRQF_SAMPLE_RANDOM (老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。
这几个 flag是可以通过或的方式同时使用的)dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL devname设置中断名称,在cat /proc/interrupts中可以看到此名称request_irq()返回0表示成功,返回TNVAL表示中断号无效或处理函数指针为 NULL,返回-EBUSY表示中断已经被占用且不能共享关于中断注册的例子,大家可在内核中搜索下request_irq 在编写驱动的过程中,比较容易产生疑惑的地方是:1、中断向量表在什么位置?是如何建立的?2、 从中断开始,系统是怎样执行到我自己注册的函数的?3、 中断号是如何确定的?对于硬件上有子中断的中断号如何确定?4、 中断共享是怎么回事,dev_id的作用是?本文以2.6.26内核和S3C2410处理器为例,为大家讲解这几个问题二、 异常向量表的建立在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置: 一个是0,另一个是0xffff0000可以通过CP15协处理器c1寄存器中V位 (bit[13])控制V和中断向量表的对应关系如下:V=0 〜 0x00000000~0x0000001CV=1 〜 0xffff0000~0xffff001Carch/arm/mm/proc-arm920.S 中.sec tion ".text.init", #alloc, #execins tr__arm920_setup: orr r0, r0, #0x2100@ ..1. ...1 ..11 ...1//bit13=1中断向量表基址为0xFFFF0000。
R0的值将被付给CP15的C1.在linux中,向量表建立的函数为:init /main.c->s tart_ kernel>t rap_i nit() void __init trap_init(void)—{ -unsigned long vectors = CONFIG_VECTORS_BASE;memcpy((void *)vectors, __vectors_start,__vectors_end - __vectors_start);memcpy((void *)vectors + 0x200, __stubs_start,__stubs_end — __stubs_start);}在2.6.26内核中CONFIG_VECTORS_BASE最初是在各个平台的配置文件中设定的, 如:arch/arm/configs/s3c2410_defconfig 中C0NFIG_VECT0RS_BASE=0xffff0000__vectors_end 至 __vectors_start 之间为异常向量表位于 arch/arm/kernel/entry-armv.S.globl __vectors_startvectors_start:swi SYS_ERROR0:vector_pabt + stubs_offsetvector_dabt + stubs_offsetvector_addrexcptn + stubs_offsetvector_irq + stubs_offsetvector_fiq + stubs_offset//未定义指令异常://软件中断异常://数据异常://保留://普通中断异常://快速中断异常:b vec to r_und + stu bs_offse t //复位异常: ldr pc, .LCvswi + stubs_offset b b b b b.globl __vectors_end:__vectors_end:__stubs_end至 _stubs_start之间是异常处理的位置。
也位于文件 arch/arm/kernel/entry—armv.S 中vector_und、 vector_pabt、 vector_irq、 vector_fiq都在它们中间stubs_offset 值如下: .equ stubs_offset, __vectors_start + 0x200 — __stubs_startstubs_offset是如何确定的呢?(引用网络上的一段比较详细的解释) 当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±32M) 写入指令码从上面的代码可以看到中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为 指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的我们把搬移前的中断向量表中的irq入口地址记irq_PC,它在中断 向量表的偏移量就是irq_PC—vectors_start,vector_irq在stubs中的偏移量是vector_irq-stubs_start,这两个偏移量在搬移前后是不变的搬移后vectors_start 在 OxffffOOOO 处,而 stubs_start 在 0xffff0200 处,所以搬移 后的vector_irq相对于中断向量中的中断入口地址的偏移量就是,200+vector_irq在stubs中的偏移量再 减去中断入口在向量表中的偏移量,即200+vector_irq-stubs_start-irq_PC+vectors_start 二(vector_irq-irq_PC) + vectors_start+200-Stubs_start,对于括号内的值实际上就是中断向量表中写 的vector_irq,减去irq_PC是由汇 编器完成的,而后面的 一vectors_start+200-Stubs_start 就应该是 stubs_offset , 实 际上在 entry-armv.S中也是这样定义的三、中断处理过程■这一节将以S3C2410为例,描述linux-2.6.26内核中,从中断开始,中断是如 何一步一步执行到我们注册函数的。
■3.1 中断向量表 arch\arm\kernel\en try—armv.S__vectors_start:swi SYS_ERROROb vector_und + stubs_offsetldr pc, .LCvswi + stubs_offsetb vector_pabt + stubs_offsetb vector_dabt + stubs_offsetb vector_addrexcptn + stubs_offsetb vector_irq + stubs_offsetb vector_fiq + stubs_offset.globl __vectors_end__vectors_end:中断发生后,跳转到b vector_irq + stubs_offset的位置执行注意现在的向 量表的初始位置是OxffffOOOO■3.2 中断跳转的入口位置 arch\arm\kernel\entry-armv.S.globl __stubs_start__stubs_start:/** Interrupt dispatcher*/vector_stub irq, IRQ_M0DE, 4 @IRQ_M0DE 在include\asm\ptrace.h 中定义:Oxl2.long __irq_usr @ O (USR_26 / USR_32).long __irq_invalid @ 1 (FIQ_26 / FIQ_32).long __irq_invalid @ 2 (IRQ_26 / IRQ_32).long __irq_svc @ 3 (SVC_26 / SVC_32).long __irq_invalid @ 4.long __irq_invalid @ 5.long __irq_invalid @ 6.long __irq_invalid @ 7.long __irq_invalid @ 8.long __irq_invalid @ 9.long __irq_invalid @ a.long __irq_invalid @ b.long __irq_invalid @ c.long __irq_invalid @ d.long __irq_invalid @ e.long __irq_invalid @ f 上面代码中vector_stub宏的定义为:.macro vector_stub, name, mode, correction=0.align 5vector_\name:.if \correctionsub lr, lr, #\correction.endif@@ Save rO, lr_ (parent PC) and spsr_@ (parent CPSR)@st mia sp, {r0, lr} @ save r0, lrmrs lr, spsrstr lr, [sp, #8] @ save spsr@@ Prepare for SVC32 mode. IRQs remain disabled.@mrs r0, cpsreor rO, rO, #(\mode 八 SVC_MODE)msr spsr_cxsf, rO @为后面进入svc模式做准备@@ the branch table must immediately follow this code@and lr, lr, #0x0f @进入中断前的mode的后4位@#define USR_MODE 0x00000010@#define FIQ_MODE 0x00000011@#define IRQ_MODE 0x00000012@#define SVC_MODE 0x00000013@#define ABT_MODE 0x00000017@#define UND_MODE 0x0000001b@#define SYSTEM_MODE 0x0000001fmov r0, spldr lr, [pc, lr。












