女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一個(gè)關(guān)于Linux中斷的問(wèn)題:硬件處理,初始化和中斷處理

Linux閱碼場(chǎng) ? 來(lái)源:未知 ? 作者:李倩 ? 2018-08-09 17:16 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

硬件處理

最近解決一個(gè)關(guān)于Linux中斷的問(wèn)題,把相關(guān)機(jī)制整理了一遍,記錄在此。

不同的外部設(shè)備、不同的體系結(jié)構(gòu)、不同的OS其中斷實(shí)現(xiàn)機(jī)制都有差別,本文對(duì)應(yīng)的OS為linux3.4版本,外部設(shè)備為PCI設(shè)備、系統(tǒng)為X86。

概覽

中斷讓外設(shè)能夠通知CPU他需要獲得服務(wù)(讓CPU執(zhí)行指定的中斷服務(wù)例程ISR)。為了達(dá)到這個(gè)目的,首先要為中斷執(zhí)行做好準(zhǔn)備,完成初始化相關(guān)的操作。包括:1、 初始化中斷控制器等相關(guān)器件(OS初始化過(guò)程中完成);2、 配置并使能外部設(shè)備(比如使用pci_enable_msix),得到irq號(hào);在這個(gè)操作過(guò)程中,內(nèi)核需要完成的大致操作是:

1、 確定該中斷的執(zhí)行CPU,并在對(duì)應(yīng)CPU上建立vector和irq號(hào)的對(duì)應(yīng)關(guān)系(利用全局per-cpu變量vector_irq),配置中斷控制器(I/OAPIC、PIR等),可能還需要設(shè)置外部設(shè)備(比如設(shè)置MSI

Capacity registers);

2、 為對(duì)應(yīng)的irq_desc初始化正確的handle_irq接口(通用邏輯接口);

3、 為對(duì)應(yīng)的irq_desc初始化正確的底層chip操作接口。

3、 使用request_irq號(hào)為該中斷號(hào)指定一個(gè)服務(wù)例程;

完成了以上的初始化操作,在外設(shè)中斷到來(lái)的時(shí)候,為該中斷指定的ISR(Interrupt Service Routines)就能得到執(zhí)行,這個(gè)執(zhí)行過(guò)程大致如下:

