成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

嵌入式實(shí)時(shí)系統(tǒng)的基石:ARM+Linux中斷設(shè)計(jì)實(shí)戰(zhàn)

系統(tǒng) Linux
如果遇到未知的中斷源,函數(shù)會(huì)返回IRQ_NONE,表示該中斷未被處理,就像指揮官遇到無法識(shí)別的情況時(shí),選擇暫時(shí)不采取行動(dòng),等待進(jìn)一步的信息。

在當(dāng)今數(shù)字化時(shí)代,高效計(jì)算是推動(dòng)科技發(fā)展的核心動(dòng)力。而 ARM 與 Linux 中斷系統(tǒng),宛如開啟這扇高效計(jì)算大門的關(guān)鍵鑰匙。ARM 架構(gòu),以其低功耗、高性能的特性,廣泛應(yīng)用于從智能手機(jī)到工業(yè)控制等各類設(shè)備,為系統(tǒng)運(yùn)行奠定了堅(jiān)實(shí)基礎(chǔ)。Linux 操作系統(tǒng),則憑借開源、靈活的優(yōu)勢(shì),成為眾多開發(fā)者的首選。

那么,中斷系統(tǒng)在其中扮演著怎樣的角色呢?簡(jiǎn)單來說,中斷系統(tǒng)如同一個(gè)智能管家,當(dāng)外部設(shè)備(如鍵盤、鼠標(biāo))或內(nèi)部事件(如定時(shí)器溢出)有服務(wù)請(qǐng)求時(shí),它能迅速通知 CPU 暫停當(dāng)前任務(wù),轉(zhuǎn)而去處理緊急事務(wù),處理完畢后又巧妙地讓 CPU 回到原來的工作中。這種機(jī)制大大提升了系統(tǒng)的響應(yīng)速度與運(yùn)行效率。特別是在 ARM 與 Linux 的組合中,中斷系統(tǒng)經(jīng)過深度優(yōu)化,進(jìn)一步挖掘出兩者的潛力。在接下來的內(nèi)容中,我們將深入剖析 ARM+Linux 中斷系統(tǒng)的工作原理、技術(shù)細(xì)節(jié),一同探尋它是如何為高效計(jì)算賦能的。

一、中斷系統(tǒng):計(jì)算世界的 “緊急響應(yīng)者”

在日常生活中,我們難免會(huì)遭遇各種緊急狀況。當(dāng)火災(zāi)發(fā)生時(shí),煙霧報(bào)警器會(huì)瞬間感應(yīng)到異常,隨即發(fā)出尖銳的警報(bào)聲。這一警報(bào)就如同給消防系統(tǒng)發(fā)送了 “緊急信號(hào)”,消防員們收到信號(hào)后,會(huì)即刻停下手中的其他工作,迅速登上消防車,風(fēng)馳電掣般趕赴火災(zāi)現(xiàn)場(chǎng)。到達(dá)后,他們會(huì)爭(zhēng)分奪秒地展開滅火行動(dòng),直到成功撲滅大火,才會(huì)返回消防站,繼續(xù)待命,等待下一次任務(wù)。又比如在繁忙的交通道路上,突然發(fā)生了嚴(yán)重的交通事故,傷者急需救治。

這時(shí),路人會(huì)馬上撥打 120 急救電話,急救中心接到電話后,會(huì)立即調(diào)度救護(hù)車,醫(yī)護(hù)人員放下手頭正在處理的事務(wù),迅速前往事故地點(diǎn),對(duì)傷者進(jìn)行緊急救治,隨后將傷者送往醫(yī)院,完成任務(wù)后再回到崗位,準(zhǔn)備應(yīng)對(duì)下一次的急救需求。

在計(jì)算機(jī)的世界里,也存在著類似的 “緊急響應(yīng)機(jī)制”,那就是中斷系統(tǒng) 。計(jì)算機(jī)的 CPU 就如同消防員或醫(yī)護(hù)人員,它平時(shí)有條不紊地執(zhí)行著各種程序任務(wù)。而當(dāng)外部設(shè)備(如鍵盤、鼠標(biāo)、網(wǎng)卡等)或者內(nèi)部事件(如定時(shí)器溢出)有緊急事情需要 CPU 處理時(shí),就會(huì)向 CPU 發(fā)送中斷信號(hào)。CPU 在接收到中斷信號(hào)后,會(huì)暫時(shí)停下當(dāng)前正在執(zhí)行的任務(wù),轉(zhuǎn)而去處理這個(gè)中斷請(qǐng)求。等處理完中斷后,再回到原來被中斷的任務(wù)處,繼續(xù)執(zhí)行后續(xù)的指令。

ARM+Linux 中斷系統(tǒng),正是基于 ARM 架構(gòu)的硬件平臺(tái)與 Linux 操作系統(tǒng)相結(jié)合的中斷處理體系。ARM 架構(gòu)憑借其低功耗、高性能以及豐富的外設(shè)接口等優(yōu)勢(shì),在嵌入式領(lǐng)域應(yīng)用廣泛,從手機(jī)、平板電腦到工業(yè)控制設(shè)備、智能家居系統(tǒng),到處都有它的身影。Linux 操作系統(tǒng)則以開源、穩(wěn)定、可定制性強(qiáng)等特點(diǎn),深受開發(fā)者的喜愛,在服務(wù)器領(lǐng)域占據(jù)著重要地位,同時(shí)也在嵌入式系統(tǒng)開發(fā)中被大量采用。ARM+Linux 中斷系統(tǒng)的高效運(yùn)行,對(duì)于保障這些設(shè)備和系統(tǒng)的穩(wěn)定運(yùn)行、實(shí)時(shí)響應(yīng)至關(guān)重要,是理解和開發(fā)基于 ARM+Linux 平臺(tái)應(yīng)用的關(guān)鍵所在。

二、ARM 中斷的硬件基石

2.1ARM 的運(yùn)行模式與異常分類

ARM 處理器擁有七種運(yùn)行模式,就像是一位多才多藝的演員,可以根據(jù)不同的場(chǎng)景切換不同的 “角色” ,每種模式都有其獨(dú)特的用途和權(quán)限,共同協(xié)作維持著系統(tǒng)的穩(wěn)定運(yùn)行。

  • 用戶模式(User Mode):這是用戶程序正常執(zhí)行的模式,就像普通市民在自己的生活空間內(nèi)活動(dòng),權(quán)限相對(duì)有限。在這個(gè)模式下,程序只能執(zhí)行自己的數(shù)據(jù)處理任務(wù),不能隨意操作其他硬件資源,也無法直接切換到其他模式。例如,我們?cè)谑謾C(jī)上運(yùn)行的各類 APP,它們大多運(yùn)行在用戶模式下,受到系統(tǒng)的限制,不能隨意訪問底層硬件,以保障系統(tǒng)的安全和穩(wěn)定。
  • 系統(tǒng)模式(System Mode):屬于特權(quán)模式,類似于城市管理者,雖然和用戶模式共用一套寄存器,但卻擁有更高的權(quán)限,可以不受用戶模式的限制,自由訪問系統(tǒng)資源。操作系統(tǒng)的一些特權(quán)任務(wù)會(huì)利用這個(gè)模式來訪問受控資源,比如對(duì)系統(tǒng)關(guān)鍵文件的讀寫操作等。
  • 中斷模式(IRQ Mode):用于處理一般的中斷請(qǐng)求,當(dāng)硬件產(chǎn)生中斷信號(hào)后,就會(huì)自動(dòng)進(jìn)入該模式,如同城市中的普通應(yīng)急響應(yīng)部門,隨時(shí)準(zhǔn)備處理各種常規(guī)的緊急情況。比如鍵盤按鍵按下、鼠標(biāo)移動(dòng)等操作產(chǎn)生的中斷,都會(huì)由中斷模式來處理。
  • 快速中斷模式(FIQ Mode):主要用于處理對(duì)時(shí)間要求緊急的中斷請(qǐng)求,就像是城市中的特種應(yīng)急部隊(duì),在高速數(shù)據(jù)傳輸及通道處理等場(chǎng)景中發(fā)揮關(guān)鍵作用。例如,在音視頻數(shù)據(jù)的實(shí)時(shí)傳輸過程中,為了保證數(shù)據(jù)的流暢性和及時(shí)性,相關(guān)的中斷就會(huì)由快速中斷模式來處理。它比普通中斷模式速度更快,這是因?yàn)樗鼡碛懈嗟莫?dú)立寄存器(r8 - r14 以及 SPSR 都有對(duì)應(yīng)的 banked 寄存器),模式切換時(shí) CPU 自動(dòng)保存和恢復(fù)這些寄存器的值,無需中斷處理程序手動(dòng)操作,節(jié)省了時(shí)間 。而且它的入口地址(0x1c)與普通中斷(0x18)不同,由于跳轉(zhuǎn)范圍限制,至少少了一條跳轉(zhuǎn)指令,也提高了處理速度。
  • 管理模式(Supervisor Mode):這是 CPU 上電后的默認(rèn)模式,是操作系統(tǒng)的保護(hù)模式,軟中斷(SWI)處理函數(shù)就在此模式下執(zhí)行,就像城市的最高管理決策層。當(dāng)用戶模式下的程序請(qǐng)求使用硬件資源時(shí),會(huì)通過軟件中斷進(jìn)入該模式。比如,用戶程序需要讀取磁盤文件時(shí),就會(huì)觸發(fā)軟中斷,進(jìn)入管理模式,由操作系統(tǒng)來完成具體的磁盤讀取操作。系統(tǒng)復(fù)位或開機(jī)時(shí)也會(huì)進(jìn)入該模式,通常在此模式下進(jìn)行系統(tǒng)的初始化工作。
  • 數(shù)據(jù)訪問終止模式(Abort Mode):當(dāng)程序訪問非法地址或沒有權(quán)限讀取的內(nèi)存地址時(shí),就會(huì)進(jìn)入該模式,類似于城市中的安全檢查部門在發(fā)現(xiàn)非法訪問時(shí)介入。在 Linux 下編程時(shí)經(jīng)常出現(xiàn)的 segment fault 錯(cuò)誤,通常就是在這個(gè)模式下拋出返回的。例如,程序試圖訪問一個(gè)未分配給它的內(nèi)存區(qū)域,就會(huì)觸發(fā)數(shù)據(jù)訪問終止異常,進(jìn)入該模式。
  • 未定義指令終止模式(Undefined Mode):當(dāng) CPU 在指令的譯碼階段不能識(shí)別該指令操作時(shí),會(huì)進(jìn)入此模式,用于支持硬件協(xié)處理器的軟件仿真,就像是城市中對(duì)未知情況的探索研究部門。比如,在不支持特定浮點(diǎn)運(yùn)算指令的硬件上執(zhí)行該指令時(shí),就會(huì)進(jìn)入未定義模式

