我們知道,arm的異常和復位向量表有兩種選擇,一種是低端向量,向量位址位於0x00000000,另一種是高階向量,向量位址位於0xffff0000,linux選擇使用高階向量模式,也就是說,當異常發生時,cpu會把pc指標自動跳轉到始於0xffff0000開始的某乙個位址上。
arm異常向量表
位址異常類別
0xffff0000
復位0xffff0004
未定義指令
0xffff0008
軟中斷swi
0xffff000c
prefetch abort
0xffff0010
data abort
0xffff0014
保留0xffff0018
irq0xffff001c
fiq
中斷向量表在arch/arm/kernel/entry_armv.s中定義,系統啟動階段setup_arch函式會呼叫arch/arm/kernel/traps.h中的early_trap_init,
這個函式會把__vectors_start(這個位址是不是鏈結在核心映象,編譯完了賦值的)開始的**拷貝到0xffff0000處,
把__stubs_start開始的**拷貝到0xffff+0x200處,這樣中斷來時,就可以跳轉到相應的中斷向量入口。
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
真正的向量跳轉表,位於__vectors_start和__vectors_end之間
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start
.globl __vectors_start
__vectors_start:
arm( swi sys_error0 )
thumb( svc #0 )
thumb( nop )
w(b) vector_und + stubs_offset
w(ldr) pc, .lcvswi + stubs_offset
w(b) vector_pabt + stubs_offset
w(b) vector_dabt + stubs_offset
w(b) vector_addrexcptn + stubs_offset
w(b) vector_irq + stubs_offset
w(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
跳轉部分
.globl __stubs_start
__stubs_start:
/** interrupt dispatcher
*///這一句巨集展開後實際上就是定義了vector_irq,根據進入cpu中斷前的模式,分別跳轉到__irq_usr或__irq_svc
vector_stub irq, irq_mode, 4
.long __irq_usr @ 0 (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
... /*
* data abort dispatcher
* enter in abt mode, spsr = usr cpsr, lr = usr pc
*///這一句巨集展開後實際上就是定義了vector_dabt,根據進入cpu中斷前的模式,分別跳轉到__dabt_usr或__dabt_svc
vector_stub dabt, abt_mode, 8
... /*
* prefetch abort dispatcher
* enter in abt mode, spsr = usr cpsr, lr = usr pc
*/vector_stub pabt, abt_mode, 4
... /*
* undef instr entry dispatcher
* enter in und mode, spsr = svc/usr cpsr, lr = svc/usr pc
*/vector_stub und, und_mode
...vector_fiq:
disable_fiq
subs pc, lr, #4
vector_addrexcptn:
b vector_addrexcptn
.lcvswi:
.word vector_swi
.globl __stubs_end
__stubs_end:
__irq_usr和__irq_svc的區別是進入和退出中斷時是否進行使用者棧和核心棧之間的切換等,他們最終都會進入到irq_handler這個巨集
.macro irq_handler
get_irqnr_preamble r5, lr
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@@ routine called with r0 = irq number, r1 = struct pt_regs *
@adrne lr, bsym(1b)
bne asm_do_irq
.endm
get_irqnr_preamble和get_irqnr_and_base這兩個巨集的目的是從中斷控制器獲得irq的編號,然後呼叫asm_do_irq,到這裡中斷程式完成了從彙編**到c**的傳遞,並且獲得了引起中斷的irq編號。
asm_do_irq() arch/arm/kernel/irq.c
generic_handle_irq()
generic_handle_irq_desc
desc->handle_irq 系統中斷處理函式
desc->chip->ack(irq) 清除中斷
handle_irq_event(irq, action) 遍歷並呼叫這個desc下所有的使用者中斷處理函式action
action->handler(irq, action->dev_id); 使用者中斷處理函式
當系統進入中斷後,首先會進入系統中斷處理函式,這個之前由set_irq_handler註冊給desc->irq_flow_handler_t handler_irq了,在系統中斷處理函式中又會呼叫使用者中斷處理函式,這個之前由request_irq註冊給desc->struct irq_action *action了
linux中斷(interrupt)子系統之二:arch相關的硬體封裝層
作業系統學習(三) 中斷概述
中斷分為外部硬體中斷 內部中斷和軟中斷。中斷也是作業系統的一種解決方案,那麼為什麼需要引入中斷機制呢。為了分享計算能力,處理器應當為多使用者多工提供硬體一級的支援。在單處理系統中,當乙個任務的執行時,還有其他多個任務等待獲取處理器來執行。當乙個任務等待輸入輸出時,應該把處理器轉給另乙個任務執行。但問...
Linux中斷子系統
linux kernel的中斷子系統之 一 一 前言 乙個合格的linux驅動工程師需要對kernel中的中斷子系統有深刻的理解,只有這樣,在寫具體driver的時候才能 1 正確的使用linux kernel提供的的api,例如最著名的request threaded irq request ir...
linux中斷子系統
參考引用 wowotech 乙個很好的linux技術部落格。一 概述 目的kernel管理硬體裝置的方式 輪詢 中斷。中斷效率高且反應快於輪詢,因為它利用了硬體本身執行指令前會做的 中斷電訊號週期輪詢 分類中斷分為同步 synchronous 和非同步 asynchronous 同步也稱為異常,由c...