1、 外設(shè)根據(jù)各自的配置,產(chǎn)生中斷信號(hào)或者中斷消息(MSI,INT# message)。2、 中斷控制器從外設(shè)獲取中斷電信號(hào)或者中斷消息,把它翻譯為vector(CPU使用這個(gè)參數(shù)來(lái)決定是誰(shuí)發(fā)生了中斷,要如何處理)并提交到CPU。3、 對(duì)X86系統(tǒng),CPU利用從中斷控制器獲取到的vector為索引,查詢IDT (interrupt descriptor table)得到該中斷的處理接口(對(duì)linux,是在entry_64.s中定義的函數(shù)common_interrupt接口)并執(zhí)行。4、 在linux定義的common_interrupt接口中,執(zhí)行完中斷執(zhí)行環(huán)境建立后,會(huì)進(jìn)入generic interrupt layer執(zhí)行,其首先通過(guò)vector查找到irq和對(duì)應(yīng)的irq_desc結(jié)構(gòu),并執(zhí)行該結(jié)構(gòu)的handle_irq接口,這個(gè)接口就是generic interrupt layer的通用邏輯接口,比如handle_edge_irq/handle_level_irq等;在中斷執(zhí)行的通用邏輯接口中,會(huì)通過(guò)irq_desc::action調(diào)用外設(shè)指定的ISR。在linux中可以通過(guò)/proc/interrupts查看當(dāng)前系統(tǒng)中所有中斷的統(tǒng)計(jì)信息,在/proc/irq/xxx(中斷號(hào))下面,可以看到該中斷的詳細(xì)信息。

中斷相關(guān)硬件

這里的描述很多來(lái)自INTEL的文檔《Intel Software developer’s Manual, system programming guide》和《PCI Express System Architecture》

中斷控制器

中斷控制器的功能是:把外設(shè)的中斷信號(hào),轉(zhuǎn)換成CPU能夠明白的vector,并完成中斷執(zhí)行控制,確保在合適的時(shí)機(jī)把中斷提交給CPU執(zhí)行。對(duì)這部分內(nèi)容,《interrupt in linux》有詳細(xì)的描述。1、 8259A:每個(gè)8259A有8個(gè)管腳,每個(gè)管腳對(duì)應(yīng)其連接的CPU的IDT中的一個(gè)vector,單獨(dú)使用8259A,其硬件連線就決定了對(duì)設(shè)備vector的使用。典型的場(chǎng)景是使用兩個(gè)8259A級(jí)聯(lián),理論最多16個(gè)中斷號(hào)(就是ISA IRQs),實(shí)際能提供對(duì)15個(gè)中斷線的處理(master的IRQ2用于連接slave),其具體的分配見(jiàn)下圖。2、 PIR:用于完成輸入的信號(hào)到輸出信號(hào)的映射。在下圖中PIR被用于完成多個(gè)PCI設(shè)備的INT#信號(hào)到8259A對(duì)應(yīng)引腳的路由。對(duì)應(yīng)這種連接方式,在PCI設(shè)備初始化的時(shí)候,OS會(huì)根據(jù)BISO提供的信息設(shè)置PIR,把INT#路由到O0-O3中正確的管腳,從而體現(xiàn)到8259A的正確管腳(對(duì)應(yīng)了vector),這樣INT#信號(hào)就被轉(zhuǎn)換為vector并提交到CPU。由于可能有較多的PCI設(shè)備,而PIR的輸入/出錯(cuò)管腳有限,所以連接到相同輸入關(guān)鍵的INT#會(huì)共享一個(gè)中斷。

3、 I/O APIC每個(gè)I/O APIC提供24個(gè)管腳,能夠和外部設(shè)備的中斷線連接,每個(gè)管腳都可以通過(guò)配RTE(Redirection table entry)配置對(duì)應(yīng)的vector。其功能是:把外部設(shè)備的中斷請(qǐng)求,翻譯為local APIC的interrupt message,并按照配置的vector,發(fā)送給指定的local APIC處理(在SMP系統(tǒng),存在多個(gè)CPU,也就有多個(gè)local APIC)。通常的配置方式是:第一個(gè)I/O APIC的前16個(gè)管腳,配置來(lái)處理之前的ISA IRQs,其它外設(shè)比如PCI設(shè)備,則直接使用其他管腳連接。4、 local APIC其負(fù)責(zé)處理IPI(inter-process interrupt)、直接連接的中斷處理、接收和處理interrupt message,每個(gè)CPU有自己的local APIC。對(duì)應(yīng)I/O APIC和local APIC的組合,其連接方式見(jiàn)下圖

針對(duì)X86中斷控制器硬件和linux對(duì)這些硬件的初始化,在《interrupt in linux》中有很詳細(xì)的描述。

X86對(duì)中斷的處理

Local APIC的處理過(guò)程每個(gè)local APIC對(duì)應(yīng)了一個(gè)CPU。其處理interrupt message的過(guò)程如下:1、 判斷該中斷的destination是否為當(dāng)前APIC,如果不是則忽略,否則繼續(xù)處理2、 如果是SMI/NMI/INIT/ExtINT, or SIPI(這些中斷都負(fù)責(zé)特殊的系統(tǒng)管理任務(wù),外設(shè)一般不會(huì)使用)被直接送到CPU執(zhí)行,否則執(zhí)行下一步。3、 設(shè)置Local APIC 的IRR寄存器的對(duì)應(yīng)bit位。4、 如果該中斷優(yōu)先級(jí)高于當(dāng)前CPU正在執(zhí)行的中斷,且當(dāng)前CPU沒(méi)有屏蔽中斷(按照X86和LINUX的實(shí)現(xiàn),這時(shí)是屏蔽了中斷的),則該高優(yōu)先級(jí)中斷會(huì)中斷當(dāng)前正在執(zhí)行的中斷(置ISR位,并開(kāi)始執(zhí)行),低優(yōu)先級(jí)中斷會(huì)在高優(yōu)先級(jí)中斷完成后繼續(xù)執(zhí)行,否則只有等到當(dāng)前中斷執(zhí)行完成(寫(xiě)了EOI寄存器)后才能開(kāi)始執(zhí)行下一個(gè)中斷。5、 在CPU可以處理下一個(gè)中斷的時(shí)候,從IRR中選取最高優(yōu)先級(jí)的中斷,清0 IRR中的對(duì)應(yīng)位,并設(shè)置ISR中的對(duì)應(yīng)位,然后ISR中最高優(yōu)先級(jí)的中斷被發(fā)送到CPU執(zhí)行(如果其它優(yōu)先級(jí)和屏蔽檢查通過(guò))。6、 CPU執(zhí)行中斷處理例程,在合適的時(shí)機(jī)(在IRET指令前)通過(guò)寫(xiě)EOI寄存器來(lái)確認(rèn)中斷處理已經(jīng)完成,寫(xiě)EOI寄存器會(huì)導(dǎo)致local APIC清理ISR的對(duì)應(yīng)bit,對(duì)于level trigged中斷,還會(huì)向所有的I/O APIC發(fā)送EOI message,通告中斷處理已經(jīng)完成。

說(shuō)明:1、 關(guān)于Local APIC的IRR和ISR寄存器interrupt request register (IRR) 和 in-service register (ISR),都是256bit寄存器,每個(gè)bit對(duì)應(yīng)一個(gè)中斷(其中[0-15]不能使用,SMI/NMI/INIT/ExtINT/SIPI的發(fā)送和執(zhí)行不經(jīng)過(guò)ISR和IRR) 。IRR中保存的是已經(jīng)被local APIC接納但是還沒(méi)有開(kāi)始執(zhí)行的中斷;ISR中保持的是當(dāng)前正在執(zhí)行但是還沒(méi)有完成的中斷。2、 中斷優(yōu)先級(jí)對(duì)應(yīng)通過(guò)local APIC發(fā)送到CPU的中斷,按照其vector進(jìn)行優(yōu)先級(jí)排序:優(yōu)先級(jí)=vector/16數(shù)值越大,優(yōu)先級(jí)越高。由于local APIC允許的vector范圍為[16,255],而X86系統(tǒng)預(yù)留了[0,31]作為系統(tǒng)保留使用的vector,實(shí)際的用戶定義中斷的優(yōu)先級(jí)的取值范圍為[2,15],在每個(gè)優(yōu)先級(jí)內(nèi)部,vector的值越大,優(yōu)先級(jí)越高。Local APIC中還有一個(gè)關(guān)于中斷優(yōu)先級(jí)的寄存器TPR(task priority register)寄存器:用于確定打斷線程執(zhí)行需要的中斷優(yōu)先級(jí)級(jí)別,只有優(yōu)先級(jí)高于設(shè)置值的中斷才會(huì)被CPU執(zhí)行 (SMI/NMI/INIT/ExtINT, or SIPI不受限制),也就是除了特殊中斷外,優(yōu)先級(jí)低于TPR指定值的中斷將被忽略。3、 中斷的pending對(duì)于同一個(gè)vector,如果有多次中斷請(qǐng)求,可能IRR和ISR對(duì)應(yīng)的bit位都被置位,也就是對(duì)同一個(gè)vector,local APIC可以pending兩個(gè)中斷,其后的即使有多處,也會(huì)被合并為一個(gè)執(zhí)行。4、 中斷執(zhí)行時(shí)機(jī)中斷的執(zhí)行總是在指令邊界開(kāi)始(只有一個(gè)特殊的exception:abort在外,出現(xiàn)了這個(gè)中斷,系統(tǒng)基本上也就完蛋了),也就是中斷不可能打斷指令的執(zhí)行。

CPU對(duì)中斷和異常的處理相關(guān)概念1、 vector(中斷向量)vector是一個(gè)整數(shù),在X86CPU上,使用vector對(duì)中斷(interrupt,外部設(shè)備產(chǎn)生)和異常(exception,CPU在程序執(zhí)行中產(chǎn)生)統(tǒng)一編號(hào),每個(gè)CPU核心內(nèi)部,中斷/異常和vector所以一一對(duì)應(yīng)的;但是在各個(gè)不同的CPU核心上,相同的vector可以對(duì)應(yīng)不同的中斷(至少對(duì)于linux的設(shè)置,異常還是使用相同的vector)。vector的取值范圍為[0,255],其中[0,31]被系統(tǒng)保留使用(多數(shù)作為異常的vector),其余的可供外設(shè)中斷使用(系統(tǒng)設(shè)備比如local APIC也占用了部分[32,255]這個(gè)范圍的vector)。2、 IDT(interrupt descriptor table)X86 CPU采用一個(gè)有256個(gè)元素的數(shù)組來(lái)描述中斷/異常,該數(shù)組的index為vector;其內(nèi)容包括了三種gate descriptor,用于描述一個(gè)中斷/異常的處理接口;這個(gè)數(shù)組就是IDT,CPU在收到中斷請(qǐng)求的時(shí)候,就利用vector獲取到對(duì)應(yīng)的中斷處理接口描述并執(zhí)行。3、 可屏蔽中斷通過(guò)CPU INTR管腳/local APIC接收到的中斷是可屏蔽中斷,這些中斷能夠通過(guò)清零EFLAGS的IF來(lái)屏蔽(CLI指令)。通過(guò)INT n指令生成的中斷即使使用了和外部中斷一樣的vector,也是不可屏蔽的;同樣CPU運(yùn)行過(guò)程中同步產(chǎn)生的trap、fault、abort等異常也是不可屏蔽的。4、 NMINMI是不可屏蔽中斷(不可通過(guò)IF標(biāo)志屏蔽),是通過(guò)CPU的NMI管腳發(fā)出的中斷或者通過(guò)delivery mode為NMI的方式提交的中斷。NMI中斷在執(zhí)行前,CPU不僅會(huì)屏蔽其它中斷,也會(huì)屏蔽NMI中斷,直到NMI中斷處理執(zhí)行完成(IRET指令被執(zhí)行)。使用INT 2指令雖然能執(zhí)行NMI中斷處理函數(shù),但是相關(guān)硬件不會(huì)介入,也就是沒(méi)有相關(guān)的屏蔽NMI中斷的操作。

CPU執(zhí)行中斷的過(guò)程1、 利用vector,查IDT得到中斷描述符;2、 如果中斷發(fā)生在用戶態(tài),會(huì)首先執(zhí)行stack switch切換到內(nèi)核態(tài)執(zhí)行;3、 依次保存EFLAGS CS IP到當(dāng)前棧,如果需要(有error code的異常),把error code PUSH到當(dāng)前棧。并把IF/TF位清零屏蔽可屏蔽中斷;至此,CPU完成了中斷處理程序執(zhí)行環(huán)境的建立。4、 執(zhí)行中斷描述符定義的中斷處理入口(IDT中指定地址的代碼);5、 根據(jù)環(huán)境執(zhí)行不同的中斷退出方式,比如執(zhí)行現(xiàn)場(chǎng)調(diào)度操作(retint_careful和retint_kernel),最終都會(huì)執(zhí)行IRET指令;至此,中斷執(zhí)行完成。異常的執(zhí)行過(guò)程類似,只不過(guò)異常在執(zhí)行前不會(huì)把IF位清零,只清零TF位。

PCI設(shè)備的中斷

本部分的很多內(nèi)容來(lái)自《PCI Interrupts for x86 Machines under FreeBSD》和《PCI Express?Base Specification Revision 3.0》和《PCI Express System Architecture》。PCI設(shè)備的中斷有兩種模式:一種是INT#模式,一種是MSI模式。

INT#模式每個(gè)PCI設(shè)備用四個(gè)中斷信號(hào),對(duì)應(yīng)INTA#、INTB# INTC#、INTD#,這些中斷信號(hào)采用level trigger 的方式并且為低電平有效,PCI設(shè)備通過(guò)拉低對(duì)應(yīng)的信號(hào)來(lái)assert對(duì)應(yīng)的中斷,并在ISR訪問(wèn)PCI設(shè)備的指定寄存器deassert該中斷。

中斷線和X86系統(tǒng)的連接這里存在兩種常見(jiàn)連接模式,一種是使用老的8259A+PIR的系統(tǒng),一種是使用新的I/O APIC的系統(tǒng)。對(duì)于使用8259A的系統(tǒng):PCI的中斷線連接到一個(gè)可編程的PIR設(shè)備,再通過(guò)該設(shè)備連接到8259A(見(jiàn)X86中斷控制器一章的圖);對(duì)于采用I/OAPIC的系統(tǒng),可以使用以下的連接方式,同樣這里只畫(huà)出了一個(gè)中斷線,同時(shí)根據(jù)不同的系統(tǒng)配置可能存在多個(gè)I/OAPIC。除了采用直接的中斷引腳連接,PCI還支持virtual INT#,使用INT# message(Assert INT# message和deassert INT# message)的方式來(lái)使用INT#信號(hào)。

NT#模式的局限1、 中斷數(shù)量有限且不方便擴(kuò)展:每個(gè)物理的PCI設(shè)備,最多只有4個(gè)中斷但是至少能支持8個(gè)function,且系統(tǒng)中可能存在多個(gè)PCI設(shè)備,不得不使用中斷共享的模式,影響使用性能。2、 同步問(wèn)題:由于INT#中斷采用的是side channel,中斷信號(hào)和數(shù)據(jù)本身存在不同步的問(wèn)題:可能在中斷到達(dá)的時(shí)候,對(duì)應(yīng)的數(shù)據(jù)沒(méi)有達(dá)到,為了處理這個(gè)問(wèn)題,一般采用“讀刷新”的做法,也就是在使用該設(shè)備寫(xiě)入到X86的數(shù)據(jù)之前,ISR先對(duì)這個(gè)設(shè)備進(jìn)行一次讀操作來(lái)確保相關(guān)數(shù)據(jù)已經(jīng)寫(xiě)入完成,比如讀PCI設(shè)備的中斷狀態(tài)寄存器等。

MSI/MSI-X模式在這種模式下,PCI設(shè)備通過(guò)和數(shù)據(jù)DMA一樣的通道來(lái)完成中斷處理,通過(guò)向特定地址空間(系統(tǒng)FSB Interrupt存儲(chǔ)器空間)發(fā)起一個(gè)寫(xiě)操作來(lái)發(fā)起中斷。該寫(xiě)操作的地址和數(shù)據(jù)信息在PCI設(shè)備初始化MSI功能的時(shí)候已經(jīng)填寫(xiě)到MSI Capacity registers(MSI模式)/MSI-X table(MSI-X)中(對(duì)X86,這個(gè)地址空間是FEE00000H開(kāi)始的地址空間,其實(shí)就是local APIC寄存器映射的地址空間),地址信息保存在Message address register,其中包含了目標(biāo)CPU信息和FSB Interrupt存儲(chǔ)器空間;數(shù)據(jù)中包含了該MSI中斷對(duì)應(yīng)的vector,保存在Message data register中。 MCH(memory control hub)截獲這個(gè)寫(xiě)操作,轉(zhuǎn)換為FSB interrupt message并向各個(gè)CPU核心廣播,local APIC接收并處理這個(gè)消息,最終觸發(fā)CPU的中斷處理過(guò)程。使用這種機(jī)制,中斷的數(shù)量不受PIR/ IOAPIC等各種器件管腳數(shù)量的限制,MSI可以支持32個(gè)中斷,而MSI-X可以達(dá)到2048個(gè);中斷的傳遞相當(dāng)直接,省略了中斷路由的過(guò)程;并且能直接從interrupt message中獲取vector信息,減少了交互過(guò)程。

初始化

相關(guān)概念和關(guān)鍵數(shù)據(jù)結(jié)構(gòu)

1、 irq號(hào):在當(dāng)前系統(tǒng)中全局唯一,對(duì)應(yīng)內(nèi)核數(shù)據(jù)結(jié)構(gòu)struct irq_desc,每個(gè)外設(shè)的中斷有一個(gè)irq號(hào)(體系結(jié)構(gòu)預(yù)留的中斷,是沒(méi)有對(duì)應(yīng)的irq_desc結(jié)構(gòu)和irq號(hào)的),該irq在該中斷的生命周期內(nèi)都不會(huì)改變,且和該中斷的中斷處理函數(shù)關(guān)聯(lián);內(nèi)核使用一個(gè)bitmap allocated_irqs來(lái)標(biāo)識(shí)當(dāng)前系統(tǒng)已經(jīng)分配的irq;irq號(hào)的管理與底層中斷設(shè)備和配置無(wú)關(guān),屬于Generic Interrupt Layer;對(duì)于irq號(hào)分布集中的情況,不配置CONFIG_SPARSE_IRQ,內(nèi)核采用數(shù)組直接管理,數(shù)組下標(biāo)就是irq號(hào);而對(duì)于irq號(hào)比較分散的,設(shè)置CONFIG_SPARSE_IRQ,內(nèi)核采用radix tree來(lái)管理所有的irq號(hào)。2、 vector號(hào):內(nèi)核使用全局bitmap used_vectors來(lái)標(biāo)識(shí)那些vector被系統(tǒng)預(yù)留,不能被外設(shè)分配使用。3、 irq號(hào)和vector號(hào)的關(guān)聯(lián):內(nèi)核中使用per-cpu變量vector_irq來(lái)描述irq號(hào)和vector號(hào)的關(guān)聯(lián),對(duì)每個(gè)CPU,vector_irq是一個(gè)數(shù)組,在X86架構(gòu)下成員數(shù)量為256,其數(shù)組的index為vector,值為irq,如果為-1則表示該CPU上的這個(gè)vector尚未分配。4、 struct irq_desc結(jié)構(gòu),用來(lái)描述一個(gè)中斷,是內(nèi)核generic interrupt layer的關(guān)鍵數(shù)據(jù)結(jié)構(gòu),其包含了中斷的大部分信息,并連接了driver層和物理中斷設(shè)備層,每個(gè)irq號(hào)對(duì)應(yīng)一個(gè)該結(jié)構(gòu),共享相同irq號(hào)的中斷共享該結(jié)構(gòu)。它的關(guān)鍵成員包括:

a) irq_data :為該中斷對(duì)應(yīng)的物理中斷設(shè)備層相關(guān)的數(shù)據(jù)。