在這七種模式中,除了用戶模式外,其他六種模式都屬于特權(quán)模式,擁有更高的權(quán)限,可以訪問系統(tǒng)的所有資源,并且能夠自由切換處理器模式。而特權(quán)模式中,除了系統(tǒng)模式外,其余五種模式(中斷模式、快速中斷模式、管理模式、數(shù)據(jù)訪問終止模式、未定義指令終止模式)又被統(tǒng)稱為異常模式,它們不僅可以通過特權(quán)程序切換進(jìn)入,還能由特定的異常情況觸發(fā)進(jìn)入。

中斷模式是ARM異常模式之一(IRQ模式,F(xiàn)IQ模式),是一種異步事件,如外部按鍵產(chǎn)生中斷,內(nèi)部定時(shí)器產(chǎn)生中斷,通信數(shù)據(jù)口數(shù)據(jù)收發(fā)產(chǎn)生中斷等。

當(dāng)一個(gè)異常產(chǎn)生時(shí),以FIQ為例,CPU切入FIQ模式時(shí)

  • ①將原來執(zhí)行程序的下一條指令地址保存到LR中,就是將R14保存到R14_fiq里面。
  • ②拷貝CPSR到SPSR_fiq。
  • ③改變CPSR模式位的值,改到FIQ模式。
  • ④改變PC值,將其指向相應(yīng)的異常處理向量表。

離開異常處理的時(shí)候:

  • ①將LR(R14_fiq)賦給PC。
  • ②將SPSR(SPSR_fiq)拷貝到CPSR。
  • ③清除中斷禁止標(biāo)志(如果開始時(shí)置位了)。

當(dāng)一個(gè)外部IRQ中斷產(chǎn)生時(shí):

  • ①處理器切換到IRQ模式
  • ②PC跳到0x18處運(yùn)行,因?yàn)檫@是IRQ的中斷入口。
  • ③通過0x18:LDR PC, IRQ_ADDR,跳轉(zhuǎn)到相應(yīng)的中斷服務(wù)程序。這個(gè)中斷服務(wù)程序就要確定中斷源,每個(gè)中斷源會(huì)有自己獨(dú)立的中斷服務(wù)程序。
  • ④得到中斷源,然后執(zhí)行相應(yīng)中斷服務(wù)程序
  • ⑤清除中斷標(biāo)志,返回

這就是一個(gè)外部中斷完整的執(zhí)行流程了,下面以具體寄存器來更具體的了解ARM的中斷機(jī)制。

假設(shè)ARM核有兩個(gè)中斷引腳,一根是irq pin,一根是fiq pin,正常情況下,ARM核只是機(jī)械地隨著PC指示去執(zhí)行,當(dāng)CPSR中的I位和F位都為1時(shí),IRQ和FIQ都處于禁止?fàn)顟B(tài),這時(shí)候無論發(fā)什么信號(hào),ARM都不會(huì)理睬。

當(dāng)I位或F位為0時(shí),irq pin有中斷信號(hào)過來時(shí),ARM當(dāng)前工作就會(huì)被打斷,切換到IRQ模式,并且跳轉(zhuǎn)到異常向量表的中斷入口0x18,SRCPND中相應(yīng)位置1,經(jīng)過檢查中斷優(yōu)先級(jí)寄存器以及屏蔽寄存器,確定中斷源,INTPND相應(yīng)位置1(經(jīng)過仲裁,只有一位置1),這過程由ARM自動(dòng)完成。0x18存放的是總的中斷處理函數(shù),在這個(gè)函數(shù)里,可以建立一個(gè)二級(jí)中斷向量表,先清除SRCPND相應(yīng)位,然后根據(jù)中斷源執(zhí)行相應(yīng)中斷服務(wù)程序,清除INTPND,返回。

及時(shí)清除中斷 Pending 寄存器的標(biāo)志位是為了避免兩個(gè)問題:①發(fā)生中斷返回后,立即又被中斷,不斷的重復(fù)響應(yīng)②丟失中斷處理過程中發(fā)生的中斷,返回后不響應(yīng)。

在某個(gè)IRQ中斷程序執(zhí)行過程中,有另外一個(gè)外部IRQ中斷產(chǎn)生,會(huì)將SRCPND相應(yīng)位置1,等該中斷服務(wù)執(zhí)行完,經(jīng)過仲裁決定下一個(gè)要響應(yīng)的中斷。但是假如當(dāng)產(chǎn)生的是FIQ,則保存當(dāng)前IRQ的現(xiàn)場(chǎng),嵌套響應(yīng)FIQ,F(xiàn)IQ服務(wù)程序執(zhí)行完,再繼續(xù)執(zhí)行IRQ服務(wù)。那么當(dāng)一個(gè)FIQ正在服務(wù),產(chǎn)生另外一個(gè)FIQ,會(huì)怎樣呢,答案是不會(huì)被打斷,跟IRQ一樣等當(dāng)前中斷服務(wù)完成,再仲裁剩余需要相應(yīng)的中斷。

所以得出這樣的結(jié)論:

①關(guān)于中斷嵌套:IRQ模式只能被FIQ模式打斷,F(xiàn)IQ模式下誰也打不斷。

②關(guān)于優(yōu)先級(jí):ARM核對(duì)中斷優(yōu)先級(jí),有明確的可編程管理。

下面再來看看Linux對(duì)ARM是怎么處理的,記住一個(gè)前提:Linux對(duì)ARM的硬件特性可以取舍,但不可更改。

建立異常向量表:系統(tǒng)從arch/arm/kernel/head.S的ENTRY(stext)開始執(zhí)行,__lookup_processor_type檢查處理器ID,__lookup_machine_type檢查機(jī)器ID,__create_page_tables創(chuàng)建頁表,啟動(dòng)MMU,然后由arch/arm/kernel/head_common.S 跳到start_kernel()->trap_init()

void __init trap_init(void)
{
    unsigned long vectors = CONFIG_VECTORS_BASE;
    …
    memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
    memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
    memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
    …
}
#define CONFIG_VECTORS_BASE 0xffff0000

CONFIG_VECTORS_BASE在autoconf.h定義,在ARM V4及V4T以后的大部分處理器中,中斷向量表的位置可以有兩個(gè)位置:一個(gè)是0,另一個(gè)是0xffff0000。可以通過CP15協(xié)處理器c1寄存器中V位(bit[13])控制。V和中斷向量表的對(duì)應(yīng)關(guān)系如下:

V=0 ~ 0x00000000~0x0000001C
V=1 ~ 0xffff0000~0xffff001C

__vectors_end 至 __vectors_start之間為異常向量表,位于arch/arm/kernel/entry-armv.S

.globl __vectors_start
__vectors_start:
swi SYS_ERROR0
b vector_und + stubs_offset//復(fù)位異常
ldr pc, .LCvswi + stubs_offset //未定義異常
b vector_pabt + stubs_offset//軟件中斷異常
b vector_dabt + stubs_offset//數(shù)據(jù)異常
b vector_addrexcptn + stubs_offset//保留
b vector_irq + stubs_offset //普通中斷異常
b vector_fiq + stubs_offset//快速中斷異常
.globl __vectors_end
__vectors_end:

stubs_offset值如下:

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

stubs_offset是如何確定的呢?

當(dāng)匯編器看到B指令后會(huì)把要跳轉(zhuǎn)的標(biāo)簽轉(zhuǎn)化為相對(duì)于當(dāng)前PC的偏移量(±32M)寫入指令碼。從上面的代碼可以看到中斷向量表和stubs都發(fā)生了代碼搬移,所以如果中斷向量表中仍然寫成b vector_irq,那么實(shí)際執(zhí)行的時(shí)候就無法跳轉(zhuǎn)到搬移后的vector_irq處,因?yàn)橹噶畲a里寫的是原來的偏移量,所以需要把指令碼中的偏移量寫成搬移后的。我們把搬移前的中斷向量表中的irq入口地址記irq_PC,它在中斷向量表的偏移量就是irq_PC-vectors_start, vector_irq在stubs中的偏移量是vector_irq-stubs_start,這兩個(gè)偏移量在搬移前后是不變的。

搬移后 vectors_start在0xffff0000處,而stubs_start在0xffff0200處,所以搬移后的vector_irq相對(duì)于中斷向量中的中斷入口地址的偏移量就是,200+vector_irq在stubs中的偏移量再減去中斷入口在向量表中的偏移量,即200+ vector_irq-stubs_start-irq_PC+vectors_start = (vector_irq-irq_PC) + vectors_start+200-stubs_start,對(duì)于括號(hào)內(nèi)的值實(shí)際上就是中斷向量表中寫的vector_irq,減去irq_PC是由匯編器完成的,而后面的 vectors_start+200-stubs_start就應(yīng)該是stubs_offset,實(shí)際上在entry-armv.S中也是這樣定義的。

2.2ARM 中斷引腳與中斷使能控制

在 ARM 架構(gòu)中,中斷的硬件實(shí)現(xiàn)依賴于特定的引腳和控制機(jī)制。我們可以假設(shè) ARM 核心有兩根中斷引腳(實(shí)際中是集成在芯片內(nèi)部,從外部不可見),一根叫 irq pin,用于普通中斷請(qǐng)求;另一根叫 fiq pin,用于快速中斷請(qǐng)求 。這兩根引腳就像是連接外部設(shè)備與 CPU 的 “緊急聯(lián)絡(luò)線”,一旦外部設(shè)備有緊急事務(wù)需要 CPU 處理,就會(huì)通過這兩根引腳向 CPU 發(fā)送中斷信號(hào)。

