Fw 中斷的初始化

2022-09-10 21:42:24 字數 4120 閱讀 9787

要使用中斷肯定得初始化,這些初始化在系統啟動時已經為你做好了,但是我們還是來看看怎樣初始化的,這樣就能更好的理解中斷機制了。

先看下面函式:

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....