b) handle_irq:為該該中斷使用的通用邏輯接口。

c) action:為driver層提供的ISR信息,其為一個(gè)單向鏈表結(jié)構(gòu),所有共享該中斷的設(shè)備的ISR都鏈接在這里。

內(nèi)核關(guān)鍵數(shù)據(jù)結(jié)構(gòu)和相關(guān)初始化

對(duì)X86 CPU,Linux內(nèi)核使用全局idt_table來(lái)表達(dá)當(dāng)前的IDT,該變量定義在traps.c

gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, };//初始化為全0。

對(duì)中斷相關(guān)的初始化,內(nèi)核主要有以下工作:1、 設(shè)置used_vectors,確保外設(shè)不能分配到X86保留使用的vector(預(yù)留的vector范圍為[0,31],另外還有其他通過(guò)apic_intr_init等接口預(yù)留的系統(tǒng)使用的vector);2、 設(shè)置X86CPU保留使用的vector對(duì)應(yīng)的IDT entry;這些entry使用特定的中斷處理接口;3、 設(shè)置外設(shè) (包括ISA中斷)使用的中斷處理接口,這些中斷處理接口都一樣。4、 設(shè)置ISA IRQ使用的irq_desc;5、 把IDT的首地址加載到CPU的IDTR(Interrupt Descriptor Table Register);6、 初始化中斷控制器(下一章描述)以上工作主要在以下函數(shù)中完成:

可以看到,這個(gè)過(guò)程會(huì)完成每個(gè)中斷vector對(duì)應(yīng)的idt entry的初始化,系統(tǒng)把這些中斷vector分成以下幾種:1、X86保留vector,這些vector包括[0,0x1f]和APIC等系統(tǒng)部件占用的vector,對(duì)這些vector,會(huì)記錄在bitmap used_vectors中,確保不會(huì)被外設(shè)分配使用;同時(shí)這些vector都使用各自的中斷處理接口,其中斷處理過(guò)程相對(duì)簡(jiǎn)單(沒(méi)有g(shù)eneric interrupt layer的參與,CPU直接調(diào)用到各自的ISR)。2、ISA irqs,對(duì)這些中斷,在初始化過(guò)程中已經(jīng)完成了irq_desc、vector_irq、以及IDT中對(duì)應(yīng)entry的分配和設(shè)置,同時(shí)可以發(fā)現(xiàn)ISA中斷,在初始化的時(shí)候都被設(shè)置為運(yùn)行在0號(hào)CPU。3、其它外設(shè)的中斷,對(duì)這些中斷,在初始化過(guò)程中僅設(shè)置了對(duì)應(yīng)的IDT,和ISA中斷一樣,其中斷處理接口都來(lái)自interrupt數(shù)組。

中斷處理接口interrupt數(shù)組interrupt數(shù)組是內(nèi)核中外設(shè)中斷對(duì)應(yīng)的IDT entry,其在entry_64.S中定義,定義如下:

這段匯編的效果是:在代碼段,生成了一個(gè)符號(hào)irq_entries_start,該符號(hào)對(duì)應(yīng)的內(nèi)容是一組可執(zhí)行代碼,一共(NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7組,每組為7個(gè)中斷入口,為:

每組的最后一個(gè)中斷入口不需要jmp 2f是因?yàn)槠鋚ushq_cfi(就是pushq咯)下面就是2f這個(gè)標(biāo)號(hào)的地址了。(不明白的是:為什么不在jmp 2f的地方直接寫(xiě)上jmp common_interrupt?非要jmp 2f,2f的地方再次jmp common_interrupt?)

而interrupt是一個(gè)數(shù)組,該數(shù)組在初始化完成后釋放,其每個(gè)數(shù)組項(xiàng)都是一個(gè)地址,是對(duì)應(yīng)的“pushq_cfi”代碼的地址(每個(gè)代表中斷入口的標(biāo)號(hào))。系統(tǒng)在初始化的時(shí)候,對(duì)外設(shè)使用interrupt數(shù)組作中斷處理接口,就是在中斷發(fā)生時(shí),執(zhí)行代碼段:

初始化中斷控制器

對(duì)中斷控制器的使用基本上有三種機(jī)制:1、 中斷路由表 $PIRstruct irq_routing_table,該結(jié)構(gòu)用于使用PIR和8259A的系統(tǒng),在微軟的文獻(xiàn)《PCI IRQ Routing Table Specification》中描述了該結(jié)構(gòu)詳細(xì)信息。其描述了一個(gè)PCI設(shè)備的INT#是如何連接到PIR設(shè)備的輸入端口的。其關(guān)鍵數(shù)據(jù)是一個(gè)可變長(zhǎng)的struct irq_info數(shù)組,每個(gè)struct irq_info描述了一個(gè)PCI物理設(shè)備的4個(gè)INT#相關(guān)的中斷路由信息和對(duì)應(yīng)可用的ISA IRQs的bitmap。BIOS根據(jù)相關(guān)設(shè)備的物理連接填寫(xiě)該數(shù)據(jù)結(jié)構(gòu),OS在設(shè)備初始化過(guò)程中使用這些信息為使用INT#的設(shè)備分配對(duì)應(yīng)的vector和irq。2、 MP tablestruct mpc_intsrc,該數(shù)據(jù)結(jié)構(gòu)用于使用I/O APIC的系統(tǒng)中,描述系統(tǒng)中所有PCI設(shè)備4個(gè)INT#信號(hào)和I/O APIC輸入引腳的對(duì)應(yīng)關(guān)系。該數(shù)據(jù)結(jié)構(gòu)的srcbus成員為對(duì)應(yīng)PCI設(shè)備的bus id;srcbusirq描述了一個(gè)INT#信號(hào),其bit0-bit1用于描述是INTA#–INTD#中的哪一個(gè)(對(duì)應(yīng)值為0-3),bit2-bit6描述該P(yáng)CI設(shè)備的slot id。dstapic為該描述對(duì)應(yīng)的I/O APIC的ID。dstirq描述srcbus和srcbusirq確定的INT#對(duì)應(yīng)的irq號(hào)信息(具體的解析有多種情況)。在系統(tǒng)中有一個(gè)以該數(shù)據(jù)結(jié)構(gòu)為成員的全局?jǐn)?shù)組mp_irqs,用于管理系統(tǒng)中所有的硬件中斷信號(hào)和irq之間的關(guān)聯(lián)。對(duì)MP table及其使用的更加詳細(xì)的描述,見(jiàn)《Multiprocessor Specification v1.4》3、 ACPI(Advanced Configuration and PowerInterface)機(jī)制這種機(jī)制為I/O APIC機(jī)制和中PIR機(jī)制提供統(tǒng)一的管理界面,該機(jī)制使用struct acpi_prt_entry描述INT#和GSI(能和vector、irq對(duì)應(yīng))的關(guān)系,系統(tǒng)中所有的struct acpi_prt_entry由OS從BIOS提供的信息中獲取,并保存在鏈表acpi_prt_list中。注:對(duì)GSI的說(shuō)明,GSI(global system interrupt)表示的是系統(tǒng)中中斷控制器的每個(gè)輸入管腳的唯一編號(hào),在使用ACPI模式管理中斷控制器的時(shí)候使用。對(duì)使用8259A的系統(tǒng),GSI和ISA IRQ是一一對(duì)應(yīng)的。對(duì)于使用APIC的,每個(gè)I/O APIC會(huì)由BISO分配一個(gè)基址,這個(gè)base+對(duì)應(yīng)管腳的編號(hào)(從0開(kāi)始)就是對(duì)應(yīng)的GSI。通常是基址為0的I/O APIC的前16個(gè)管腳用于ISA IRQS,對(duì)GSI更加詳細(xì)的描述,見(jiàn)《Advanced Configuration and Power Interface Revision 2.0》