而 CPU 是否響應(yīng)這些中斷信號(hào),由當(dāng)前程序狀態(tài)寄存器(CPSR)中的 I 位和 F 位來控制。當(dāng) CPSR 中的 I 位為 1 時(shí),IRQ 中斷被禁止,此時(shí)即使 irq pin 上有中斷信號(hào),CPU 也不會(huì)理會(huì),就如同消防員將火警鈴聲設(shè)置為靜音,對(duì)火災(zāi)警報(bào)充耳不聞;當(dāng) F 位為 1 時(shí),F(xiàn)IQ 中斷被禁止,fiq pin 上的中斷信號(hào)也無法引起 CPU 的注意 。只有當(dāng) I 位和 F 位都為 0 時(shí),irq pin 和 fiq pin 上的中斷信號(hào)才能成功打斷 CPU 當(dāng)前正在執(zhí)行的任務(wù),使 CPU 切換到相應(yīng)的中斷模式進(jìn)行處理。例如,在系統(tǒng)進(jìn)行一些關(guān)鍵的、不能被中斷干擾的操作時(shí),就可以通過設(shè)置 CPSR 中的 I 位和 F 位來禁止中斷,確保操作的完整性和正確性。

當(dāng)有外部中斷產(chǎn)生時(shí),跳轉(zhuǎn)到異常向量表的“b vector_irq + stubs_offset //普通中斷異常”,進(jìn)入異常處理函數(shù),跳轉(zhuǎn)的入口位置 arch\arm\kernel\entry-armv.S 代碼簡(jiǎn)略如下:

.globl __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
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)
vector_stub dabt, ABT_MODE, 8
vector_stub pabt, ABT_MODE, 4
vector_stub und, UND_MODE
/*
* Undefined FIQs
*/
vector_fiq:
disable_fiq
subs pc, lr, #4
vector_addrexcptn:
b vector_addrexcptn

vector_stub是個(gè)函數(shù)調(diào)用宏,根據(jù)中斷前的工作模式?jīng)Q定進(jìn)入__irq_usr,__irq_svc。這里入__irq_svc,同時(shí)看到這里FIQ產(chǎn)生時(shí),系統(tǒng)未做任何處理,直接返回,即Linux沒有提供對(duì)FIQ的支持,繼續(xù)跟進(jìn)代碼

__irq_svc:
svc_entry
…
irq_handler

svc_entry是一個(gè)宏,主要實(shí)現(xiàn)了將SVC模式下的寄存器、中斷返回地址保存到堆棧中。然后進(jìn)入最核心的中斷響應(yīng)函數(shù)irq_handler,irq_handler實(shí)現(xiàn)過程arch\arm\kernel\entry-armv.S

.macro irq_handler
get_irqnr_preamble r5, lr
1: get_irqnr_and_base r0, r6, r5, lr @判斷中斷號(hào),通過R0返回,3.5節(jié)有實(shí)現(xiàn)過程
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ @進(jìn)入中斷處理。
……
.endm

get_irqnr_and_base中斷號(hào)判斷過程,include/asm/arch-s3c2410/entry-macro.s

.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov \base, #S3C24XX_VA_IRQ
@@ try the interrupt offset register, since it is there
ldr \irqstat, [ \base, #INTPND ]
teq \irqstat, #0
beq 1002f
ldr \irqnr, [ \base, #INTOFFSET ] @通過判斷INTOFFSET寄存器得到中斷位置
…
@@ we have the value
1001:
adds \irqnr, \irqnr, #IRQ_EINT0 @加上中斷號(hào)的基準(zhǔn)數(shù)值,得到最終的中斷號(hào),注意:此時(shí)沒有考慮子中斷的具體情況。IRQ_EINT0在include/asm/arch-s3c2410/irqs.h中定義.從這里可以看出,中斷號(hào)的具體值是有平臺(tái)相關(guān)的代碼決定的,和硬件中斷掛起寄存器中的中斷號(hào)是不等的。
1002:
@@ exit here, Z flag unset if IRQ
.endm

asm_do_IRQ實(shí)現(xiàn)過程,arch/arm/kernel/irq.c

asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);
    struct irq_desc *desc = irq_desc + irq;//根據(jù)中斷號(hào),找到響應(yīng)的irq_desc

    /*
     * Some hardware gives randomly wrong interrupts. Rather
     * than crashing, do something sensible.
     */
    if (irq >= NR_IRQS)
        desc = &bad_irq_desc;

    irq_enter();

    desc_handle_irq(irq, desc);//根據(jù)irq和desc進(jìn)入中斷處理

    /* AT91 specific workaround */
    irq_finish(irq);

    irq_exit();
    set_irq_regs(old_regs);
}
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
    desc->handle_irq(irq, desc);//中斷處理 
}

上述asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)使用了asmlinkage標(biāo)識(shí)。那么這個(gè)標(biāo)識(shí)的含義如何理解呢?

該符號(hào)定義在kernel/include/linux/linkage.h中,如下所示:

include//各個(gè)具體處理器在此文件中定義asmlinkage
#ifdef __cplusplus
        #define CPP_ASMLINKAGE extern "C"
        #else
        #define CPP_ASMLINKAGE
        #endif
#ifndef asmlinkage//如果以前沒有定義asmlinkage
        #define asmlinkage CPP_ASMLINKAGE
        #endif

對(duì)于ARM處理器的,沒有定義asmlinkage,所以沒有意義(不要以為參數(shù)是從堆棧傳遞的,對(duì)于ARM平臺(tái)來說還是符合ATPCS過程調(diào)用標(biāo)準(zhǔn),通過寄存器傳遞的)。

但對(duì)于X86處理器的中是這樣定義的:

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))

表示函數(shù)的參數(shù)傳遞是通過堆棧完成的。

中斷處理過程代碼就跟到這了,那么最后一個(gè)問題desc->handle_irq(irq, desc);是怎么跟我們注冊(cè)的中斷函數(shù)相關(guān)聯(lián)的呢?再?gòu)闹袛嗄P妥?cè)入手:

中斷相關(guān)的數(shù)據(jù)結(jié)構(gòu):在include/asm/arch/irq.h中定義。

irq_desc[]是一個(gè)指向irq_desc_t結(jié)構(gòu)的數(shù)組, irq_desc_t結(jié)構(gòu)是各個(gè)設(shè)備中斷服務(wù)例程的描述符。Irq_desc_t結(jié)構(gòu)體中的成員action指向該中斷號(hào)對(duì)應(yīng)的irqaction結(jié)構(gòu)體鏈表。Irqaction結(jié)構(gòu)體定義在include/linux/interrupt.h中,如下:

truct irqaction {
irq_handler_t handler; //中斷處理函數(shù),注冊(cè)時(shí)提供
unsigned long flags; //中斷標(biāo)志,注冊(cè)時(shí)提供
cpumask_t mask; //中斷掩碼
const char *name; //中斷名稱
void *dev_id; //設(shè)備id,本文后面部分介紹中斷共享時(shí)會(huì)詳細(xì)說明這個(gè)參數(shù)的作用
struct irqaction *next; //如果有中斷共享,則繼續(xù)執(zhí)行,
int irq; //中斷號(hào),注冊(cè)時(shí)提供
struct proc_dir_entry *dir; //指向IRQn相關(guān)的/proc/irq/n目錄的描述符
};

在注冊(cè)中斷號(hào)為irq的中斷服務(wù)程序時(shí),系統(tǒng)會(huì)根據(jù)注冊(cè)參數(shù)封裝相應(yīng)的irqaction結(jié)構(gòu)體。并把中斷號(hào)為irq的irqaction結(jié)構(gòu)體寫入irq_desc [irq]->action。這樣就把設(shè)備的中斷請(qǐng)求號(hào)與該設(shè)備的中斷服務(wù)例程irqaction聯(lián)系在一起了。當(dāng)CPU接收到中斷請(qǐng)求后,就可以根據(jù)中斷號(hào)通過irq_desc []找到該設(shè)備的中斷服務(wù)程序。

2.3中斷向量表與中斷執(zhí)行流程

中斷向量表在 ARM 中斷系統(tǒng)中扮演著至關(guān)重要的角色,它是中斷處理的 “導(dǎo)航地圖”。在 32 位 ARM 系統(tǒng)中,中斷向量表一般位于內(nèi)存的特定地址,有兩個(gè)可選位置:一個(gè)是低地址 0x00000000 - 0x0000001c(Low vector) ;另一個(gè)是高地址 0Xffff0000 - 0xffff001c(High vector) ,具體使用哪個(gè)位置由 CPU 決定。中斷向量表中存放著各個(gè)中斷和異常對(duì)應(yīng)的處理程序的入口地址,當(dāng)有中斷或異常發(fā)生時(shí),CPU 會(huì)自動(dòng)將程序計(jì)數(shù)器(PC)指向中斷向量表中的相應(yīng)地址,從而跳轉(zhuǎn)到對(duì)應(yīng)的中斷服務(wù)例程進(jìn)行處理。

