ARMLINUX的中断系统.docx
- 文档编号:9674091
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:26
- 大小:28.03KB
ARMLINUX的中断系统.docx
《ARMLINUX的中断系统.docx》由会员分享,可在线阅读,更多相关《ARMLINUX的中断系统.docx(26页珍藏版)》请在冰点文库上搜索。
ARMLINUX的中断系统
1,entry-armv.S
.macro irq_handler
1:
get_irqnr_and_baser0,r6,r5,lr
movner1,sp
routinecalledwithr0=irqnumber,r1=structpt_regs*
adrnelr,1b 返回到1处,asm_do_IRQ返回后将再次查询发生的中断
bneasm_do_IRQ kernel的中断处理函数
...
.endm
2,entry-macro.S
下面这个宏查询ISPR(IRQ待定中断服务寄存器,当有需要处理的中断时,这个寄存器的相应位会置位,任意时刻,最多一个位会置位),计算出的中断号放在irqnr指定的寄存器中;这个宏在不同的ARM芯片上是不一样的,下面是s3c44b0x的定义
.macro get_irqnr_and_base, irqnr,irqstat,base,tmp
ldr\base,=S3C44B0X_I_ISPR 装入中断服务寄存器地址
ldr\base,[\base] 装入中断服务寄存器值
mov\irqnr,#0
2222:
tst\base,#1 测试中断位
bne1111f OK,找到
add\irqnr,\irqnr,#1 中断号加1
mov\base,\base,lsr#1 中断服务寄存器值右移1位,比较下一位
cmp\irqnr,#NR_IRQS 比较一下,是不是超出了总的中断号
bcc2222b 还没找到,继续
1111:
.endm
3,下面这个宏是所有中断服务过程进入时的前序,主要是在当前堆栈上分配一个pt_regs结构,把r0-r15以及cpsr等保存到这个结构中,在进入irq_handler时,sp指向pt_regs底端
.macro svc_entry
subsp,sp,#S_FRAME_SIZE sizeof(pt_regs),分配一个pt_regs结构
stmibsp,{r1-r12} 保存r1-r12
ldmiar0,{r1-r3} r0指向何处?
这个地方的容是什么?
参见4节
(1)
(2)处
addr5,sp,#S_SP S_SP为sp寄存器在pt_regs中的偏移
movr4,#-1 ORIG_r0=-1?
addr0,sp,#S_FRAME_SIZE r0为中断前的堆栈指针,将成为pt_regs中的sp的值
strr1,[sp] savethe"real"r0copied fromtheexceptionstack
movr1,lr
Wearenowreadytofillintheremainingblanksonthestack:
r0-sp_svc
r1-lr_svc
r2-lr_,alreadyfixedupforcorrectreturn/restart
r3-spsr_
r4-orig_r0(seept_regsdefinitioninptrace.h)
stmiar5,{r0-r4}
.endm
4,
.macro vector_stub,name,mode,correction=0
.align5
vector_\name:
.if \correction
sublr,lr,#\correction 修正返回地址,如果必要的话
.endif
Saver0,lr_ (parentPC)andspsr_
(parentCPSR)
stmiasp,{r0,lr} saver0,lr
(1)(为什么向上长呢?
)
mrslr,spsr
strlr,[sp,#8] savespsr
PrepareforSVC32mode.IRQsremaindisabled.
mrsr0,cpsr
eorr0,r0,#(\mode^SVC_MODE)
msrspsr_cxsf,r0
thebranchtablemustimmediatelyfollowthiscode
andlr,lr,#0x0f 这里时,lr的值是spsr的值,因此,这个指令之后lr的值为spsr[0-3],即,系统模式的低4位
movr0,sp
(2)
ldrlr,[pc,lr,lsl#2] lr=pc+lr<<2,usr:
pc,fiq:
pc+4,irq:
pc+8,svc:
pc+12,abt:
pc+28,und:
pc+44,system:
pc+60
movspc,lr branchtohandlerinSVCmode
.endm
对于irq中断,会这样调用上面这个宏:
vector_stubirq,IRQ_MODE,4
5,中断处理过程总体结构,当中断发生后控制先转移到4,然后跳转到__irq_svc
__irq_svc:
svc_entry
irq_handler
ldrr0,[sp,#S_PSR] irqsarealreadydisabled,S_PSR为cpsr在pt_regs中的偏移;sp指向在svc_entry中分配的pt_regs结构
msrspsr_cxsf,r0 恢复spsr
ldmiasp,{r0-pc}^ loadr0-pc,cpsr
...
.global__stub_start
__stub_start:
vector_stubirq,IRQ_MODE,4
.long__irq_usr
.long__irq_invalid
.long__irq_invalid
.long__irq_svc
.long__irq_invalid
...
以下与irq中断无关,但是是arm整个异常处理结构的一部分,因此列示在这里
vector_stubdabt,ABT_MODE,8
...
vector_stubpabt,ABT_MODE,4
...
vector_stubund,UND_MODE
...
vector_fiq:
...
vector_addrexcptn:
...
.LCvswi:
...
.globl__stubs_end
__stubs_end:
...
下面这些才是最初的入口点,__vector_start和__vector_end之间的代码会被移动到CONFIG_VECTORS_BASE开始的地方,例如0xc000000
.globl__vectors_start
__vectors_start:
swiSYS_ERROR0 Reset
bvector_und+stubs_offset Undefinedinstruction
ldrpc,.LCvswi+stubs_offset swiinstruction
bvector_pabt+stubs_offset PrefetchAbort
bvector_dabt+stubs_offset DataAbort
bvector_addrexcptn+stubs_offset ARMreserved
b vector_irq +stubs_offset IRQ
bvector_fiq+stubs_offset FIQ
.globl__vectors_end
__vectors_end:
...
附录1,arm体系下pt_regs结构
struct pt_regs{
longuregs[18];
};
uregs[0]-uregs[17]分别对应,r0-r15,cpsr,ORIG_r0
附录1,irq中断时堆栈的变化
--------
spsr
--------
lr,中断返回地址,修正后的
--------
r0
--------<-进入irq_svc之前,sp的值,也是r0的值
pt_regs
---------<-进入svc_entry后,sp的值
浅析armlinux2.4.19中断irq分发例程的派发流程之根基
文章来源:
应用程序运行在user模式,对应arm的cpsr&15的值为0,而核代码运行在svc模式,对应arm的cpsr&15的值为3,
所以,如果应用程序在运行期间,即usr模式下,arm发生了irq中断,那么中断处理代码得知后会调用__irq_usr分发处理例程处理irq中断,如果在系统调用syscall之类使程序运行在核空间执行核程序的时候,即svc模式下,arm发生了irq中断,那么中断处理代码得知后会调用__irq_svc分发处理例程处理irq中断,中断程序是怎么识别svc和usr模式,进而派发相应的__irq_usr和__irq_svc分发例程的呢,来看看代码部分:
//1.arch\arm\kernel\entry-armv.S
...
.LCvswi:
.word vector_swi
.LCsirq:
.word __temp_irq
.LCsund:
.word __temp_und
.LCsabt:
.word __temp_abt
__stubs_end:
.equ __real_stubs_start, .LCvectors + 0x200
.LCvectors:
swi SYS_ERROR0
b __real_stubs_start + (vector_undefinstr - __stubs_start)
ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
b __real_stubs_start + (vector_prefetch - __stubs_start)
b __real_stubs_start + (vector_data - __stubs_start)
b __real_stubs_start + (vector_addrexcptn - __stubs_start)
//irq中断发生后,cpu捕获中断,跳转到这里执行vector_IRQ处理程序[gliethttp_20071225]
//中断处理代码位于0xFFFF0000地址之后的空间中,
//为了更透彻的理解,最好先看看另3篇文章
//《浅析arm-linux中断vector向量表的建立流程》
//《浅析armlinux-setup_arch()->create_mapping()函数5-2-2》
//《浅析arm-linux系统调用的流程》
//文章1:
//文章2:
//文章3:
//为了更好理解上面的这几篇文章,最好先看看《浅析armlinux2.4.19启动程序[head-armv.s文件]》
//文章4:
b __real_stubs_start + (vector_IRQ - __stubs_start)
b __real_stubs_start + (vector_FIQ - __stubs_start)
...
//2.arch\arm\kernel\entry-armv.S
...
vector_IRQ:
savemodespecificregisters
ldr r13, .LCsirq //取出LCsirq变量的地址,用来存放lr
sub lr, lr, #4 //lr-4,这是arm必须的
str lr, [r13] //将计算之后的返回地址lr存入LCsirq变量
//读取此次irq中断发生时,cpu所处模式spsr,即,中断发生时cpu正在用户空间运行用户应用程序,
//还是在核空间svc模式下运行核代码,lr&15的数值为arm进入irq之前cpu运行的模式值
//如果lr&15=0表示,此次irq中断发生时,cpu正运行用户空间的用户程序,
//如果lr&15=3表示,此次irq中断发生时,cpu正运行核空间的核代码[gliethttp_20071225]
mrs lr, spsr
str lr, [r13, #4]
mrs r13, cpsr
bic r13, r13, #MODE_MASK
orr r13, r13, #I_BIT | MODE_SVC
//切换到svc模式,因为当前cpsr为irq模式,所以可以修改cpsr,
//注意在usr模式下cpsr的数值,即使使用了msrspsr_c,r13赋值语句,
//因为usr模式不允许修改cpsr,所以r13的数值并不能被真正赋值给spsr,
//执行完赋值语句之后,spsr的数值不会发生任何改变,仍然是原来的值[gliethttp_20071225]
msr spsr_c, r13
and lr, lr, #15
//lr&15的值为发生irq之前cpu所在的空间,
//0:
在用户空间发生了irq中断
//3:
在核空间发生了irq中断
//lr<<2=lr*4也就是pc+0和pc+12
//分别对应LCtab_irq的.word__irq_usr域和.word__irq_svc域
ldr lr, [pc, lr, lsl #2]
//跳转到__irq_usr或者__irq_svc处理此次irq中断[gliethttp_20071225]
movs pc, lr
.LCtab_irq:
.word __irq_usr 0 (USR_26 / USR_32)//用户空间发生irq中断
.word __irq_invalid 1 (FIQ_26 / FIQ_32)
.word __irq_invalid 2 (IRQ_26 / IRQ_32)
.word __irq_svc 3 (SVC_26 / SVC_32)//核空间发生irq中断
.word __irq_invalid 4
.word __irq_invalid 5
.word __irq_invalid 6
.word __irq_invalid 7
.word __irq_invalid 8
.word __irq_invalid 9
.word __irq_invalid a
.word __irq_invalid b
.word __irq_invalid c
.word __irq_invalid d
.word __irq_invalid e
.word __irq_invalid f
...
.LCvswi:
.word vector_swi
.LCsirq:
.word __temp_irq
.LCsund:
.word __temp_und
.LCsabt:
.word __temp_abt
ARMLinux中断分析
ARM体系结构中,把复位、中断、快速中断等都看作‘异常’,当这些‘异常’发生时,CPU会到固定地址处去找指令,他们对应的地址如下:
地址
异常类型
进入时的工作模式
0x00000000
Reset
Supervisor
0x00000004
Und
Undefined
0x00000008
Softinterupt
Supervisor
0x0000000c
Abort(prefetch)
Abort
0x00000010
Abort(data)
Abort
0x00000014
Reserved
Reserved
0x00000018
IRQ
IRQ
0x0000001c
FIQ
FIQ
首先要明确的一点就是,无论存地址空间是如何映射的,以上这些地址都不会变,比如当有快速中断发生时,ARM将铁定到0X0000001C这个地址处取指令。
这也是BOOTLOADER把操作系统引导以后,存必须重映射的原因!
否则操作系统不能真正接管整套系统!
LINUX启动以后要初始化这些区域,初始化代码在main.c中的start_kernel()中,具体是调用函数trap_ini()来实现的。
如下面所示(具体可参照entry-armv.S):
.LCvectors:
swiSYS_ERROR0
b__real_stubs_start+(vector_undefinstr-__stubs_start)
ldrpc,__real_stubs_start+(.LCvswi-__stubs_start)
b__real_stubs_start+(vector_prefetch-__stubs_start)
b__real_stubs_start+(vector_data-__stubs_start)
b__real_stubs_start+(vector_addrexcptn-__stubs_start)
b__real_stubs_start+(vector_IRQ-__stubs_start)
b__real_stubs_start+(vector_FIQ-__stubs_start)
ENTRY(__trap_init)
stmfdsp!
{r4-r6,lr}
adrr1,.LCvectorssetupthevectors
ldmiar1,{r1,r2,r3,r4,r5,r6,ip,lr}
stmiar0,{r1,r2,r3,r4,r5,r6,ip,lr}
addr2,r0,#0x200
adrr0,__stubs_startcopystubsto0x200
adrr1,__stubs_end
1:
ldrr3,[r0],#4
strr3,[r2],#4
cmpr0,r1
blt1b
LOADREGS(fd,sp!
{r4-r6,pc})
以上可以看出这个函数初始化了中断向量,实际上把相应的跳转指令拷贝到了对应的地址。
当发生中断时,不管是从用户模式还是管理模式调用的,最终都要调用do_IRQ():
__irq_usr:
subsp,sp,#S_FRAME_SIZE
stmiasp,{r0-r12}saver0-r12
ldrr4,.LCirq
addr8,sp,#S_PC
ldmiar4,{r5-r7}getsavedPC,SPSR
stmiar8,{r5-r7}savepc,psr,old_r0
stmdbr8,{sp,lr}^
alignment_trapr4,r7,__temp_irq
zero_fp
1:
get_irqnr_and_baser0,r6,r5,lr
movner1,sp
adrsvcne,lr,1b
routinecalledwithr0=irqnumber,r1=structpt_regs*
bnedo_IRQ调用do_IRQ来实现具体的中断处理
movwhy,#0
get_current_tasktsk
bret_to_user
对于以上代码,在很多文章中都有过分析,这里不再赘述。
Linux每个中断通过一个结构irqdesc来描述,各中断的信息都在这个结构中得以体现:
structirqdesc{
unsignedintnomask:
1;/*IRQdoesnotmaskinIRQ*/
unsignedintenabled:
1;/*IRQiscurrentlyenabled*/
unsignedinttriggered:
1;/*IRQhasoccurred*/
unsignedintprobing:
1;/*IRQinuseforaprobe*/
unsignedintprobe_ok:
1;/*IRQcanbeusedforprobe*/
unsignedintvalid:
1;/*IRQclaimable*/
unsignedintnoautoenable:
1;/*don'tautomaticallyenableIRQ*/
unsignedintunused:
25;
void(*mask_ack)(unsignedintirq);/*MaskandacknowledgeIRQ*/
void(*mask)(unsignedintirq);/*MaskIRQ*/
void(*unma
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARMLINUX 中断 系统