除了中斷路由表,其它兩種機(jī)制的初始化(包括相關(guān)中斷路由信息的初始化)的在《interrupt in linux》中有很詳細(xì)的描述。這些初始化操作都在內(nèi)核初始化的時(shí)候完成。

為PCI設(shè)備配置中斷

為PCI設(shè)備配置中斷,分為兩個(gè)步驟,步驟一:為設(shè)備分配irq號(hào)(對(duì)MSIX,會(huì)有多個(gè)),為該中斷分配執(zhí)行CPU和它使用的vector,并通過(guò)對(duì)中斷控制器的設(shè)置,確保對(duì)應(yīng)的中斷信號(hào)和vector匹配。對(duì)于使用INT#類型的中斷,通常通過(guò)pci_enable_device/pci_enable_device_mem/pci_enable_device_io中對(duì)函數(shù)pcibios_enable_device的調(diào)用來(lái)完成(只有在沒(méi)有開(kāi)啟MSI/MSIX的時(shí)候才會(huì)為INT#做配置),而要配置MSI/MSIX中斷要使用的是pci_enable_msix。步驟二:request_irq為該設(shè)備的irq指定對(duì)應(yīng)的中斷處理例程,把irq號(hào)和驅(qū)動(dòng)定義ISR關(guān)聯(lián)。

pcibios_enable_device

該接口用于使能PCI設(shè)備INT#模式的中斷。其主要功能由pcibios_enable_irq(dev)完成,pcibios_enable_irq是一個(gè)函數(shù)指針,對(duì)于ACPI模式,其在上電過(guò)程中被設(shè)置為acpi_pci_irq_enable,其它情況被設(shè)置為pirq_enable_irq。

對(duì)ACPI模式,其執(zhí)行過(guò)程為:1、 acpi_pci_irq_enable:其先根據(jù)設(shè)備的管腳信息獲取一個(gè)GSI(可以認(rèn)為有了GSI,就有了irq號(hào),gsi_to_irq可以完成其轉(zhuǎn)換),有了gsi/irq,要完成設(shè)置還必須有vector并且把它們關(guān)聯(lián)起來(lái),因此如果GSI獲取成功,會(huì)使用acpi_register_gsi來(lái)完成后續(xù)操作。2、 acpi_register_gsi:其主要功能由__acpi_register_gsi來(lái)完成,該函數(shù)指針在ACPI模式下被設(shè)置為acpi_register_gsi_ioapic,acpi_register_gsi_ioapic的執(zhí)行過(guò)程如下:mp_register_gsi===>io_apic_set_pci_routing===>io_apic_set_pci_routing===>io_apic_setup_irq_pin_once===>io_apic_setup_irq_pin===>setup_ioapic_irq,在setup_ioapic_irq中,就會(huì)利用assign_irq_vector為該irq選擇對(duì)應(yīng)的執(zhí)行CPU,并分配該CPU上的vector,同時(shí)還把該vector等配置寫(xiě)入到I/O APIC對(duì)應(yīng)管腳的RTE,從而完成整個(gè)中斷的配置。這樣在該INT#信號(hào)到來(lái)的時(shí)候,I/O APIC就能根據(jù)對(duì)應(yīng)管腳的RTE,把該信號(hào)翻譯為一個(gè)vector,并通過(guò)中斷消息發(fā)送到local APIC。同時(shí)在setup_ioapic_irq中,還通過(guò)ioapic_register_intr===>irq_set_chip_and_handler_name為得到的irq號(hào)對(duì)應(yīng)的irq_desc設(shè)置了->irq_data.chip和handle_irq函數(shù)指針(對(duì)level觸發(fā)的,為handle_fasteoi_irq,否則為handle_edge_irq)

對(duì)其它模式,其通過(guò)pcibios_lookup_irq完成執(zhí)行:在配置了I/O APIC的場(chǎng)景,pirq_enable_irq通過(guò)IO_APIC_get_PCI_irq_vector獲取到irq號(hào),然后和ACPI模式一樣,通過(guò)io_apic_set_pci_routing完成對(duì)I/O APIC的配置。而對(duì)沒(méi)有配置I/O APIC的場(chǎng)景,主要通過(guò)pcibios_lookup_irq來(lái)完成相關(guān)操作:1、 pcibios_lookup_irq通過(guò)讀取BIOS提供的中斷路由表 ($PIR表,irq_routing_table)信息和當(dāng)前irq分配情況(pirq_penalty數(shù)組),在考慮均衡的前提下為當(dāng)前設(shè)備分配一個(gè)可用的irq。2、 根據(jù)當(dāng)前PIR的相關(guān)信息,決定最終的irq號(hào)選擇,相關(guān)代碼行如下