以外部 IRQ 中斷為例,當(dāng) irq pin 上有中斷信號(hào)到來時(shí),整個(gè)中斷執(zhí)行流程如下:

  1. 模式切換:ARM 核心檢測(cè)到 irq pin 上的中斷信號(hào)后,首先會(huì)檢查 CPSR 中的 I 位,如果 I 位為 0(即 IRQ 中斷未被禁止),CPU 會(huì)自動(dòng)切換到 IRQ 模式,就像消防員接到火災(zāi)警報(bào)后,迅速換上消防服,進(jìn)入戰(zhàn)斗狀態(tài)。
  2. 跳轉(zhuǎn)至中斷向量表:CPU 切換到 IRQ 模式后,PC 會(huì)跳到中斷向量表中 IRQ 對(duì)應(yīng)的入口地址 0x18 處運(yùn)行 。這個(gè)過程是硬件自動(dòng)完成的,就像是消防系統(tǒng)根據(jù)警報(bào)類型,自動(dòng)將消防員引導(dǎo)到對(duì)應(yīng)的火災(zāi)現(xiàn)場(chǎng)位置。
  3. 跳轉(zhuǎn)到中斷服務(wù)程序:在 0x18 地址處,通常存放著一條跳轉(zhuǎn)指令(如 LDR PC, IRQ_ADDR),通過這條指令,CPU 會(huì)跳轉(zhuǎn)到具體的中斷服務(wù)程序。這個(gè)中斷服務(wù)程序的任務(wù)是確定中斷源,因?yàn)榭赡苡卸鄠€(gè)外部設(shè)備共享 irq pin,每個(gè)設(shè)備產(chǎn)生的中斷都需要有獨(dú)立的處理方式。比如,鍵盤和鼠標(biāo)都可能通過 irq pin 發(fā)送中斷信號(hào),中斷服務(wù)程序需要判斷到底是鍵盤按鍵按下產(chǎn)生的中斷,還是鼠標(biāo)移動(dòng)產(chǎn)生的中斷,然后再執(zhí)行相應(yīng)的處理操作。
  4. 執(zhí)行中斷服務(wù)程序:確定中斷源后,CPU 會(huì)執(zhí)行相應(yīng)的中斷服務(wù)程序,完成對(duì)中斷事件的處理。例如,如果是鍵盤中斷,中斷服務(wù)程序可能會(huì)讀取鍵盤輸入的字符,并將其傳遞給相應(yīng)的應(yīng)用程序;如果是定時(shí)器中斷,可能會(huì)更新系統(tǒng)時(shí)間、觸發(fā)定時(shí)任務(wù)等。
  5. 清除中斷標(biāo)志與返回:中斷服務(wù)程序執(zhí)行完畢后,需要清除中斷標(biāo)志,通知系統(tǒng)中斷已經(jīng)處理完畢。然后,CPU 會(huì)恢復(fù)到中斷前的狀態(tài),將程序執(zhí)行流程返回到被中斷的地方繼續(xù)執(zhí)行,就像消防員撲滅火災(zāi)后,脫下消防服,回到原來的工作崗位,繼續(xù)之前未完成的任務(wù)。在這個(gè)過程中,需要將之前保存的寄存器值恢復(fù),將 CPSR 從 SPSR 中恢復(fù),將 LR 中的值賦給 PC 等,確保程序能夠無縫銜接繼續(xù)執(zhí)行。

三、ARM+Linux 中斷系統(tǒng)基礎(chǔ)解析

3.1ARM 架構(gòu)中斷機(jī)制

在 ARM 架構(gòu)的璀璨星空中,中斷機(jī)制宛如一條貫穿其中的璀璨銀河,連接著處理器與外部設(shè)備,為系統(tǒng)的高效運(yùn)行提供了關(guān)鍵支撐。ARM 架構(gòu)下的中斷,猶如靈動(dòng)的使者,根據(jù)其特性和應(yīng)用場(chǎng)景,主要分為兩類:IRQ(Interrupt Request,外部中斷請(qǐng)求)和 FIQ(Fast Interrupt Request,快速中斷請(qǐng)求) ,它們各具特色,在不同的場(chǎng)景中發(fā)揮著獨(dú)特的作用。

IRQ,作為通用中斷請(qǐng)求的代表,是 ARM 架構(gòu)中較為常見的中斷類型。當(dāng)外部設(shè)備如鍵盤、鼠標(biāo)、網(wǎng)絡(luò)接口等有事件需要處理器關(guān)注時(shí),就會(huì)發(fā)出 IRQ 中斷請(qǐng)求。它就像是一位勤勞的信使,在系統(tǒng)中頻繁穿梭,將外部設(shè)備的各種請(qǐng)求傳遞給處理器。在我們?nèi)粘J褂玫闹悄苁謾C(jī)中,當(dāng)用戶點(diǎn)擊屏幕時(shí),觸摸屏控制器會(huì)產(chǎn)生 IRQ 中斷,通知處理器進(jìn)行相應(yīng)的處理,如打開應(yīng)用程序、滑動(dòng)頁面等。IRQ 中斷的特點(diǎn)是通用性強(qiáng),能夠靈活地響應(yīng)各種外部設(shè)備的請(qǐng)求,就像一個(gè)萬能的接口,連接著各種各樣的外部設(shè)備。而且,它還可以處理多個(gè)中斷請(qǐng)求的并發(fā)情況,當(dāng)多個(gè)外部設(shè)備同時(shí)發(fā)出中斷請(qǐng)求時(shí),IRQ 能夠有條不紊地將這些請(qǐng)求傳遞給處理器,由處理器按照一定的優(yōu)先級(jí)順序進(jìn)行處理,從而保證系統(tǒng)的實(shí)時(shí)性和可靠性 。

而 FIQ,則是中斷世界中的 “閃電俠”,以其快速響應(yīng)的特點(diǎn)而著稱。它主要用于處理那些對(duì)時(shí)間要求極為苛刻、需要快速響應(yīng)的中斷請(qǐng)求,如高速數(shù)據(jù)傳輸、通道處理等場(chǎng)景。在高速網(wǎng)絡(luò)通信中,數(shù)據(jù)的接收和發(fā)送需要及時(shí)處理,否則可能會(huì)導(dǎo)致數(shù)據(jù)丟失或延遲。此時(shí),F(xiàn)IQ 就發(fā)揮了重要作用,它能夠在極短的時(shí)間內(nèi)響應(yīng)中斷請(qǐng)求,迅速處理數(shù)據(jù),確保網(wǎng)絡(luò)通信的順暢。FIQ 之所以能夠如此快速地響應(yīng),得益于它擁有更高的優(yōu)先級(jí)。

當(dāng) FIQ 和 IRQ 同時(shí)產(chǎn)生時(shí),處理器會(huì)毫不猶豫地優(yōu)先響應(yīng) FIQ 中斷,就像在緊急情況下,人們會(huì)優(yōu)先處理最緊急的事務(wù)一樣。此外,F(xiàn)IQ 模式還提供了更多的 banked 寄存器,這些寄存器就像是為 FIQ 量身定制的 “快速通道”,在模式切換時(shí),CPU 能夠自動(dòng)保存和恢復(fù)相關(guān)寄存器的值,大大減少了上下文切換的開銷,從而提高了中斷處理的速度 。

在實(shí)際應(yīng)用中,我們需要根據(jù)不同的場(chǎng)景需求,合理地選擇使用 IRQ 和 FIQ。對(duì)于那些對(duì)實(shí)時(shí)性要求不高的普通外部設(shè)備,如打印機(jī)、攝像頭等,使用 IRQ 中斷即可滿足需求;而對(duì)于那些對(duì)時(shí)間要求極高的高速數(shù)據(jù)傳輸設(shè)備,如高速 USB 接口、以太網(wǎng)控制器等,則需要使用 FIQ 中斷來確保系統(tǒng)的性能。

3.2Linux 對(duì) ARM 中斷的管理

Linux 內(nèi)核,就像一位智慧的指揮官,對(duì) ARM 中斷進(jìn)行著有條不紊的管理,確保系統(tǒng)的穩(wěn)定運(yùn)行。在這個(gè)過程中,中斷向量表的建立和中斷注冊(cè)是兩個(gè)關(guān)鍵的環(huán)節(jié),它們就像是 Linux 內(nèi)核管理 ARM 中斷的兩把 “利刃”,發(fā)揮著至關(guān)重要的作用。

中斷向量表,是中斷處理的 “導(dǎo)航地圖”,它記錄了每個(gè)中斷對(duì)應(yīng)的處理程序的入口地址。在 ARM 架構(gòu)中,中斷向量表的位置可以通過 CP15 協(xié)處理器的控制寄存器 C1 的 bit13 來設(shè)置,當(dāng)該位為 0 時(shí),中斷向量表起始于 0x00000000;當(dāng)該位為 1 時(shí),起始于 0xffff0000 。在 Linux 內(nèi)核啟動(dòng)的過程中,會(huì)精心地建立中斷向量表。它首先會(huì)確定中斷向量表的基地址,然后將異常向量表從內(nèi)存的特定位置復(fù)制到中斷向量表的基地址處。異常向量表中包含了各種中斷和異常的處理入口,如復(fù)位異常、未定義指令異常、中斷異常等。

在 ARMv8 架構(gòu)中,中斷向量表的建立過程涉及到多個(gè)步驟,包括初始化中斷控制器、設(shè)置中斷向量表的基地址、將異常向量表復(fù)制到中斷向量表的基地址等。通過這些步驟,Linux 內(nèi)核為中斷處理搭建了一個(gè)堅(jiān)實(shí)的基礎(chǔ),使得處理器在接收到中斷請(qǐng)求時(shí),能夠迅速找到對(duì)應(yīng)的處理程序入口,就像在地圖上找到目的地的路線一樣。

中斷注冊(cè),則是將設(shè)備的中斷處理函數(shù)與中斷號(hào)進(jìn)行綁定的過程,就像是為每個(gè)中斷請(qǐng)求找到對(duì)應(yīng)的 “處理專家”。在 Linux 內(nèi)核中,設(shè)備驅(qū)動(dòng)程序開發(fā)者需要使用 request_irq 函數(shù)來注冊(cè)中斷。這個(gè)函數(shù)的原型如下:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id);

其中,irq 是要申請(qǐng)的硬件中斷號(hào),它就像是設(shè)備的 “專屬號(hào)碼”,用于唯一標(biāo)識(shí)一個(gè)中斷請(qǐng)求;handler 是向系統(tǒng)注冊(cè)的中斷處理函數(shù),當(dāng)該中斷發(fā)生時(shí),系統(tǒng)會(huì)調(diào)用這個(gè)函數(shù)來處理中斷,它是處理中斷的核心代碼;irqflags 是中斷處理的屬性,如設(shè)置了 IRQF_DISABLED,則表示中斷處理程序是快速處理程序,在被調(diào)用時(shí)會(huì)屏蔽所有中斷,以確保快速處理中斷;如設(shè)置了 IRQF_SHARED,則表示多個(gè)設(shè)備可以共享這個(gè)中斷,這在一些資源有限的系統(tǒng)中非常有用;devname 是設(shè)置的中斷名稱,方便在系統(tǒng)中識(shí)別和管理中斷,就像給每個(gè)設(shè)備取一個(gè)名字一樣;dev_id 在中斷共享時(shí)會(huì)用到,一般設(shè)置為這個(gè)設(shè)備的設(shè)備結(jié)構(gòu)體或者 NULL,它用于在共享中斷時(shí)區(qū)分不同的設(shè)備 。

