arm 中斷配置以及處理的原始碼分析

迷霧綠洲發表於2015-07-29

CPU的中斷機制是多工的基礎。現代計算機能夠有如此的工作效率很大程度依賴於高速多級的中斷處理。如果CPU沒有中斷處理就只能順序執行程式碼,想不能時時相應外部處理,無法進行多工的工作。
arm的中斷時分為兩級中斷,nomal interrupt和fast interrupt。快速中斷fiq可以打斷進入到niq,不過一般嵌入式系統速度不是很高,任務也不會出現特別時時的需要 一般不會開啟fiq,畢竟開啟之後對於記憶體互斥處理,中間資料儲存將有更高的要求。
一般的soc會在arm外部部署一箇中斷控制器的ip來進行中斷管理。這裡面會維護一個終端的優先順序和記錄中斷狀態。
一下是一份帶有中斷處理的彙編初始程式碼。
.globl _main
.globl start

.equ USERMODE, 0x10
.equ FIQMODE, 0x11
.equ IRQMODE, 0x12
.equ SVCMODE, 0x13
.equ ABORTMODE, 0x17
.equ UNDEFMODE, 0x1b
.equ MODEMASK, 0x1f
.equ NOINT, 0xc0

start:
b reset
interrupt_vector:
LDR PC, _undefined_instruction
LDR PC, _software_interrupt
LDR PC, _prefetch_abort
LDR PC, _data_abort
LDR PC, _not_used
LDR PC, _normal_interrupt
LDR PC, _fast_interrupt

@———————————————-
@ Vector
@———————————————-
_undefined_instruction: .long undefined_instruction
_software_interrupt: .long software_interrupt
_prefetch_abort: .long prefetch_abort
_data_abort: .long data_abort
_not_used: .long not_used
_normal_interrupt: .long normal_interrupt
_fast_interrupt: .long fast_interrupt

undefined_instruction:
B undefined_instruction

software_interrupt:
B software_interrupt

prefetch_abort:
B prefetch_abort

data_abort:
B data_abort

not_used:
B not_used

normal_interrupt:
mrs r8,spsr
@ B normal_interrupt
stmfd sp!, {r0-r12,lr}
ldr r0, =0x00000001
ldr r1, =0x00000002
ldr r2, =0x00000003
ldr r3, =0x00000004
bl rt_hw_trap_irq
ldmfd sp!, {r0-r12,lr}
mrs r8,spsr
@msr cpsr, r8
subs pc, lr, #4

fast_interrupt:
B fast_interrupt

.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
cpsid if
bx lr

/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
cpsie aif
bx lr

.globl test_save_spsr
test_save_spsr:
mrs r9,spsr
bx lr

reset:

———————————————-

Set CPU mode, flush caches, etc.

———————————————-

#set the cpu to svc32 mode
#turn off IRQ/FIQ bit of CPU
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr_c,r0

#vector 0x0
#enable icaches
#little endian
#disable dcaches, mmu
ldr r0, =0x00400078
mcr p15, 0, r0, c1, c0, 0

ldr r0, =0x00000000
mcr p15, 0, r0, c8, c7, 0   @Flush TLB
mcr p15, 0, r0, c7, c7, 0   @ Flush Caches
mcr p15, 0, r0, c7, c10, 4  @ Flush Write Buffer



mrs     r0, cpsr
bic     r0, r0, #MODEMASK
orr     r1,r0,#IRQMODE|NOINT
msr     cpsr_cxsf,r1            /* IRQ mode            */
ldr     sp, =0xa2000000

mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0x53
msr cpsr_c,r0
ldr sp, =0x10003800

@———————————————-
@ jump to main
@———————————————-

b main

這裡面從頭開始分析:
開始是start的入口點
這個地址一般定義為0地址
後面的
LDR PC, _undefined_instruction
LDR PC, _software_interrupt
LDR PC, _prefetch_abort
LDR PC, _data_abort
LDR PC, _not_used
LDR PC, _normal_interrupt
LDR PC, _fast_interrupt
為 0x4 0x8 0xa 0x10.. 的地址
如果arm接收到了中斷會根據中斷的型別分別跳轉到這些地址。這裡常遇到的就是data_abort中斷,這個中斷一般是訪問了非法未定義的地址無法獲取到資料,prefetch_abort中斷時無法獲取到正確的指令的中斷,一般是程式碼區損壞出現了非法指令或者是訪問指令區域錯誤到了非法地址了。
最後兩個就是我們正常的快速中斷和正常中斷了。可以看到normal_interrupt 中斷normal_interrupt:
mrs r8,spsr
@ B normal_interrupt
stmfd sp!, {r0-r12,lr}
ldr r0, =0x00000001
ldr r1, =0x00000002
ldr r2, =0x00000003
ldr r3, =0x00000004
bl rt_hw_trap_irq
ldmfd sp!, {r0-r12,lr}
mrs r8,spsr
@msr cpsr, r8
subs pc, lr, #4
他是跳轉過來之後先馬上儲存自己的執行狀態暫存器,因為後面的cpu執行狀態是在中斷模式,跟使用者模式用的協處理器有幾個是公用的,後面肯定會覆蓋的 ,如果不儲存後面就要恢復不了了 ,儲存完狀態就會跳到中斷處理函式rt_hw_trap_irp 中,執行完這個中斷你就可以回到使用者模式把壓到終端狀態棧的協處理器回覆回來。
這裡需要注意的是cpu有幾個棧,中斷的棧 mrs r0, cpsr
bic r0, r0, #MODEMASK
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 /* IRQ mode */
ldr sp, =0xa2000000

這裡和使用者模式的棧不是一個地址 ,
最後有個需要注意的是:cpu預設上電是不開啟中斷響應的。需要我們用協處理器去開啟他
rt_hw_interrupt_enable:
cpsie aif
bx lr

產生中斷前一定要呼叫他執行。
下一篇將貼出mmu的原始碼分析。

相關文章