也就是:如果是硬鏈接(INT#直接連接到了8259A,沒(méi)有經(jīng)過(guò)PIR),直接獲取irq號(hào),如果PIR中已經(jīng)有該輸入線的配置,使用已有的值,否則利用剛剛分配的可用irq,并寫(xiě)入到PIR,以便能夠完成中斷信號(hào)到irq號(hào)的轉(zhuǎn)換。注意:1、這里的r,也就是pirq_router,代表一種PIR硬件,全局配置pirq_routers中描述了當(dāng)前支持的PIR,并在初始化的時(shí)候通過(guò)pirq_find_router獲取了對(duì)應(yīng)當(dāng)前配置的PIR對(duì)應(yīng)的描述。2、這里沒(méi)有分配vector,是因?yàn)檫@里使用的irq號(hào)范圍為0-16,是ISA IRQs,其與vector的對(duì)應(yīng)關(guān)系簡(jiǎn)單:vector = IRQ0_VECTOR + irq,并在系統(tǒng)初始化過(guò)程中,已經(jīng)通過(guò)early_irq_init中分配了irq_desc結(jié)構(gòu),通過(guò)init_IRQ設(shè)置了vector_irq(只運(yùn)行于CPU0上),然后通過(guò)x86_init.irqs.intr_init(native_init_IRQ)===> x86_init.irqs.pre_vector_init(init_ISA_irqs)設(shè)置了->irq_data.chip(i8259A_chip)和handle_irq函數(shù)指針(handle_level_irq)。

Pci_enable_msix

該函數(shù)完成MSIX中斷相關(guān)的設(shè)置。

msix_capability_init中實(shí)現(xiàn)中斷初始化的是arch_setup_msi_irqs,對(duì)于X86系統(tǒng),其為x86_setup_msi_irqs,x86_setup_msi_irqs中直接調(diào)用了native_setup_msi_irqs,該函數(shù)是X86系統(tǒng)中實(shí)現(xiàn)MSIX中斷初始化的關(guān)鍵函數(shù),對(duì)于沒(méi)有啟用interrupt remap的系統(tǒng),其實(shí)現(xiàn)如下:

該函數(shù)中有兩個(gè)關(guān)鍵函數(shù),分別是create_irq_nr和setup_msi_irq,其中create_irq_nr是分配一個(gè)vector給當(dāng)前的中斷,分配vector的同時(shí),也為該中斷指定了執(zhí)行CPU。setup_msi_irq則負(fù)責(zé)把相關(guān)配置信息寫(xiě)入到PCIE配置區(qū),并設(shè)置irq_desc的數(shù)據(jù),其中關(guān)鍵的是irq_desc的handle_irq被設(shè)置為handle_edge_irq。create_irq_nr的實(shí)現(xiàn)如下:

其中__assign_irq_vector負(fù)責(zé)分配vector,并和中斷在CPU上的調(diào)度相關(guān),其實(shí)現(xiàn)如下

從實(shí)現(xiàn)中可以看到,該函數(shù)從FIRST_EXTERNAL_VECTOR(外設(shè)中斷的起始vector號(hào),通常是0x20) 到first_system_vector(外部中斷結(jié)束vector號(hào),通常是254,255被系統(tǒng)作為保留的SPURIOUS_APIC_VECTOR使用)的范圍中,為當(dāng)前中斷分配一個(gè)vector,要求該vector在對(duì)應(yīng)的cpu上均可用,該vector按照系統(tǒng)配置的要求和對(duì)應(yīng)的cpu核心綁定,并在要求的cpu中沒(méi)有被其它中斷使用。需要說(shuō)明的是,在setup_msi_irq中會(huì)再次通過(guò)msi_compose_msg再次調(diào)用__assign_irq_vector,但是由于這時(shí)已經(jīng)存在滿足CPU綁定要求的vector,不會(huì)多次分配。

從以上分析可以得到MSI-X中斷的一個(gè)綁定特征:根據(jù)當(dāng)前APIC配置,每個(gè)中斷都有對(duì)應(yīng)的可以運(yùn)行的cpu,pci_enable_msix在這些要求的cpu核心上建立了vector (APIC的配置由數(shù)據(jù)結(jié)構(gòu)struct apic來(lái)抽象,其vector_allocation_domain用于決定需要在那些cpu核心上為該中斷建立vector),當(dāng)前我的系統(tǒng)使用的是apic_physflat,對(duì)每個(gè)MSI中斷,其只在一個(gè)cpu核心上建立vector,對(duì)應(yīng)的MSI-X中斷事實(shí)上被綁定到該cpu核心上。在用戶通過(guò)echo xxx > /proc/irq/xxx/affinity來(lái)調(diào)整中斷的綁定屬性時(shí),內(nèi)核會(huì)重新為該中斷分配一個(gè)新的在對(duì)應(yīng)核心上可用的vector,但是irq號(hào)不會(huì)改變。綁定屬性調(diào)整的調(diào)用路徑大致為irq_affinity_proc_fops===>irq_affinity_proc_write===> write_irq_affinity===>irq_set_affinity===>__irq_set_affinity_locked===>chip->irq_set_affinity(msi_set_affinity)。也就是最終通過(guò)msi_set_affinity來(lái)實(shí)現(xiàn),在該函數(shù)中首先通過(guò) __ioapic_set_affinity在綁定屬性要求的cpu中選擇空閑vector,然后通過(guò)__write_msi_msg把配置寫(xiě)入PCIE配置區(qū)。需要說(shuō)明的是:該irq最終可以運(yùn)行的cpu數(shù)量并不完全由用戶指定,還與apic的模式相關(guān),對(duì)于apic_physflat,實(shí)際上只為該irq分配了一個(gè)cpu核心,該irq只能運(yùn)行在用戶指定的cpu中的一個(gè),而不是全部。

附:關(guān)于全局變量apic

該全局變量為local apic的抽象,在不同的系統(tǒng)配置下,有不同的選擇,其最終的選擇結(jié)果,由內(nèi)核的config(反應(yīng)在/arch/x86/kernel/apic/Makefile)和硬件配置等來(lái)決定。1、 定義各種apic driver首先,每種apic配置都會(huì)使用apic_driver/ apic_drivers來(lái)定義,apic_driver的定義如下

這個(gè)定義的目的是把sym的地址寫(xiě)入到名為” .apicdrivers”的段中。2、 定義全局符號(hào)__apicdrivers和__apicdrivers_end在linker script vmlinux.lds.S中,定義了__apicdrivers為” .apicdrivers”段的開(kāi)始地址,而__apicdrivers_end為結(jié)束地址?!?.apicdrivers”段中是各個(gè)不同的apic配置對(duì)應(yīng)的struct apic。

3、 apic的probe在初始化過(guò)程(start_kernel)中,會(huì)調(diào)用default_setup_apic_routing(probe_64.c中定義)來(lái)完成apic的probe,該函數(shù)會(huì)按照各個(gè)struct apic結(jié)構(gòu)在.apicdrivers中的順序,依次調(diào)用其probe接口,第一個(gè)調(diào)用返回非0的struct apic結(jié)構(gòu)就被初始化到全局變量apic。也就是:如果有多個(gè)apic結(jié)構(gòu)可用,最終會(huì)選擇在.apicdrivers段中出現(xiàn)的第一個(gè);所以makefile文件中各個(gè).o出現(xiàn)的順序也會(huì)覺(jué)得最終的apic probe結(jié)果。

request_irq

該函數(shù)把irq和用戶指定的中斷處理函數(shù)關(guān)聯(lián)。用戶指定的每個(gè)處理函數(shù)對(duì)應(yīng)于一個(gè)struct irqaction結(jié)構(gòu),這些處理函數(shù)構(gòu)成一個(gè)鏈表,保存在struct irq_desc::action成員中。詳細(xì)見(jiàn)request_irq===>request_threaded_irq中的處理。

中斷的執(zhí)行

在內(nèi)核代碼中,對(duì)X86平臺(tái)中斷執(zhí)行的基本過(guò)程是:1、 通過(guò)IDT中的中斷描述符,調(diào)用common_interrupt;2、 通過(guò)common_interrupt,調(diào)用do_IRQ,完成vector到irq_desc的轉(zhuǎn)換,進(jìn)入Generic interrupt layer(調(diào)用處理函數(shù)generic_handle_irq_desc);3、 調(diào)用在中斷初始化的時(shí)候,按照中斷特性(level觸發(fā),edge觸發(fā)等、simple等)初始化的irq_desc:: handle_irq,執(zhí)行不同的通用處理接口,比如handle_simple_irq;4、 這些通用處理接口會(huì)調(diào)用中斷初始化的時(shí)候注冊(cè)的外部中斷處理函數(shù);完成EOI等硬件相關(guān)操作;并完成中斷處理的相關(guān)控制。

common_interrupt

按照之前CPU執(zhí)行中斷過(guò)程的描述,X86 CPU在準(zhǔn)備好了中斷執(zhí)行環(huán)境后,會(huì)調(diào)用中斷描述符定義的中斷處理入口;根據(jù)中斷相關(guān)初始化過(guò)程我們知道,對(duì)于用戶自定義中斷,中斷處理入口都是(對(duì)系統(tǒng)預(yù)留的,就直接執(zhí)行定義的接口了):

就是在把vector入棧后,執(zhí)行common_interrupt,common_interrupt在entry_64.S中定義,其中關(guān)鍵步驟為:調(diào)用do_IRQ,完成后會(huì)根據(jù)環(huán)境判斷是否需要執(zhí)行調(diào)度,最后執(zhí)行iretq指令完成中斷處理,iret指令的重要功能就是回復(fù)中斷函數(shù)前的EFLAGS(執(zhí)行中斷入口前被入棧保存,并清零IF位關(guān)中斷),并恢復(fù)執(zhí)行被中斷的程序(這里不一定會(huì)恢復(fù)到之前的執(zhí)行環(huán)境,可能執(zhí)行軟中斷處理,或者執(zhí)行調(diào)度)。

do_IRQ

do_IRQ的基本處理過(guò)程如下,其負(fù)責(zé)中斷執(zhí)行環(huán)境建立、vector到irq的轉(zhuǎn)換等

Generic interrupt layer

該層負(fù)責(zé)的是平臺(tái)無(wú)關(guān)/設(shè)備無(wú)關(guān)的中斷通用邏輯,對(duì)這部分,在《Linux generic IRQ handling》中有詳細(xì)描述。其負(fù)責(zé)完成中斷處理的接口是generic_handle_irq_desc,該接口會(huì)執(zhí)行irq_desc::handle_irq; Generic interrupt layer根據(jù)中斷特性的不同,把中斷分成幾類,包括:level type(handle_level_irq)、edge type(handle_edge_irq)、simple type(handle_simple_irq)等,這些中斷類型對(duì)應(yīng)的處理函數(shù)是都在kernel/irq/chip.c中定義,并入前面的描述,在相關(guān)中斷初始化的時(shí)候,被賦值給irq_desc::handle_irq;對(duì)于PCI設(shè)備,只用了兩種,level type(INT#模式)、edge type(MSI/MSI-X模式)。

edge 觸發(fā)中斷的基本處理過(guò)程:

電壓跳變觸發(fā)中斷===>中斷控制器接收中斷,記IRR寄存器===>中斷控制器置ISR寄存器===>CPU屏蔽本CPU中斷===>CPU處理中斷,發(fā)出EOI===>中斷控制器確認(rèn)可以處理下一次中斷===>ISR清中斷源,電壓歸位===>中斷源可以發(fā)起下一次中斷===>CPU中斷處理完成,執(zhí)行完現(xiàn)場(chǎng)處理后執(zhí)行IRET,不再屏蔽本CPU中斷。edge觸發(fā)的特點(diǎn):a) 中斷不會(huì)丟如果中斷觸發(fā)時(shí)中斷被屏蔽,那么中斷控制器會(huì)記錄下該中斷,在屏蔽取消的時(shí)候會(huì)再執(zhí)行。b) edge觸發(fā)的缺點(diǎn)是完成共享不方便:比如A和B兩個(gè)中斷源共享一個(gè)中斷,每次ISR先檢查A再檢查B,如果B先發(fā)生中斷,在ISR檢查完A,檢查B的過(guò)程中,A發(fā)生中斷。那么在ISR處理開(kāi)始的時(shí)候,A會(huì)告訴ISR,不是它干的,然后ISR處理B的中斷,完成后通過(guò)清理中斷源把B的電壓歸位,但是由于A的中斷沒(méi)有得到處理,電壓沒(méi)有歸位,這個(gè)共享的中斷就不能得到再次觸發(fā)了。edge觸發(fā)對(duì)應(yīng)的通用邏輯接口