當(dāng)設(shè)備驅(qū)動(dòng)程序調(diào)用 request_irq 函數(shù)成功注冊(cè)中斷后,Linux 內(nèi)核會(huì)將中斷處理函數(shù)與中斷號(hào)關(guān)聯(lián)起來,并記錄在相應(yīng)的中斷管理數(shù)據(jù)結(jié)構(gòu)中。當(dāng)中斷發(fā)生時(shí),內(nèi)核會(huì)根據(jù)中斷號(hào)找到對(duì)應(yīng)的中斷處理函數(shù),并調(diào)用它來處理中斷。在一個(gè)包含多個(gè) GPIO 設(shè)備的嵌入式系統(tǒng)中,每個(gè) GPIO 設(shè)備都可能產(chǎn)生中斷。設(shè)備驅(qū)動(dòng)程序會(huì)為每個(gè) GPIO 設(shè)備的中斷號(hào)注冊(cè)相應(yīng)的中斷處理函數(shù),當(dāng)某個(gè) GPIO 設(shè)備產(chǎn)生中斷時(shí),內(nèi)核能夠準(zhǔn)確地找到對(duì)應(yīng)的中斷處理函數(shù),對(duì)中斷進(jìn)行處理,從而實(shí)現(xiàn)設(shè)備與系統(tǒng)之間的高效通信 。通過中斷注冊(cè),Linux 內(nèi)核實(shí)現(xiàn)了對(duì)中斷的精細(xì)管理,使得系統(tǒng)能夠靈活地響應(yīng)各種設(shè)備的中斷請(qǐng)求。

四、Linux在ARM上的中斷構(gòu)建

4.1異常向量表的建立與設(shè)置

在 Linux 系統(tǒng)基于 ARM 架構(gòu)啟動(dòng)的過程中,異常向量表的建立是一個(gè)關(guān)鍵步驟,就像是搭建一座城市的應(yīng)急指揮中心,為后續(xù)的中斷處理奠定基礎(chǔ) 。

ARM 架構(gòu)支持將異常向量表放置在兩個(gè)不同的內(nèi)存位置,具體由 CP15 協(xié)處理器 C1 寄存器的 bit [13](即 V 位)來控制 。當(dāng) V = 0 時(shí),異常向量表位于低地址 0x00000000 - 0x0000001c;當(dāng) V = 1 時(shí),異常向量表位于高地址 0Xffff0000 - 0xffff001c 。在大多數(shù) ARM V4 及 V4T 以后的處理器中,通常會(huì)選擇使用高地址的異常向量表。

在 Linux 內(nèi)核啟動(dòng)時(shí),start_kernel () 函數(shù)是整個(gè)內(nèi)核初始化的起點(diǎn),其中 trap_init ()(在一些內(nèi)核版本中可能是 early_trap_init ())函數(shù)負(fù)責(zé)異常向量表的初始化工作 。以 early_trap_init () 函數(shù)為例,其內(nèi)部實(shí)現(xiàn)過程如下:

void __init early_trap_init(void)
{
    unsigned long vectors = CONFIG_VECTORS_BASE;
    extern char __stubs_start[], __stubs_end[];
    extern char __vectors_start[], __vectors_end[];
    extern char __kuser_helper_start[], __kuser_helper_end[];
    int kuser_sz = __kuser_helper_end - __kuser_helper_start;

    /* 將異常向量表、stubs和kuser helpers拷貝到向量頁 */
    memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
    memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
    memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

    /* 拷貝信號(hào)返回處理函數(shù)到向量頁 */
    memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, sizeof(sigreturn_codes));

    /* 刷新指令緩存,使這些更改對(duì)指令流可見 */
    flush_icache_range(vectors, vectors + PAGE_SIZE);

    /* 修改異常向量表占據(jù)頁面的訪問權(quán)限 */
    modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}

首先,獲取 CONFIG_VECTORS_BASE 的值,該值通常在各個(gè)平臺(tái)的配置文件中設(shè)定,如在 arch/arm/configs/s3c2410_defconfig 中,CONFIG_VECTORS_BASE = 0xffff0000 ,它指定了異常向量表的目標(biāo)地址。然后,通過 memcpy 函數(shù)將定義在 arch/arm/kernel/entry-armv.S 中的異常向量表(__vectors_end 至__vectors_start 之間的內(nèi)容)拷貝到目標(biāo)地址 vectors 處 。

同時(shí),將異常處理程序的 stub(__stubs_end 至__stubs_start 之間的內(nèi)容)拷貝到 vectors + 0x200 的位置,將 kuser helpers 拷貝到 vectors + 0x1000 - kuser_sz 的位置 。接著,把信號(hào)返回處理函數(shù)拷貝到特定位置。之后,調(diào)用 flush_icache_range 函數(shù)刷新指令緩存,確保 CPU 能夠獲取到最新的代碼。最后,使用 modify_domain 函數(shù)修改異常向量表占據(jù)頁面的訪問權(quán)限,使得只有核心態(tài)可以訪問該頁,保障系統(tǒng)的安全性。

在 arch/arm/kernel/entry-armv.S 文件中,定義了異常向量表的具體內(nèi)容:

.globl __vectors_start
__vectors_start:
    swi SYS_ERROR0
    b vector_und + stubs_offset   //復(fù)位異常
    ldr pc, .LCvswi + stubs_offset   //未定義指令異常
    b vector_pabt + stubs_offset   //軟件中斷異常
    b vector_dabt + stubs_offset  //數(shù)據(jù)中斷異常
    b vector_addrexcptn + stubs_offset
    b vector_irq + stubs_offset   //普通中斷異常
    b vector_fiq + stubs_offset  //快速中斷異常
.globl __vectors_end
__vectors_end:

這里,每個(gè)異常類型都對(duì)應(yīng)著一個(gè)特定的跳轉(zhuǎn)指令,例如普通中斷(IRQ)對(duì)應(yīng)的是 b vector_irq + stubs_offset 。其中,stubs_offset 的值通過.equ stubs_offset, __vectors_start + 0x200 - __stubs_start 定義,它的作用是確保在異常向量表和 stubs 發(fā)生代碼搬移后,跳轉(zhuǎn)指令能夠正確地跳轉(zhuǎn)到搬移后的異常處理程序位置 。當(dāng) ARM 處理器發(fā)生異常時(shí),會(huì)根據(jù)異常類型跳轉(zhuǎn)到異常向量表中對(duì)應(yīng)的位置,進(jìn)而跳轉(zhuǎn)到相應(yīng)的異常處理程序處執(zhí)行。

4.2中斷處理函數(shù)的流程解析

當(dāng)硬件中斷觸發(fā)后,整個(gè)中斷處理流程就像是一場(chǎng)有條不紊的接力賽,涉及多個(gè)關(guān)鍵函數(shù)和操作,從硬件層面逐步過渡到軟件層面進(jìn)行處理。

假設(shè)一個(gè)外部設(shè)備(如按鍵)產(chǎn)生了中斷信號(hào),該信號(hào)首先會(huì)被 ARM 芯片的中斷控制器接收 。以常見的 ARM 芯片中斷控制器為例,它會(huì)將中斷信號(hào)進(jìn)行初步處理,檢查中斷屏蔽寄存器和中斷優(yōu)先級(jí)寄存器等,確定是否要將該中斷信號(hào)傳遞給 CPU 。如果中斷未被屏蔽且具有足夠的優(yōu)先級(jí),中斷控制器會(huì)通過 irq pin 向 CPU 發(fā)送中斷請(qǐng)求信號(hào)。

CPU 在執(zhí)行當(dāng)前指令的過程中,會(huì)不斷檢查是否有中斷信號(hào)到來 。當(dāng)檢測(cè)到 irq pin 上的中斷信號(hào)后,且當(dāng)前程序狀態(tài)寄存器(CPSR)中的 I 位為 0(表示 IRQ 中斷未被禁止)時(shí),CPU 會(huì)立即做出響應(yīng) 。首先,CPU 會(huì)自動(dòng)切換到 IRQ 模式,這是硬件自動(dòng)完成的操作,就像是消防員迅速切換到戰(zhàn)斗模式。然后,程序計(jì)數(shù)器(PC)會(huì)跳轉(zhuǎn)到異常向量表中 IRQ 對(duì)應(yīng)的入口地址 0x18 處運(yùn)行 。在 0x18 地址處,存放著一條跳轉(zhuǎn)指令(例如 LDR PC, IRQ_ADDR),通過這條指令,CPU 會(huì)跳轉(zhuǎn)到具體的中斷處理程序。

在 Linux 內(nèi)核中,中斷處理程序的入口是 vector_irq,它定義在 arch/arm/kernel/entry-armv.S 文件中 。vector_irq 首先會(huì)進(jìn)行一些現(xiàn)場(chǎng)保護(hù)操作,保存當(dāng)前寄存器的值,以便在中斷處理完成后能夠恢復(fù)到中斷前的狀態(tài) 。然后,通過一系列的判斷和跳轉(zhuǎn),最終會(huì)調(diào)用到 irq_handler 這個(gè)宏 。

irq_handler 宏實(shí)際上是調(diào)用 handle_arch_irq 函數(shù),而 handle_arch_irq 函數(shù)是在中斷控制器初始化時(shí)注冊(cè)的處理函數(shù) 。在不同的 ARM 平臺(tái)中,handle_arch_irq 函數(shù)可能會(huì)有所不同,例如在使用 GIC(Generic Interrupt Controller)中斷控制器的平臺(tái)中,handle_arch_irq 函數(shù)通常會(huì)指向 gic_handle_irq 函數(shù) 。

