写在前面
作者一直支持GPL的精神。允许任何人自由使用、转载、复制和再分发,但必须保留作者署名,必须保证全文完整转载,包括完整的版权声明。
由于作者水平有限,因此不能保证文章内容准确无误,请批判阅读。如果你发现任何错误或对文章内容有任何建议 ,欢迎你与我联系: Email: caiallen@tom.com QQ群: 14765968
最近因为公司项目忙,好久没更新这里了。也因为项目,才发现原来ARM 的bootloader默认是不支持中断嵌套的,所以必须得自己实现。同时也发现,44b0有向量中断和非向量中断之分,而2410是没有向量中断的。也许这样说并不准确。因为对2410来说,它有:
b ResetHandler ; 0x00000000 b HandlerUndef ; 0x00000004 handler for Undefined mode b HandlerSWI ; 0x00000008 handler for SWI interrupt b HandlerPabort ; 0x0000000c handler for PAbort b HandlerDabort ; 0x00000010 handler for DAbort b . ; 0x00000014
b HandlerIRQ ; 0x00000018 handler for IRQ interrupt b HandlerFIQ ; 0x0000001c handler for FIQ interrupt
这几个地址存放的就是向量表。然而它又不像44b0存在以下地址的向量表:
; 44b0的中断向量表 ResetEntry b ResetHandler ; for debug b HandlerUndef ; handlerUndef b HandlerSWI ; SWI interrupt handler b HandlerPabort ; handlerPAbort b HandlerDabort ; handlerDAbort b . ; handlerReserved b HandlerIRQ b HandlerFIQ VECTOR_BRANCH ldr pc, = HandlerEINT0 ; mGA 0x20 ldr pc, = HandlerEINT1 ; ldr pc, = HandlerEINT2 ; ldr pc, = HandlerEINT3 ; ldr pc, = HandlerEINT4567 ; ldr pc, = HandlerTICK ; mGA 0x34 b . b . ldr pc, = HandlerZDMA0 ; mGB 0x40 ldr pc, = HandlerZDMA1 ; ldr pc, = HandlerBDMA0 ; ldr pc, = HandlerBDMA1 ; ldr pc, = HandlerWDT ; ldr pc, = HandlerUERR01 ; mGB 0x54 b . b . ldr pc, = HandlerTIMER0 ; mGC 0x60 ldr pc, = HandlerTIMER1 ; ldr pc, = HandlerTIMER2 ; ldr pc, = HandlerTIMER3 ; ldr pc, = HandlerTIMER4 ; ldr pc, = HandlerTIMER5 ; mGC 0x74 b . b . ldr pc, = HandlerURXD0 ; mGD 0x80 ldr pc, = HandlerURXD1 ; ldr pc, = HandlerIIC ; ldr pc, = HandlerSIO ; ldr pc, = HandlerUTXD0 ; ldr pc, = HandlerUTXD1 ; mGD 0x94 b . b . ldr pc, = HandlerRTC ; mGKA 0xa0 b . b . b . b . b . ; mGKA b . b . ldr pc, = HandlerADC ; mGKB 0xc0 b . ; b . ; b . ; b . ; b . ; mGKB b . b . ldr pc, = EnterPWDN ; 0xe0= EnterPWDN
这里就必须讲一下向量中断模式和非向量中断模式的概念 向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址,函数中,节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会自动跳转到HandlerADC函数中。
非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt pending寄存器中对应标志位置位 然后跳转到位于0x18处的统一中断函数中, 该函数通过读取interrupt pending寄存器中对应标志位来判断中断源,并根据优先级关系再跳到对应中断源的处理代码中。
现在说回中断嵌套。要想实现中断可嵌套并安全正确地返回,现场保护是关键。在IRQ中断发生时,先在IRQ模式保护现场,然后转到SVC模式把现场环境拷贝到SVC的堆栈,处理IRQ中断,并在这个模式下恢复现场。下面是我对2410的bootloader做了修改,实现了IRQ中断嵌套:
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * * * ; * * IsrIRQ * * ; * * * * ; 真正的非向量IRQ中断入口; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * IsrIRQ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 1) 在中断模式下保护被中断的模式的环境; 1- 1 lr- 4压栈,lr- 4才是被中断的模式的PC返回地址; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = SUBS LR, LR, #4 STMFD {LR}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 2 再压入lr, 仅作占位,该值在被中断的模式的lr的寄出器中 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = STMFD {LR}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 3 保存R0~R12的值。这样在后面的算法里可以使用R0~R12; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = STMFD {R0- R12}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 4 保存SPSR; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MRS R0, SPSR STMFD {R0} ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 5 恢复IRQ模式下的堆栈指针,指向被中断前的位置; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ADD R3, SP, #64 MOV SP, R3; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; (2)切换到SVC模式,利用SVC的堆栈保存现场,并在四J较麓鞩RQ中断; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MSR CPSR_cxsf, #SVCMODE| I_BIT ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; (3)拷贝现场; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDMDB {R0} STMFD {R0} LDMDB {R0} STMFD {LR} LDR R1, = 56 0 LDMDB {R0} STMFD {R0} SUBS R1, R1, #4 BNE %B0 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 4) 设置中断入口; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDR R9, = INTOFFSET LDR R9, [ R9] ; 读入中断偏移码, 确定中断源 LDR R8, = HandleEINT0; 二级跳转表的首地址 ADD R8, R8, R9, LSL #2 ; R8= R8+ R9X4得到相应的中断入口地址, LDR R8, [ R8] ; 把中断偏移地址和基地址相加 MOV LR, PC ADD LR, LR, #4 MOV PC, R8; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 5) 中断返回后,在恢复现场前,屏蔽所有IRQ中断; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MRS R0, CPSR ORR R0, R0, #0x80 MSR CPSR_c, R0 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 6) 恢复现场; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDMFD {R0} MSR SPSR_cxsf, R0 LDMFD {R0- R12, LR, PC}^
44b0的非向量中断的实现与2410的类似,因为我使用的是44b0的向量中断,所以,我把下面的:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=$HandleLabel ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
MEND
修改为:
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 1) 在中断模式下保护被中断的模式的环境; 1- 1 lr- 4压栈,lr- 4才是被中断的模式的PC返回地址; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = SUBS LR, LR, #4 STMFD {LR}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 2 再压入lr, 仅作占位,该值在被中断的模式的lr的寄出器中 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = STMFD {LR}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 3 保存R0~R12的值。这样在后面的算法里可以使用R0~R12; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = STMFD {R0- R12}; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 4 保存SPSR; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MRS R0, SPSR STMFD {R0} ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; 1- 5 恢复IRQ模式下的堆栈指针,指向被中断前的位置; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ADD R3, SP, #64 MOV SP, R3; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; (2)切换到SVC模式,利用SVC的堆栈保存现场,并在此模式下处理IRQ中断; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MSR CPSR_cxsf, #SVCMODE| I_BIT ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; (3)拷贝现场; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDMDB {R0} STMFD {R0} LDMDB {R0} STMFD {LR} LDR R1, = 56 0 LDMDB {R0} STMFD {R0} SUBS R1, R1, #4 BNE %B0 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 4) 设置中断入口; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDR R9, =$HandleLabel LDR R9, [ R9] ; 读入中断偏移码, 确定中断源 MOV LR, PC ADD LR, LR, #4 MOV PC, R9; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 5) 中断返回后,在恢复现场前,屏蔽所有IRQ中断; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = MRS R0, CPSR ORR R0, R0, #0x80 MSR CPSR_c, R0 ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; ( 6) 恢复现场; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = LDMFD {R0} MSR SPSR_cxsf, R0 LDMFD {R0- R12, LR, PC}^
注意:当使用上面的中断嵌套处理时,C语言中中断服务程序不能再使用__irq关键字,因为上面已经作了现场环境的保护处理,而__irq的作用也是自动作现场环境处理,而且它的处理是不支持中断嵌套的。