level 觸發(fā):

這種模式下,外設(shè)通過(guò)把電壓保持到某個(gè)門(mén)限值來(lái)完成觸發(fā)中斷,在處理完成(EOI)后,如果電壓還在門(mén)限值,就會(huì)再次觸發(fā)中斷的執(zhí)行。level觸發(fā)的特點(diǎn):a) 方便中斷共享b) 對(duì)中斷觸發(fā)時(shí)中斷被屏蔽的情況,如果中斷屏蔽解除后仍然引腳電壓仍然在門(mén)限值,就執(zhí)行該中斷的ISR,否則不執(zhí)行。需要說(shuō)明的是:對(duì)于使用local APIC的系統(tǒng),level觸發(fā)和edge觸發(fā)需要配置local APIC的Local Vector Table。4、 level觸發(fā)對(duì)應(yīng)的通用邏輯接口

level觸發(fā)和edge觸發(fā)在通用邏輯層最大的不同就是當(dāng)其他CPU正在處理該中斷的時(shí)候,系統(tǒng)的行為,對(duì)edge觸發(fā),會(huì)把該中斷記錄下來(lái),當(dāng)前處理結(jié)束后再次執(zhí)行,而level直接退出。產(chǎn)生這種差異的原因是:level觸發(fā)不怕丟?

無(wú)論是那種觸發(fā)方式,都會(huì)調(diào)用handle_irq_event處理中斷,該函數(shù)中會(huì)遍歷irq_desc::action鏈表,執(zhí)行action->handler,也就是驅(qū)動(dòng)在中斷初始化的時(shí)候,通過(guò)request_irq注冊(cè)的中斷處理接口。

總結(jié)

中斷的使能狀態(tài)

1、 在local APIC層次(當(dāng)前CPU),一個(gè)中斷正在處理的時(shí)候,不會(huì)有相同的中斷或者優(yōu)先級(jí)低于該中斷的其它中斷來(lái)打斷當(dāng)前中斷的執(zhí)行;但是高優(yōu)先級(jí)中斷可以打斷低優(yōu)先級(jí)中斷。2、 在X86 CPU層次(當(dāng)前CPU),從中斷執(zhí)行開(kāi)始到IRET,IF位都被清零,也就是只有不可屏蔽中斷能夠打斷當(dāng)前中斷的執(zhí)行。3、 在Generic interrupt layer層次,如果一個(gè)中斷已經(jīng)在系統(tǒng)中執(zhí)行,會(huì)阻止該中斷在其它CPU上的執(zhí)行。4、 在外設(shè)/驅(qū)動(dòng)中斷處理函數(shù)層次往往也有中斷使能的功能,比如啟用了NAPI的網(wǎng)卡,在中斷處理函數(shù)開(kāi)始執(zhí)行的時(shí)候,往往會(huì)通過(guò)硬件功能關(guān)閉該中斷,要在對(duì)應(yīng)的軟中斷完成處理后才通過(guò)硬件功能使能該中斷。注:NMI中斷雖然稱為不可屏蔽中斷,也有一個(gè)例外:NMI中斷執(zhí)行過(guò)程中,該CPU屏蔽了后來(lái)的NMI中斷。