gic_handle_irq 函數(shù)是 GIC 中斷控制器的核心處理函數(shù),它的主要工作流程如下:

  1. 讀取中斷確認(rèn)寄存器:首先,讀取 GIC 的中斷確認(rèn)寄存器(GIC_CPU_INTACK),這個(gè)操作實(shí)際上是向 GIC 確認(rèn) CPU 已經(jīng)接收到中斷信號(hào) 。同時(shí),該寄存器會(huì)返回一個(gè)唯一的中斷號(hào),用于標(biāo)識(shí)產(chǎn)生中斷的設(shè)備。
  2. 處理中斷:根據(jù)返回的中斷號(hào),查找對(duì)應(yīng)的中斷處理函數(shù),并調(diào)用該函數(shù)進(jìn)行中斷處理 。在這個(gè)過程中,可能會(huì)涉及到對(duì)中斷源的進(jìn)一步判斷和處理,例如讀取設(shè)備的狀態(tài)寄存器,獲取中斷的具體原因等。
  3. 通知中斷結(jié)束:當(dāng)中斷處理完成后,需要向 GIC 發(fā)送中斷結(jié)束信號(hào) 。這通過寫入 GIC 的中斷結(jié)束寄存器(GIC_CPU_EOI)來實(shí)現(xiàn),告知 GIC 本次中斷已經(jīng)處理完畢,GIC 可以再次接受這個(gè)中斷號(hào)的中斷請(qǐng)求。

在驅(qū)動(dòng)層面,當(dāng)設(shè)備驅(qū)動(dòng)注冊(cè)時(shí),會(huì)使用 request_irq 函數(shù)來注冊(cè)中斷處理函數(shù) 。例如:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);

其中,irq 是中斷號(hào),handler 是具體的中斷處理函數(shù),flags 用于指定中斷的屬性(如中斷觸發(fā)方式、是否共享中斷等),name 是中斷的名稱,dev 是傳遞給中斷處理函數(shù)的上下文數(shù)據(jù) 。當(dāng)硬件中斷發(fā)生并經(jīng)過上述的一系列處理后,最終會(huì)調(diào)用到驅(qū)動(dòng)中注冊(cè)的中斷處理函數(shù) handler 。在中斷處理函數(shù)中,會(huì)根據(jù)設(shè)備的具體需求進(jìn)行相應(yīng)的處理,例如讀取設(shè)備的數(shù)據(jù)、更新設(shè)備的狀態(tài)等 。處理完成后,中斷處理函數(shù)會(huì)返回一個(gè) irqreturn_t 類型的值,用于告知系統(tǒng)中斷處理的結(jié)果。

當(dāng)中斷處理函數(shù)執(zhí)行完畢后,會(huì)進(jìn)行現(xiàn)場(chǎng)恢復(fù)操作,將之前保存的寄存器值恢復(fù),將 CPSR 從 SPSR 中恢復(fù),將 LR 中的值賦給 PC 等,使 CPU 回到中斷前的狀態(tài),繼續(xù)執(zhí)行被中斷的任務(wù) 。

五、ARM的GIC中斷控制器剖析

5.1GIC 的基本概念與版本介紹

在 ARM 架構(gòu)的中斷體系中,GIC(Generic Interrupt Controller)即通用中斷控制器,扮演著至關(guān)重要的角色,堪稱中斷管理的 “總指揮” 。它就像是城市中的交通指揮中心,負(fù)責(zé)收集、管理和分配來自各個(gè)外部設(shè)備以及內(nèi)部事件的中斷信號(hào),確保 CPU 能夠有條不紊地處理這些中斷請(qǐng)求。

目前,GIC 共有四個(gè)版本,分別為 V1 至 V4 。其中,V1 是最早期的版本,如今已逐漸被淘汰,不再?gòu)V泛應(yīng)用;V2 版本應(yīng)用較為廣泛,它最多支持 8 個(gè) ARM core,常用于 ARMv7 - A 架構(gòu)的芯片,如 Cortex - A7、Cortex - A9、Cortex - A15 等 ,像一些早期的智能手機(jī)、平板電腦等設(shè)備中,就常常能看到基于 GIC V2 的中斷控制;V3 和 V4 版本則主要面向 ARM64 服務(wù)器系統(tǒng)結(jié)構(gòu),支持更多的 ARM core,能夠滿足大規(guī)模數(shù)據(jù)處理和多任務(wù)并發(fā)的需求 ,在數(shù)據(jù)中心、云計(jì)算等領(lǐng)域發(fā)揮著重要作用。

例如,GIC - 500 最多支持 128 個(gè) cpu core,它要求 ARM core 必須是 ARMV8 指令集的(如 Cortex - A57),符合 GIC architecture specification version 3 。在實(shí)際應(yīng)用中,不同的芯片廠商會(huì)根據(jù)自身產(chǎn)品的需求,選擇合適版本的 GIC。例如,一些中低端的嵌入式設(shè)備可能會(huì)采用 GIC V2 版本,以降低成本并滿足基本的中斷處理需求;而高端的服務(wù)器芯片則會(huì)選用 GIC V3 或 V4 版本,以提供強(qiáng)大的中斷管理能力和高性能的計(jì)算支持。

5.2GIC 的中斷輸入信號(hào)類型

GIC 接收的中斷輸入信號(hào)主要分為三種類型,每種類型都有其獨(dú)特的特點(diǎn)和應(yīng)用場(chǎng)景,就像是不同類型的緊急事件,需要不同的應(yīng)對(duì)方式。

  1. PPI(私有外設(shè)中斷,Private Peripheral Interrupt):這是每個(gè) CPU 私有的中斷,就如同每個(gè)人專屬的緊急聯(lián)絡(luò)方式。PPI 最多支持 16 個(gè)中斷,硬件中斷號(hào)從 ID16~ID31 。它通常會(huì)被發(fā)送到指定的 CPU 上,應(yīng)用場(chǎng)景之一是 CPU 本地時(shí)鐘,比如每個(gè)核的 tick 中斷,用于進(jìn)程調(diào)度使用 。以一個(gè)多核處理器為例,每個(gè)核心都有自己獨(dú)立的 PPI 中斷,用于處理與該核心緊密相關(guān)的特定外設(shè)事件,確保各個(gè)核心能夠高效地處理自身的事務(wù),互不干擾。
  2. SPI(公用外設(shè)中斷,Shared Peripheral Interrupt):SPI 是所有 Core 共享的中斷,來自于外設(shè),類似于公共的緊急求助通道。它最多可以支持 988 個(gè)外設(shè)中斷,硬件中斷號(hào)從 ID32~ID1019 。像我們常見的按鍵中斷、串口中斷等等,這些中斷所有的 Core 都可以處理,不限定特定 Core 。在一個(gè)智能家居系統(tǒng)中,多個(gè)傳感器(如溫度傳感器、濕度傳感器、門窗傳感器等)產(chǎn)生的中斷信號(hào),都可以通過 SPI 中斷發(fā)送給 CPU,由 CPU 統(tǒng)一進(jìn)行處理,實(shí)現(xiàn)對(duì)家居環(huán)境的智能監(jiān)控和控制。

5.3GIC 的工作機(jī)制與寄存器功能

GIC 的工作機(jī)制主要依賴于兩個(gè)關(guān)鍵部分:仲裁單元(Distributor)和 CPU 接口模塊(CPU Interface) ,它們相互協(xié)作,共同完成中斷的管理和處理,就像是一個(gè)高效的團(tuán)隊(duì),各自發(fā)揮著重要的職責(zé)。

仲裁單元(Distributor)

仲裁單元就像是交通指揮中心的調(diào)度員,負(fù)責(zé)收集所有的中斷源,控制每個(gè)中斷的優(yōu)先級(jí),并將中斷事件分發(fā)到相應(yīng)的 CPU 接口端 。它的主要工作包括:

  • 全局中斷使能控制:通過 GIC_DIST_CTRL 寄存器,可以對(duì)全局中斷進(jìn)行控制 。一旦禁用了全局中斷,那么任何中斷源產(chǎn)生的中斷事件都不會(huì)被傳遞到 CPU 接口,就像是交通指揮中心關(guān)閉了所有的緊急通道,不再接收任何緊急信號(hào)。
  • 單個(gè)中斷使能或關(guān)閉控制:利用 GIC_DIST_ENABLE_CLEAR 寄存器,可以針對(duì)各個(gè)中斷源進(jìn)行控制 。禁用某一個(gè)中斷源會(huì)導(dǎo)致該中斷事件不會(huì)被分發(fā)到 CPU 接口,但不影響其他中斷源產(chǎn)生的中斷事件的分發(fā),就如同關(guān)閉了某個(gè)特定區(qū)域的緊急通道,但其他區(qū)域的緊急通道仍然暢通。
  • 中斷優(yōu)先級(jí)設(shè)置:仲裁單元會(huì)為每個(gè)中斷分配優(yōu)先級(jí),它總是將優(yōu)先級(jí)最高的中斷事件發(fā)送到 CPU 接口端 。例如,在一個(gè)同時(shí)有按鍵中斷和串口接收中斷的系統(tǒng)中,如果按鍵中斷被設(shè)置為更高的優(yōu)先級(jí),那么當(dāng)兩個(gè)中斷同時(shí)發(fā)生時(shí),仲裁單元會(huì)優(yōu)先將按鍵中斷發(fā)送給 CPU 接口,確保關(guān)鍵事件能夠得到及時(shí)處理。
  • 中斷目標(biāo)處理器列表設(shè)置:可以設(shè)置每個(gè)中斷應(yīng)該發(fā)送到哪些 CPU 核心上,實(shí)現(xiàn)中斷的合理分配 。在一個(gè)多核處理器系統(tǒng)中,對(duì)于一些計(jì)算密集型的中斷任務(wù),可以將其分配到性能較強(qiáng)的核心上進(jìn)行處理,以提高系統(tǒng)的整體性能。
  • 中斷觸發(fā)模式設(shè)置:可以設(shè)定每個(gè)外部中斷的觸發(fā)模式,是電平觸發(fā)還是邊沿觸發(fā) 。例如,對(duì)于一些對(duì)時(shí)間精度要求較高的中斷事件,可以設(shè)置為邊沿觸發(fā)模式,確保能夠及時(shí)捕捉到中斷信號(hào)。
  • 中斷分組設(shè)置:設(shè)置每個(gè)中斷屬于組 0 還是組 1 。在安全系統(tǒng)中,Group0 通常用于安全相關(guān)的中斷,連接 FIQ;Group1 作為非安全系統(tǒng)使用,連接 IRQ 。通過這種分組方式,可以增強(qiáng)系統(tǒng)的安全性和穩(wěn)定性。

