要使用中斷肯定得初始化,這些初始化在系統啟動時已經為你做好了,但是我們還是來看看怎樣初始化的,這樣就能更好的理解中斷機制了。
先看下面函式:
355 void __init init_isa_irqs (
void
)356
else
381 }
382 }
上面的函式分為兩個部分,一 個是init_8259a(0),另乙個就是for迴圈了。從名字上我們就可以看出init_8259a()是幹什麼的了,它是用來初始化8259a的, 設定它的相關暫存器,指明了它的工作方式。下面的for迴圈,一共迴圈了nr_irqs(224)次,將剛才所講的irq_desc初始化,初始化了 status,action,depth欄位,然後如果是前16個呼叫set_irq_chip_and_handler_name(),再往下看如果大 於16,那麼給字段chip賦no_irq_chiq這個定義如下 (kernel/irq/handle.c):
88 struct irq_chip no_irq_chip =
;
也就是說大於16是不需要中斷控制器的。
然後再來看函式set_irq_chip_and_handler_name(),設定irq_desc陣列中的chip和handle_irq欄位,其函式定義如下:
594 set_irq_chip_and_handler_name(
unsigned
int irq,
struct irq_chip *chip,
595 irq_flow_handler_t handle,
const
char
*name)
596
函式set_irq_chip()中的主要**為(kernel/irq/chip.c):
int set_irq_chip(
unsigned
int irq,
struct irq_chip *chip)
{struct irq_desc *desc;
desc = irq_desc + irq;
//找到所要初始化的irq_desc
desc-
>chip = chip;
}
函式__set_irq_handler()定義如下(kernel/irq/chip.c):
void
__set_irq_handler(
unsigned
int irq, irq_flow_handler_t handle,
int is_chained,
const
char
*name)
至此init_isa_irqs (void)到這裡結束,那麼誰來呼叫它了?看下面**:
387 void __init native_init_irq(
void
)388
420 }
其中將392行的函式pre_intr_init_hook()展開後就會發現:
30 void __init pre_intr_init_hook(
void
)31
也就是在函式 native_init_irq()裡呼叫了init_isa_irqs (void)。接著看native_init_irq()中的for迴圈,迴圈了224次(nr_vectors - first_external_vector),vector從0x20(first_external_vector)開始。且不等於 0x80(vector != syscall_vector),即系統呼叫,迴圈執行set_intr_gate(vector, interrupt[i]),這個函式就是設定idt中的中斷門描述符(前面講了,佔8位元組,主要儲存中斷處理程式的如夠函式位址),將中斷處理函式入口 函式位址設定為interrupt[i],當第i個中斷發生後跳轉到此位址執行。那麼interrupt陣列又是怎麼實現的了?
69 #
define irq(x,y) \
70 irq#
#x##y#
#_interrupt
71 72 #
define irqlist_16(x) \
73 irq(x,0)
, irq(x,1)
, irq(x,2)
, irq(x,3)
, \74 irq(x,4)
, irq(x,5)
, irq(x,6)
, irq(x,7)
, \75 irq(x,8)
, irq(x,9)
, irq(x,a)
, irq(x,b)
, \76 irq(x,c)
, irq(x,d)
, irq(x,e)
, irq(x,f)
77 78 /* for the irq vectors */
79 static
void
(*interrupt[nr_vectors - first_external_vector])(
void)=
;
先看79行,這個就是函式指標陣列interrupt,注意這個陣列共224項,定義了從0x2到0xf的14個irqlist_16(),而每乙個irqlist_16()又是16個irq(x,y),也就是說一共有224個irq(x,y)。
接著再看巨集#define irq(x,y) irq##x##y##_interrupt
## 表示將字串連線起來,比如irq(0x2,0)就是irq0x20_interrupt,這樣以來就會生成224個這樣的函式,從 irq0x20_interrupt一直到irq0xff_interupt。那麼這些函式是如何定義的了?往下看include/asm-x86_64 /hw_irq.h:
156 #
define irq_name2(nr) nr#
#_interrupt(
void
)157 #
define irq_name(nr) irq_name2(irq#
#nr)
163 #
define build_irq(nr) \
164 asmlinkage void irq_name(nr)
; \165 __asm__
( \166 "\n.p2align\n" \
167 "irq"
#nr "_interrupt:\n\t" \
168 "push $~("
#nr ") ; " \
169 "jmp common_interrupt");
根據156和157兩行的巨集 定義可以知道irq_name(nr)是乙個函式irqnr_interrupt()就是我們剛才上面所提到的函式陣列中interrupt的乙個, 至於是哪乙個就看nr是多少了。這個函式將nr取反(正數留給系統呼叫)壓入堆疊中,後面用到的時候再取反就可以知道中斷號了,然後跳轉到 common_interrupt,這是乙個公共的程式,暫且不說。
這樣我們就定義了乙個interrupt陣列中的乙個函式,這只是乙個函式,通過以下的巨集就可以定義224個了arch/x86_64/kernel/i8259.c:
60 build_16_irqs(0x2) build_16_irqs(0x3)
61 build_16_irqs(0x4) build_16_irqs(0x5) build_16_irqs(0x6)build_16_irqs(0x7)
62 build_16_irqs(0x8) build_16_irqs(0x9) build_16_irqs(0xa)build_16_irqs(0xb)
63 build_16_irqs(0xc) build_16_irqs(0xd) build_16_irqs(0xe)build_16_irqs(0xf)
這樣以後就定義整個interrupt中的每一函式。
至此set_intr_gate(vector, interrupt[i]);執行結束。這樣我們就對idt初始化成功。
from
zynq freeRTOS初始化中斷
問題描述 zynq7000 上 ps standalone裸跑,ps timer計時器中斷,pl ps中斷均工作正常,將 移植到freertos工程時,中斷不執行,task執行正常。解決 xilinx freertos 9.0.1 bsp,中有乙個檔案 portzynq7000.c.定義了乙個全域性...
初始化中斷描述表
現在,我們知道了 80x86 微處理器在硬體級對中斷和異常做了些什麼,接下來,我們可以繼續描述如何初始化中斷描述表。核心啟用中斷以前,必須把 idt表的初始位址裝到 idtr 暫存器,並初始化表中的每項。這項工作是在初始化系統時完成的。int指令允許使用者態程序發出乙個中斷訊號,其值可以是 0 25...
ARM Linux中斷機制之中斷的初始化
一,認識幾個重要結構體 1.中斷描述符 對於每一條中斷線都由乙個 irq desc結構來描述。在include linux irq.h中 struct irq desc cacheline internodealigned in smp 2.中斷硬體操作函式集 在include linux irq....