中斷的執(zhí)行CPU

通過(guò)中斷初始化過(guò)程我們知道:中斷在那個(gè)CPU上執(zhí)行,取決于在那個(gè)CPU上申請(qǐng)了vector并配置了對(duì)應(yīng)的中斷控制器(比如local APIC)。如果想要改變一個(gè)中斷的執(zhí)行CPU,必須重新申請(qǐng)vector并配置中斷控制器。一般通過(guò)echo xxx > /proc/irq/xxx/affinity來(lái)完成調(diào)整,同時(shí)irq_balance一類軟件可以用于完成中斷的均衡。

(完)

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11076

    瀏覽量

    217010
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11509

    瀏覽量

    213724
  • 初始化
    +關(guān)注

    關(guān)注

    0

    文章

    50

    瀏覽量

    12106

原文標(biāo)題:Linux中斷機(jī)制:硬件處理,初始化和中斷處理

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    RISC-V的中斷處理 中斷操作三個(gè)步驟

    中斷操作三個(gè)步驟: 1、中斷初始化 2、trap處理 3、用戶中斷
    的頭像 發(fā)表于 05-20 16:38 ?1934次閱讀

    端口初始化初始化中斷

    ,50MHz3.PA10浮空輸入2、初始化外設(shè)1.開(kāi)外設(shè)時(shí)鐘USART12.配置外設(shè)寄存器波特率:115200傳輸位數(shù):8位停止位數(shù):1位校驗(yàn)位:無(wú)校驗(yàn)發(fā)送接收使能硬件流控制失能3、初始化中斷
    發(fā)表于 08-16 06:54

    Linux 2.6 中斷處理原理簡(jiǎn)介

    Linux 2.6 中斷處理原理簡(jiǎn)介 中斷描述符表(Interrupt Descriptor Table,IDT)是
    發(fā)表于 02-05 10:52 ?838次閱讀

    linux驅(qū)動(dòng)之中斷處理過(guò)程C程序部分

    linux內(nèi)核將所有的中斷統(tǒng)編號(hào),使用個(gè)irq_desc[NR_IRQS]的結(jié)構(gòu)體數(shù)組來(lái)描述這些中斷
    發(fā)表于 05-07 11:13 ?1195次閱讀

    Linux驅(qū)動(dòng)技術(shù)之內(nèi)核中斷

    硬件上,中斷源可以通過(guò)中斷控制器向CPU提交中斷,進(jìn)而引發(fā)中斷處理程序的執(zhí)行,不過(guò)這種
    發(fā)表于 05-08 13:49 ?755次閱讀

    linux中斷處理之IRQ中斷

    在前個(gè)專題里曾分析過(guò)所有IRQ中斷處理流程,經(jīng)過(guò)SAVE_ALL保存硬件環(huán)境后,都會(huì)進(jìn)入do_IRQ()進(jìn)行
    發(fā)表于 05-10 10:57 ?2910次閱讀

    HAL庫(kù)中斷處理以及相關(guān)的回調(diào)函數(shù)

    驅(qū)動(dòng)的開(kāi)發(fā)時(shí)間,把重心放在應(yīng)用代碼上。 ? 但是,STM32CubeMX只是生成了底層驅(qū)動(dòng)的初始化代碼。所以,我們還需要掌握:應(yīng)用層代碼如何調(diào)用HAL庫(kù)函數(shù)(API接口),以及HAL庫(kù)中斷處理機(jī)制等相關(guān)知識(shí)。? HAL庫(kù)牽涉的內(nèi)
    的頭像 發(fā)表于 01-07 11:46 ?9932次閱讀
    HAL庫(kù)<b class='flag-5'>中斷</b><b class='flag-5'>處理</b>以及相關(guān)的回調(diào)函數(shù)

    51單片機(jī)之中斷系統(tǒng)

    事件A被中斷的地方繼續(xù)處理事件A(中斷返回),這過(guò)程稱為中斷 ?! ?# 外部中斷0外部
    發(fā)表于 11-20 17:06 ?24次下載
    51單片機(jī)之<b class='flag-5'>中斷</b>系統(tǒng)

    51單片機(jī)之中斷系統(tǒng)

    事件A被中斷的地方繼續(xù)處理事件A(中斷返回),這過(guò)程稱為中斷 ?! ?# 外部中斷0外部
    發(fā)表于 11-22 13:36 ?7次下載
    51單片機(jī)之<b class='flag-5'>中斷</b>系統(tǒng)

    CC2530中斷初始化中斷函數(shù)

    相關(guān)寄存器在cc2530中文數(shù)手冊(cè)中2.4小節(jié)中斷初始化其實(shí)中斷初始化可以參照引腳的初始化,即4個(gè)
    發(fā)表于 11-29 19:06 ?9次下載
    CC2530<b class='flag-5'>中斷</b><b class='flag-5'>初始化</b>和<b class='flag-5'>中斷</b>函數(shù)

    學(xué)4412arm基礎(chǔ)之中斷總結(jié)

    中斷4412中斷的核心圖(面試般會(huì)問(wèn))中斷過(guò)程中斷初始化a. 管腳初始化b.
    發(fā)表于 12-04 16:06 ?8次下載
    學(xué)4412arm基礎(chǔ)之<b class='flag-5'>中斷</b>總結(jié)

    STM32 HAL庫(kù)初始化MPU6050低功耗 中斷喚醒

    @[TOC]STM32初始化MPU6050低功耗 中斷喚醒STM32初始化MPU6050低功耗 中斷喚醒代碼如下: 已親自測(cè)試(2021.2.4) (以下代碼 采樣率是20Hz)低功耗
    發(fā)表于 12-06 13:36 ?20次下載
    STM32 HAL庫(kù)<b class='flag-5'>初始化</b>MPU6050低功耗 <b class='flag-5'>中斷</b>喚醒

    STM32執(zhí)行代碼初始化卡住,或者上電卡住,或者復(fù)位卡住,導(dǎo)致代碼不執(zhí)行

    ,放在其他硬件初始化之后 卡住原因:中斷初始化之后,產(chǎn)生了中斷,而其他
    發(fā)表于 12-09 09:21 ?22次下載
    STM32執(zhí)行代碼<b class='flag-5'>初始化</b>卡住,或者上電卡住,或者復(fù)位卡住,導(dǎo)致代碼不執(zhí)行

    實(shí)際中斷處理

    中斷處理處理外界發(fā)出的信號(hào)。中斷信號(hào)可能是關(guān)于數(shù)據(jù)讀寫(xiě)操作的,也可能與外部設(shè)備控制有關(guān)。Intel處理
    發(fā)表于 12-17 18:44 ?7次下載
    實(shí)際<b class='flag-5'>中斷</b><b class='flag-5'>處理</b>

    Linux中斷處理淺析

    去繼續(xù)運(yùn)行被暫時(shí)中斷的程序。Linux中通常分為外部中斷(又叫硬件中斷)和內(nèi)部中斷(又叫異常)。
    的頭像 發(fā)表于 11-09 16:46 ?1054次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>中斷</b><b class='flag-5'>處理</b>淺析