CPU 接口模塊(CPU Interface)

CPU 接口模塊則像是連接交通指揮中心和消防員(CPU)的通信員,是分發(fā)器和 CPU Core 之間的橋梁 。它的主要功能如下:

  • 中斷請(qǐng)求信號(hào)使能或關(guān)閉:可以控制是否將中斷請(qǐng)求信號(hào)發(fā)送到 CPU Core 。如果禁用了中斷,那么即使仲裁單元分發(fā)了中斷事件到 CPU 接口,也不會(huì)向 CPU 發(fā)送中斷信號(hào),就像是通信員關(guān)閉了與消防員的通信通道,消防員無法收到緊急任務(wù)通知。
  • 中斷應(yīng)答:當(dāng) CPU 接收到中斷信號(hào)并開始處理時(shí),會(huì)向 CPU 接口模塊應(yīng)答中斷 。中斷一旦被應(yīng)答,仲裁單元就會(huì)把該中斷的狀態(tài)從 pending 狀態(tài)修改成 active 。如果沒有后續(xù) pending 的中斷,那么 CPU 接口就會(huì)取消中斷信號(hào)的發(fā)送;如果在這個(gè)過程中又產(chǎn)生了新的中斷,仲裁單元會(huì)把新中斷的狀態(tài)從 pending 狀態(tài)修改成 pending and active ,CPU 接口仍然會(huì)保持中斷信號(hào)的發(fā)送,通知 CPU 有新的中斷到來,就像是消防員向通信員回復(fù)已收到任務(wù),并開始執(zhí)行,通信員根據(jù)任務(wù)情況決定是否繼續(xù)發(fā)送新的任務(wù)通知。
  • 中斷處理完成通知:當(dāng)中斷處理程序完成對(duì)一個(gè)中斷的處理后,會(huì)向 CPU 接口模塊的寄存器寫入信息,通知 GIC CPU 已經(jīng)處理完該中斷 。這樣做一方面是通知仲裁單元將中斷狀態(tài)修改為 deactive,另一方面,可以允許其他 pending 的中斷向 CPU 接口提交,就像是消防員完成任務(wù)后向通信員報(bào)告任務(wù)完成,通信員收到報(bào)告后,允許新的緊急任務(wù)進(jìn)入處理流程。
  • 優(yōu)先級(jí)掩碼設(shè)置:通過設(shè)置優(yōu)先級(jí)掩碼,可以屏蔽掉一些優(yōu)先級(jí)比較低的中斷,這些中斷不會(huì)被通知到 CPU 。例如,在系統(tǒng)進(jìn)行一些關(guān)鍵操作時(shí),可以通過設(shè)置優(yōu)先級(jí)掩碼,暫時(shí)屏蔽掉一些不重要的中斷,確保關(guān)鍵操作的順利進(jìn)行,就像是在執(zhí)行重要任務(wù)時(shí),暫時(shí)忽略一些次要的緊急事件。
  • 搶占策略定義:定義中斷的搶占策略,當(dāng)多個(gè)中斷到來的時(shí)候,選擇優(yōu)先級(jí)最高的中斷通知給 CPU Core 。比如,當(dāng)一個(gè)高優(yōu)先級(jí)的中斷到來時(shí),即使當(dāng)前 CPU 正在處理一個(gè)低優(yōu)先級(jí)的中斷,也會(huì)立即暫停當(dāng)前處理,轉(zhuǎn)而處理高優(yōu)先級(jí)的中斷,確保重要事件能夠得到優(yōu)先處理,就像是在多個(gè)緊急任務(wù)同時(shí)出現(xiàn)時(shí),優(yōu)先安排消防員處理最緊急的任務(wù)。

在 GIC 的工作過程中,這些寄存器就像是交通指揮中心的各種控制按鈕和顯示屏,通過對(duì)它們的配置和操作,實(shí)現(xiàn)對(duì)中斷的精確管理和高效處理 。例如,在系統(tǒng)初始化階段,需要對(duì) GIC 的寄存器進(jìn)行正確的配置,包括中斷使能、優(yōu)先級(jí)設(shè)置、觸發(fā)模式設(shè)置等,以確保系統(tǒng)能夠正常響應(yīng)各種中斷請(qǐng)求 。在中斷處理過程中,CPU 通過讀取和寫入相關(guān)寄存器,與 GIC 進(jìn)行交互,完成中斷的接收、處理和結(jié)束等操作 。

六、ARM+Linux中斷系統(tǒng)的應(yīng)用與優(yōu)化

6.1中斷處理程序的優(yōu)化

中斷處理程序的優(yōu)化,就像是對(duì)精密儀器的精細(xì)調(diào)校,每一個(gè)細(xì)節(jié)都關(guān)乎著系統(tǒng)的性能表現(xiàn)。從代碼結(jié)構(gòu)和算法選擇等角度入手,能夠顯著提高中斷處理程序的響應(yīng)速度,讓系統(tǒng)在面對(duì)各種中斷請(qǐng)求時(shí)更加游刃有余 。

在代碼結(jié)構(gòu)方面,要遵循簡(jiǎn)潔高效的原則。將中斷處理程序劃分為關(guān)鍵部分和非關(guān)鍵部分,是一種行之有效的策略。關(guān)鍵部分負(fù)責(zé)處理緊急且必須立即完成的任務(wù),如讀取硬件寄存器狀態(tài)、清除中斷標(biāo)志等,這些任務(wù)對(duì)時(shí)間要求極高,需要在最短的時(shí)間內(nèi)完成 。而非關(guān)鍵部分則可以將一些相對(duì)耗時(shí)但并非緊急的任務(wù),如數(shù)據(jù)處理、通知其他模塊等,放到中斷處理程序之外執(zhí)行,避免在中斷處理過程中占用過多時(shí)間,影響系統(tǒng)對(duì)其他中斷的響應(yīng) 。

在一個(gè)網(wǎng)絡(luò)通信設(shè)備的中斷處理程序中,當(dāng)接收到數(shù)據(jù)包時(shí),關(guān)鍵部分迅速讀取數(shù)據(jù)包的關(guān)鍵信息,如源地址、目的地址等,并清除中斷標(biāo)志,以確保能夠及時(shí)響應(yīng)下一個(gè)中斷請(qǐng)求;而非關(guān)鍵部分則將數(shù)據(jù)包的解析和處理工作放到一個(gè)專門的線程中執(zhí)行,這樣既保證了中斷處理的及時(shí)性,又不影響數(shù)據(jù)包的后續(xù)處理。

算法選擇也是優(yōu)化中斷處理程序的重要一環(huán)。選擇高效的算法能夠大大減少中斷處理的時(shí)間開銷,提高系統(tǒng)的性能。在數(shù)據(jù)處理任務(wù)中,不同的算法在時(shí)間復(fù)雜度和空間復(fù)雜度上存在差異,選擇合適的算法可以顯著提高處理效率 。假設(shè)需要對(duì)中斷處理過程中接收到的大量數(shù)據(jù)進(jìn)行排序,冒泡排序算法的時(shí)間復(fù)雜度為 O (n^2),而快速排序算法的平均時(shí)間復(fù)雜度為 O (n log n) 。

在數(shù)據(jù)量較大的情況下,使用快速排序算法能夠比冒泡排序算法節(jié)省大量的時(shí)間,從而提高中斷處理程序的執(zhí)行效率。因此,在編寫中斷處理程序時(shí),要根據(jù)具體的任務(wù)需求,仔細(xì)分析和選擇最優(yōu)的算法,以達(dá)到提高性能的目的 。

6.2硬件資源的合理配置

硬件資源的合理配置,是提升中斷系統(tǒng)整體性能的關(guān)鍵所在,就像是為一臺(tái)高性能電腦精心挑選和搭配各個(gè)硬件組件,使其發(fā)揮出最佳性能。在 ARM+Linux 中斷系統(tǒng)中,GIC(通用中斷控制器)作為核心硬件組件,對(duì)它的合理配置至關(guān)重要 。

GIC 的配置涉及多個(gè)方面,其中中斷優(yōu)先級(jí)的設(shè)置是關(guān)鍵環(huán)節(jié)之一。中斷優(yōu)先級(jí)決定了系統(tǒng)在處理多個(gè)中斷請(qǐng)求時(shí)的先后順序。在實(shí)際應(yīng)用中,要根據(jù)不同中斷源的重要性和實(shí)時(shí)性要求,合理地分配中斷優(yōu)先級(jí) 。對(duì)于那些對(duì)實(shí)時(shí)性要求極高的中斷源,如高速數(shù)據(jù)傳輸設(shè)備的中斷請(qǐng)求,應(yīng)將其優(yōu)先級(jí)設(shè)置為較高值,確保系統(tǒng)能夠在第一時(shí)間響應(yīng)并處理這些中斷,避免數(shù)據(jù)丟失或延遲 。

而對(duì)于一些對(duì)實(shí)時(shí)性要求相對(duì)較低的中斷源,如打印機(jī)等設(shè)備的中斷請(qǐng)求,可以將其優(yōu)先級(jí)設(shè)置為較低值。在一個(gè)工業(yè)自動(dòng)化控制系統(tǒng)中,傳感器的數(shù)據(jù)采集中斷和電機(jī)控制中斷對(duì)實(shí)時(shí)性要求很高,將它們的優(yōu)先級(jí)設(shè)置為較高,而系統(tǒng)日志記錄等輔助功能的中斷優(yōu)先級(jí)則設(shè)置為較低,這樣可以保證系統(tǒng)在關(guān)鍵任務(wù)上的實(shí)時(shí)性,同時(shí)也不影響其他非關(guān)鍵任務(wù)的正常執(zhí)行 。

中斷路由的配置也不容忽視。中斷路由決定了中斷請(qǐng)求如何被分發(fā)到相應(yīng)的 CPU 核心進(jìn)行處理。在多核處理器系統(tǒng)中,合理的中斷路由配置可以充分利用各個(gè) CPU 核心的處理能力,提高系統(tǒng)的并行處理能力 。可以根據(jù)不同中斷源的負(fù)載情況和 CPU 核心的利用率,將中斷請(qǐng)求均勻地分配到各個(gè) CPU 核心上,避免某個(gè) CPU 核心負(fù)載過高,而其他核心閑置的情況 。

在一個(gè)多線程的網(wǎng)絡(luò)服務(wù)器應(yīng)用中,將網(wǎng)絡(luò)接收中斷和網(wǎng)絡(luò)發(fā)送中斷分別路由到不同的 CPU 核心上處理,能夠充分發(fā)揮多核處理器的優(yōu)勢(shì),提高網(wǎng)絡(luò)數(shù)據(jù)的處理速度 。通過合理配置 GIC 的中斷優(yōu)先級(jí)和中斷路由等硬件資源,可以有效地提升中斷系統(tǒng)的整體性能,使系統(tǒng)更加穩(wěn)定、高效地運(yùn)行 。

6.3代碼實(shí)現(xiàn)

中斷注冊(cè)與注銷代碼示例:

在 ARM+Linux 的世界里,中斷注冊(cè)與注銷是與中斷系統(tǒng)交互的基礎(chǔ)操作,就像在一場(chǎng)盛大的音樂會(huì)上,為每一位演奏者安排好出場(chǎng)順序和離場(chǎng)流程。讓我們通過一段具體的代碼示例:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>

static irqreturn_t my_interrupt_handler(int irq, void *dev_id) {
    // 中斷處理邏輯
    printk(KERN_INFO "My Interrupt Handler: IRQ %d\n", irq);
    return IRQ_HANDLED;
}

static int __init my_module_init(void) {
    int irq_num = 50; // 假設(shè)使用的中斷號(hào)為50,實(shí)際應(yīng)用中需根據(jù)硬件確定
    int ret;

    // 中斷注冊(cè)
    ret = request_irq(irq_num, my_interrupt_handler, IRQF_TRIGGER_RISING, "my_device", NULL);
    if (ret) {
        printk(KERN_ERR "Failed to request IRQ %d: %d\n", irq_num, ret);
        return ret;
    }

    printk(KERN_INFO "Successfully registered IRQ %d\n", irq_num);
    return 0;
}

static void __exit my_module_exit(void) {
    int irq_num = 50;

    // 中斷注銷
    free_irq(irq_num, NULL);
    printk(KERN_INFO "Successfully unregistered IRQ %d\n", irq_num);
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("ARM+Linux Interrupt Example");

在這段代碼中,request_irq函數(shù)是中斷注冊(cè)的核心。它的第一個(gè)參數(shù)irq_num是要申請(qǐng)的硬件中斷號(hào),就像是為設(shè)備分配的一個(gè)獨(dú)特的 “身份證號(hào)碼”,在實(shí)際應(yīng)用中,這個(gè)號(hào)碼需要根據(jù)硬件的實(shí)際連接和配置來確定。第二個(gè)參數(shù)my_interrupt_handler是指向中斷處理函數(shù)的指針,當(dāng)中斷發(fā)生時(shí),系統(tǒng)就會(huì)調(diào)用這個(gè)函數(shù)來處理中斷,它就像是一位專業(yè)的 “問題解決者”,負(fù)責(zé)處理中斷帶來的各種任務(wù)。

第三個(gè)參數(shù)IRQF_TRIGGER_RISING是中斷處理的屬性,這里表示該中斷是上升沿觸發(fā),就像運(yùn)動(dòng)員聽到發(fā)令槍響(上升沿)后開始起跑一樣,系統(tǒng)在檢測(cè)到中斷信號(hào)的上升沿時(shí),會(huì)觸發(fā)中斷處理程序。第四個(gè)參數(shù)"my_device"是與中斷相關(guān)聯(lián)的設(shè)備名稱,方便在系統(tǒng)中識(shí)別和管理中斷,就像給每個(gè)設(shè)備貼上一個(gè)標(biāo)簽。最后一個(gè)參數(shù)NULL是設(shè)備的私有數(shù)據(jù)字段,在中斷共享時(shí)會(huì)用到,一般設(shè)置為這個(gè)設(shè)備的設(shè)備結(jié)構(gòu)體或者NULL 。

free_irq函數(shù)則用于中斷注銷,它的第一個(gè)參數(shù)是要釋放的中斷號(hào),第二個(gè)參數(shù)與注冊(cè)時(shí)的dev_id相對(duì)應(yīng),用于確保正確地釋放中斷資源。在中斷注銷時(shí),就像是讓演奏者有序地離開舞臺(tái),系統(tǒng)會(huì)清理與該中斷相關(guān)的資源,確保系統(tǒng)的穩(wěn)定運(yùn)行 。

中斷處理函數(shù)編寫:

中斷處理函數(shù)是中斷系統(tǒng)的核心,它就像是一位經(jīng)驗(yàn)豐富的指揮官,在中斷發(fā)生時(shí),迅速做出決策,指揮系統(tǒng)應(yīng)對(duì)各種情況。讓我們來看一個(gè)完整的中斷處理函數(shù)代碼示例,并深入分析其中的處理邏輯。

static irqreturn_t my_interrupt_handler(int irq, void *dev_id) {
    // 檢查中斷源
    if (irq == IRQ_BUTTON) {
        // 處理按鍵中斷
        printk(KERN_INFO "Button Interrupt Detected\n");
        // 讀取按鍵狀態(tài)
        int button_state = read_button_state();
        if (button_state == PRESSED) {
            // 執(zhí)行按鍵按下的操作
            perform_button_press_action();
        } else {
            // 執(zhí)行按鍵松開的操作
            perform_button_release_action();
        }
    } else if (irq == IRQ_TIMER) {
        // 處理定時(shí)器中斷
        printk(KERN_INFO "Timer Interrupt Detected\n");
        // 更新定時(shí)器相關(guān)的變量
        update_timer_variables();
        // 執(zhí)行定時(shí)器到期的任務(wù)
        perform_timer_expiry_task();
    } else {
        // 未知中斷源,返回未處理
        return IRQ_NONE;
    }

    // 表示中斷已處理
    return IRQ_HANDLED;
}

在這個(gè)中斷處理函數(shù)中,首先通過if - else if語句來檢查中斷源。這就像是指揮官在戰(zhàn)場(chǎng)上,首先要明確敵人的來源,才能做出正確的戰(zhàn)略部署。如果中斷源是按鍵(IRQ_BUTTON),則讀取按鍵狀態(tài),并根據(jù)狀態(tài)執(zhí)行相應(yīng)的操作,就像根據(jù)敵人的行動(dòng)做出不同的應(yīng)對(duì)策略。如果是定時(shí)器中斷(IRQ_TIMER),則更新定時(shí)器相關(guān)的變量,并執(zhí)行定時(shí)器到期的任務(wù)。

如果遇到未知的中斷源,函數(shù)會(huì)返回IRQ_NONE,表示該中斷未被處理,就像指揮官遇到無法識(shí)別的情況時(shí),選擇暫時(shí)不采取行動(dòng),等待進(jìn)一步的信息。而當(dāng)所有的中斷處理完成后,函數(shù)返回IRQ_HANDLED,表示中斷已被成功處理,就像指揮官成功完成了一次戰(zhàn)斗任務(wù),向總部匯報(bào)勝利的消息 。通過這樣的處理邏輯,中斷處理函數(shù)能夠有條不紊地應(yīng)對(duì)各種中斷情況,確保系統(tǒng)的穩(wěn)定和高效運(yùn)行。

責(zé)任編輯:武曉燕 來源: 深度Linux
相關(guān)推薦

2022-01-03 23:33:40

Linux組件系統(tǒng)

2009-05-27 19:28:20

Linux磁場(chǎng)設(shè)計(jì)

2009-07-17 16:06:59

ARM嵌入式開發(fā)

2010-01-07 10:45:38

嵌入式Linux入門

2020-07-03 07:00:00

Linux組件

2021-12-19 22:34:45

Linux容器系統(tǒng)

2011-06-17 08:59:27

QT Embedded Arm

2010-01-12 17:32:40

ARM平臺(tái)

2012-07-30 14:13:11

Linux 2.6內(nèi)核嵌入式

2009-06-26 16:05:04

嵌入式Linux

2011-01-14 13:13:23

嵌入式Linux開發(fā)

2022-12-14 08:06:08

2023-01-04 09:37:16

2011-01-06 15:11:09

嵌入式linux

2017-12-21 10:43:44

Linux嵌入式終端

2011-04-25 10:25:43

OpenEmbedde嵌入式Linux

2009-04-11 15:22:24

Linux 2.6內(nèi)核應(yīng)用

2020-06-15 07:00:00

Linux嵌入式系統(tǒng)

2020-11-16 10:47:14

FreeRTOS應(yīng)用嵌入式

2009-04-11 15:12:24

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 激情婷婷 | 欧美一区二区三区,视频 | 精品国产欧美 | 99精品久久久 | 成人精品影院 | 国产精品视频免费观看 | av在线成人 | 欧美精品成人一区二区三区四区 | 国产精品乱码一二三区的特点 | 中文字幕国产精品 | 天堂一区在线 | 久久久久一区二区三区 | 中文字幕久久精品 | 精品免费 | 日韩成人在线观看 | 日日操夜夜干 | 色爱综合网 | 欧美黑人一区 | hsck成人网| 国产91久久久久 | 久久久亚洲一区 | 97av视频 | 精品国产一区二区在线 | 国产欧美一区二区精品久导航 | 天天综合网天天综合色 | 免费激情 | 久久机热 | 一区二区三区视频在线观看 | 成年人网站国产 | 亚洲国产精品视频 | 亚州激情 | 亚洲狠狠爱| 中文字幕一级 | 久草视频观看 | 欧美久久久网站 | 免费一级毛片 | 久久久久国产精品午夜一区 | 精品国产乱码久久久久久闺蜜 | 一区二区三区四区不卡 | 国产男女视频 | 国产99小视频 |