




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第四章中斷和異常第一頁,共四十二頁,2022年,8月28日4.1中斷信號的作用4.2中斷和異常4.3中斷和異常處理程序的嵌套執(zhí)行4.4初始化中斷描述符表4.5異常處理4.6中斷處理4.7軟中斷及tasklet4,8工作隊列4.9從中斷和異常返回第二頁,共四十二頁,2022年,8月28日中斷:中斷是一個能改變處理器執(zhí)行順序的事件。中斷通常分為同步中斷和異步中斷。同步中斷:當(dāng)指令執(zhí)行時由CPU控制單元產(chǎn)生的,只有在一條指令終止執(zhí)行后CPU才會發(fā)出中斷。異步中斷:由其他硬件設(shè)備依照CPU時鐘信號隨機產(chǎn)生的。
在Intel微處理器手冊中,把同步和異步中斷分別稱為異常和中斷。中斷是由間隔定時器和I/O設(shè)備產(chǎn)生的,而異常是由程序的錯誤產(chǎn)生的,或者是由內(nèi)核必須處理的異常條件產(chǎn)生的。第三頁,共四十二頁,2022年,8月28日
中斷信號的作用是提供一種特殊的方式使處理器轉(zhuǎn)而去運行正常控制流之外的代碼。當(dāng)一個中斷信號到達時,CPU必須停止它當(dāng)前正在做的事情,并且切換到一個新的活動。
為了做到這一點,就要在內(nèi)核態(tài)堆棧保存程序計數(shù)器的當(dāng)前值(即eip和cs寄存器的內(nèi)容),并把與中斷類型相關(guān)的一個地址放進程序計數(shù)器。中斷處理與進程切換的區(qū)別:
由中斷或異常處理程序執(zhí)行的代碼不是一個進程。中斷處理程序比一個進程要“l(fā)ight”(中斷的上下文很少,建立或終止中斷處理需要的時間很少)。第四頁,共四十二頁,2022年,8月28日中斷:1)可屏蔽中斷 I/O設(shè)備發(fā)出的所有中斷請求(IRQ)都產(chǎn)生可屏蔽中斷,可屏蔽中斷可以處于兩種狀態(tài):屏蔽的或非屏蔽的,一個屏蔽的中斷只要還是屏蔽的,控制單元就忽略它。2)非屏蔽中斷
只有幾個危急事件(如硬件故障)才引起非屏蔽中斷。非屏蔽中斷總是由CPU辨認。異常:1)處理器探測異常
當(dāng)CPU執(zhí)行指令時探測到的一個反常條件所產(chǎn)生的異常??梢苑譃?組:包括故障,陷阱和異常終止。這取決于CPU控制單元產(chǎn)生異常時候保存在內(nèi)核態(tài)堆棧eip寄存器中的值。2)編程異常
在編程者發(fā)出請求時發(fā)生。是由int或int3指令觸發(fā)的;當(dāng)into(檢查溢出)和bound(檢查地址出界)指令檢查的條件不為真時,也引起編程異常??刂茊卧丫幊坍惓W鳛橄葳鍋硖幚?,編程異常通常也叫做軟中斷。編程異常有兩種用途:執(zhí)行系統(tǒng)調(diào)用和給調(diào)試程序通報一個特定的事件。第五頁,共四十二頁,2022年,8月28日每個能夠發(fā)出中斷請求的硬件設(shè)備控制器都有一條IRQ輸出線,所有現(xiàn)有的IRQ線都與一個可編程中斷控制器的輸入引腳相連,可編程控制器執(zhí)行以下動作:1.監(jiān)視IRQ線,檢查產(chǎn)生的信號。如果有兩條或兩條以上的IRQ線上產(chǎn)生信號,就選擇引腳編號較小的IRQ線。2.如果一個引發(fā)信號出現(xiàn)在IRQ線上: a)把接收到的引發(fā)信號轉(zhuǎn)換成對應(yīng)的向量。 b)把這個向量存放在中斷控制器的一個I/O端口,從而允許CPU通過數(shù) 據(jù)總線讀此向量。 c)把引發(fā)信號發(fā)送到處理器的INTR引腳,即產(chǎn)生一個中斷。 d)等待,直到CPU通過把這個中斷信號寫進可編程中斷控制器的一個 I/O端口來確認它,當(dāng)這種情況發(fā)生時,清INTR線。3.返回到第一步。IRQ線是從0開始編號的,第一條IRQ線通常表示成IRQ0,與IRQn關(guān)聯(lián)的Intel的缺省向量是n+32??梢杂羞x擇的禁止每條IRQ線,可以對PCI編程從而禁止IRQ。而有選擇的激活/禁止IRQ線不同于可屏蔽中斷的全局屏蔽/非屏蔽,當(dāng)eflags寄存器的IF標(biāo)志被清0時,由PIC發(fā)布的每個可屏蔽中斷都由CPU暫時忽略,cli和sti匯編指令分別清除和設(shè)置該標(biāo)志。第六頁,共四十二頁,2022年,8月28日目的:為了充分發(fā)揮多處理器體系結(jié)構(gòu)的并行性,能夠把中斷傳遞給系統(tǒng)中的每個CPU。結(jié)構(gòu):每個CPU都含有一個本地APIC,每個本地APIC都有32位的寄存器,一個內(nèi)部時鐘,一個本地定時設(shè)備以及為本地APIC中斷保留的兩條額外的IRQ線LINT0和LINT1。所有本地APIC都連接到一個外部I/OAPIC,形成一個多APIC的系統(tǒng)。I/OAPIC的組成:一組24條IRQ線,一張24項的中斷重定向表,可編程寄存器,以及通過APIC總線發(fā)送和接收APIC信息的一個信息單元。中斷重定向表中的信息用于把每個外部IRQ信號轉(zhuǎn)換為一條消息,然后通過APIC總線把消息發(fā)送給一個或多個本地APIC單元。來自外部硬件設(shè)備的中斷請求以下面兩種方式在可用CPU之間分發(fā):1)靜態(tài)分發(fā) IRQ信號傳遞給重定向表相應(yīng)項中所列出的本地APIC。2)動態(tài)分發(fā)
如果處理器正在執(zhí)行最低優(yōu)先級進程,IRQ信號就傳遞給這種處理器的本地APIC。
如果兩個或多個CPU共享最低優(yōu)先級,就利用仲裁技術(shù)分配CPU。第七頁,共四十二頁,2022年,8月28日仲裁技術(shù):
在本地APIC的仲裁優(yōu)先級寄存器中,給每一個CPU都分配一個0(最低)~15(最高)范圍內(nèi)的值。
每當(dāng)中斷傳遞給一個CPU時,其相應(yīng)的仲裁優(yōu)先級就自動置為0,而其他每個CPU的仲裁優(yōu)先級都增加1,當(dāng)仲裁優(yōu)先級寄存器大于15時,就把它置為獲勝CPU的前一個仲裁優(yōu)先級加1。因此,中斷以輪轉(zhuǎn)的方式在CPU之間分發(fā),且具有相同的任務(wù)優(yōu)先級。處理器間中斷(IPI):
除了在處理器之間分發(fā)中斷外,多APIC系統(tǒng)還允許CPU產(chǎn)生處理器間中斷。當(dāng)一個CPU希望把中斷發(fā)送給另一個CPU時,它就在自己本地APIC的中斷指令寄存器(ICR)中存放這個中斷向量和目標(biāo)本地APIC的標(biāo)識符。然后,通過APIC總線向目標(biāo)本地APIC發(fā)送一條消息,從而向自己的CPU發(fā)出一條相應(yīng)的中斷。 IPI被linux用來在CPU之間交換信息。第八頁,共四十二頁,2022年,8月28日80x86處理器發(fā)布了大約20種異常,內(nèi)核必須為每種異常提供一個專門的異常處理程序,對于某些異常,CPU控制單元在開始執(zhí)行異常處理前會產(chǎn)生一個硬件出錯碼,并且壓入內(nèi)核態(tài)堆棧。0Divideerror(故障)當(dāng)一個程序試圖執(zhí)行整數(shù)被0除操作時產(chǎn)生1Debug(陷阱或故障)產(chǎn)生于設(shè)置eflags的TF標(biāo)志或一條指令或操作數(shù)的地址落在一個活動debug寄存器的范圍之內(nèi)時。未用
為非屏蔽中斷保留Breakpoint(陷阱)由int3(斷點)指令引起Overflow(陷阱)當(dāng)eflags的OF標(biāo)志被設(shè)置時,into指令被執(zhí)行。Boundscheck(故障)
對于有效地址范圍之外的操作數(shù),bound指令被執(zhí)行。Invalidopcode(故障)CPU執(zhí)行單元檢測到一個無效操作碼。Devicenotavailable(故障)隨著cr0的TS標(biāo)志被設(shè)置,ESCAPE、MMX或XMM指令被執(zhí)行。Doublefault(異常中止)正常情況下當(dāng)CPU正試圖為前一個異常調(diào)用處理程序時,同時又檢測到一個異常,兩個異常能被串行的處理,然而在少數(shù)情況下,處理器不能串行的處理它們,因而產(chǎn)生這種異常。Coprocessorsegmentoverrun(異常中止)因外部的數(shù)學(xué)協(xié)處理器引起的問題。InvalidTSS(故障)CPU試圖讓一個上下文切換到有無效TSS的進程。第九頁,共四十二頁,2022年,8月28日Segmentnotpresent(故障)引用一個不存在的內(nèi)存段。Stacksegmentfault(故障)試圖超過棧段界限的指令,或者ss標(biāo)識的段不在內(nèi)存。Generalprotection(故障)違反了80x86保護模式下的保護規(guī)則之一。Pagefault(故障)尋址的頁不在內(nèi)存,相應(yīng)的頁表項為空,或者違反了一種分頁保護機制。由Intel保留。Floatingpointerror(故障)集成到CPU芯片中的浮點單元用信號通知一個錯誤情形,如數(shù)字溢出或被0除。Alignmentcheck(故障)操作數(shù)的地址沒有被正確的對齊Machinecheck(異常中止)機器檢查機制檢測到一個CPU錯誤或總線錯誤。SIMDfloatingpointexception(故障)集成到CPU芯片中的SSE或SSE2單元對浮點操作用信號通知一個錯誤情形。20~31這些值由Intel留作將來開發(fā)。第十頁,共四十二頁,2022年,8月28日中斷描述符表是一個系統(tǒng)表,它與每一個中斷或異常向量相聯(lián)系,每一個向量在表中有相應(yīng)的中斷或異常處理程序的入口地址,內(nèi)核在允許中斷發(fā)生前,必須用lidt匯編指令初始化IDT。idtrCPU寄存器指定了IDT的線性基地址及其限制(最大長度),因此IDT可以位于內(nèi)存的任何地方。IDT包含三種類型的描述符:1)任務(wù)門:
當(dāng)中斷信號發(fā)生時,必須取代當(dāng)前進程的那個進程的TSS選擇符存放在
任務(wù)門中。2)中斷門:
包含段選擇符和中斷或異常處理程序的段內(nèi)偏移量。當(dāng)控制權(quán)轉(zhuǎn)移到一
個適當(dāng)?shù)亩螘r,處理器清IF標(biāo)志,從而關(guān)閉將來會發(fā)生的可屏蔽中斷。3)陷阱門:
與中斷門相似,只是控制權(quán)傳遞到一個適當(dāng)?shù)亩螘r處理器不修改IF標(biāo)志。第十一頁,共四十二頁,2022年,8月28日當(dāng)執(zhí)行了一條指令后,cs和eip寄存器包含下一條將要執(zhí)行指令的邏輯地址,在處理那條指令之前,控制單元會檢查在運行前一條指令時是否已經(jīng)發(fā)生了一個中斷或異常,如果發(fā)生了一個中斷或異常,控制單元執(zhí)行以下操作:確定與中斷或異常關(guān)聯(lián)的向量i(0<=i<=255).讀由idtr寄存器指向的IDT表中的第i項。從gdtr寄存器獲得GDT的基地址,并在GDT中查找,以讀取IDT表項中的選擇符所標(biāo)識的段描述符,這個描述符指定中斷或異常處理程序所在段的基地址。確信中斷是由授權(quán)的中斷發(fā)生源發(fā)出的。首先將當(dāng)前特權(quán)級CPL與段描述符的描述符特權(quán)級DPL比較,如果CPL小于DPL,就產(chǎn)生一個“Generalprotection”異常,因為中斷處理程序的特權(quán)不能低于引起中斷的程序的特權(quán)。對于編程異常則做進一步的安全檢查:比較CPL與處于IDT中的門描述符的DPL,如果DPL小于CPL就產(chǎn)生一個“Generalprotection”異常。這最后一個檢查可以避免用戶應(yīng)用程序訪問特殊的陷阱門或中斷門。檢查是否發(fā)生了特權(quán)級的變化,也就是說,CPL是否不同于所選擇的段描述符的DPL,如果是,控制單元必須開始使用與新的特權(quán)級相關(guān)的棧。如果故障已經(jīng)發(fā)生,用引起異常的指令地址裝載cs和eip寄存器,從而使得這條指令能再次被執(zhí)行。第十二頁,共四十二頁,2022年,8月28日在棧中保存eflags、cs及eip的內(nèi)容。如果異常產(chǎn)生了一個硬件出錯碼,則將它保存在棧中。裝載cs和eip寄存器,其值分別是IDT表中第i項門描述符的段選擇符和偏移量字段。這些值給出了中斷或者異常處理程序的第一條指令的邏輯地址。
控制單元所執(zhí)行的最后一步就是跳轉(zhuǎn)到中斷或異常的處理程序,即被選中處理程序的第一條指令。
中斷或異常處理完后,相應(yīng)的處理程序必須產(chǎn)生一條iret指令,把控制權(quán)交給被中斷的進程,這時控制單元執(zhí)行以下操作:用保存在棧中的值裝載cs、eip或eflags寄存器。如果一個硬件出錯碼曾被壓入棧中,并且在eip內(nèi)容的上面,那么執(zhí)行iret指令前必須先彈出這個硬件出錯碼。檢查處理程序的CPL是否等于cs中最低兩位的值(這意味著被中斷的進程與處理程序運行在同一特權(quán)級),如果是,iret終止執(zhí)行,否則轉(zhuǎn)入下一步。從棧中裝載ss和esp寄存器,因此返回到與舊特權(quán)級相關(guān)的棧。檢查ds、es、fs及gs段寄存器的內(nèi)容,如果其中一個寄存器包含的選擇符是一個段描述符,并且其DPL小于CPL,那么清相應(yīng)的段寄存器。這是為了禁止用戶態(tài)的程序(CPL=3)利用內(nèi)核以前所用的段寄存器(DPL=0),如果不清這些寄存器,懷有惡意的用戶態(tài)程序就可能利用它們來訪問內(nèi)核地址空間。第十三頁,共四十二頁,2022年,8月28日
每個中斷或異常都會引起一個內(nèi)核控制路徑,或者說代表當(dāng)前進程在內(nèi)核態(tài)執(zhí)行單獨的指令序列。內(nèi)核控制路徑可以任意嵌套,一個中斷程序可以被另一個中斷程序“中斷”,因此引起內(nèi)核控制路徑的嵌套執(zhí)行。其結(jié)果是:對中斷進行處理的內(nèi)核控制路徑的最后一部分指令并不總能使當(dāng)前進程返回到用戶態(tài):如果嵌套深度大于1,這些指令將執(zhí)行上次被打斷的內(nèi)核控制路徑,此時的CPU依然運行在內(nèi)核態(tài)。允許內(nèi)核控制路徑嵌套執(zhí)行必須要求中斷處理程序永不阻塞,即中斷處理程序運行期間不能發(fā)生進程切換。在內(nèi)核沒有bug的情況下,大多數(shù)異常在在CPU處于用戶態(tài)時發(fā)生。異常要么是由編程錯誤引起,要么是由調(diào)試程序觸發(fā),但是缺頁異常發(fā)生在內(nèi)核態(tài)。一個中斷處理程序既可以搶占其他的中斷處理程序,也可以搶占異常處理程序,相反,異常處理程序從不搶占中斷處理程序。在內(nèi)核態(tài)能觸發(fā)的唯一異常就是缺頁異常,但中斷處理程序從不執(zhí)行可以導(dǎo)致缺頁的操作。在多處理器系統(tǒng)上,幾個內(nèi)核控制路徑可以并發(fā)的執(zhí)行,此外與異常相關(guān)的內(nèi)核控制路徑可以開始在一個CPU上執(zhí)行,并且由于進程切換而移往另一個CPU上執(zhí)行。第十四頁,共四十二頁,2022年,8月28日4.4初始化中斷描述符表內(nèi)核啟用中斷以前,必須把IDT表的初始地址裝到idtr寄存器,并初始化表中的每一項。這項工作是在初始化系統(tǒng)的時候完成的。Linux中中斷描述符表分類如下:中斷門:用戶態(tài)進程不能訪問的一個Intel中斷門,門的DPL字段為0,所有的Linux中斷處理程序都通過中斷門激活,并全部限制在內(nèi)核態(tài)。系統(tǒng)門:用戶態(tài)進程可以訪問的一個Intel陷阱門,門的DPL字段為3,通過系統(tǒng)門來激活三個Linux異常處理程序,它們的向量是4,5及128,因此在用戶態(tài)下可以發(fā)布into、bound和int$0x80三條匯編語言指令。系統(tǒng)中斷門:能夠被用戶態(tài)進程訪問的Intel中斷門,DPL字段為3,與向量3相關(guān)的異常處理程序是由系統(tǒng)中斷門激活的,因此在用戶態(tài)可以使用匯編語言指令int3.陷阱門:用戶態(tài)的進程不能訪問的一個Intel陷阱門,DPL字段為0,大部分Linux異常處理程序都通過陷阱門來激活。任務(wù)門:不能被用戶態(tài)進程訪問的一個Intel任務(wù)門,DPL字段為0,Linux對“doublefault”異常的處理程序是由任務(wù)門激活的。第十五頁,共四十二頁,2022年,8月28日IDT的初步初始化當(dāng)計算機還運行在實模式時,IDT被初始化并由BIOS例程使用,一旦Linux接管,IDT就被移到RAM的另一個區(qū)域,并進行第二次初始化,因為Linux沒有利用任何BIOS例程。
IDT存放在idt_table表中,有256個表項,6字節(jié)的idt_descr變量指定了IDT的大小和它的地址。在內(nèi)核初始化過程中,setup_idt()匯編語言函數(shù)用同一個中斷門(即指向ignore_int()中斷處理程序)來填充所有這256個idt_table表項。Ignore_int()中斷處理程序執(zhí)行以下操作:在棧中保存一些寄存器的內(nèi)容。調(diào)用printk()函數(shù)打印“Unknowninterrupt”系統(tǒng)消息。從?;謴?fù)寄存器的內(nèi)容。執(zhí)行iret指令以恢復(fù)被中斷的程序。 緊接著這個預(yù)初始化,內(nèi)核將在IDT中進行第二遍初始化,用有意義的陷阱和中斷處理程序替換這個空處理程序。第十六頁,共四十二頁,2022年,8月28日4.5異常處理異常處理程序的標(biāo)準(zhǔn)結(jié)構(gòu),由三部分組成:在內(nèi)核堆棧中保存大多數(shù)寄存器的內(nèi)容(匯編語言實現(xiàn))。用高級的C函數(shù)處理異常。通過ret_from_exception()函數(shù)從異常處理程序退出。第十七頁,共四十二頁,2022年,8月28日為異常處理程序保存寄存器的值用handler_name表示一個通用的異常處理程序的名字,則每一個異常處理程序都以下面的匯編指令開始:handler_name: pushl$0/*onlyforsomeexceptions*/ pushl$do_handler_name jmperror_code其中error_code匯編語言代碼執(zhí)行以下步驟:把高級C函數(shù)可能用到的寄存器保存在棧中。產(chǎn)生一條cld指令來清eflags的方向標(biāo)志DF,以確保調(diào)用字符串指令時會自動增加edi和esi寄存器的值。把棧中位于esp+36處的硬件出錯碼拷貝到edx中,給棧中這一位置存上值-1,這個值用來把0x80異常與其他異常隔離開。把保存在棧中的esp+32位置的do_handler_name()高級C函數(shù)的地址裝入edi寄存器中,然后在棧的這個位置寫入es值。第十八頁,共四十二頁,2022年,8月28日把內(nèi)核棧的當(dāng)前棧頂拷貝到eax寄存器。這個地址表示內(nèi)存單元的地址,在這個單元中存放的是第一步所保存的最后一個寄存器的值。把用戶數(shù)據(jù)段選擇符拷貝到ds和es寄存器中。調(diào)用地址在edi中的高級C函數(shù)。進入和離開異常處理函數(shù)執(zhí)行異常處理程序的C函數(shù)名總是由do_前綴和處理程序名組成。其中大部分函數(shù)把硬件出錯碼和異常向量保存在當(dāng)前進程的描述符中,然后向當(dāng)前進程發(fā)送一個適當(dāng)?shù)男盘?。異常處理程序剛一終止,當(dāng)前進程就關(guān)注這個信號,該信號要么在用戶態(tài)由進程自己的信號處理程序來處理,要么由內(nèi)核來處理。在后一種情況下,內(nèi)核一般會殺死這個進程。異常處理程序總是檢查異常時發(fā)生在用戶態(tài)還是在內(nèi)核態(tài),在內(nèi)核態(tài)時還要檢查是否由系統(tǒng)調(diào)用的無效參數(shù)引起。出現(xiàn)在內(nèi)核態(tài)的任何其他異常都是由于內(nèi)核的bug引起的,在這種情況下異常處理程序認為是內(nèi)核行為失常了。為了避免硬盤上的數(shù)據(jù)崩潰,處理程序調(diào)die()函數(shù),該函數(shù)在控制臺上打印出所有CPU寄存器內(nèi)容,并調(diào)用do_exit()來終止當(dāng)前進程。當(dāng)執(zhí)行異常處理的C函數(shù)終止時,程序執(zhí)行一條jmp指令以跳轉(zhuǎn)到ret_from_exception()函數(shù)。第十九頁,共四十二頁,2022年,8月28日4.6中斷處理中斷處理依賴于中斷類型,中斷類型主要分三類:I/O中斷、時鐘中斷和處理器間中斷。I/O中斷處理:一般情況下,I/O中斷處理程序必須足夠靈活以給多個設(shè)備同時提供服務(wù)。其靈活性是以兩種不同的方式實現(xiàn)的:1)IRQ共享:中斷處理程序執(zhí)行多個中斷服務(wù)例程(ISR),每個ISR是一個與單獨設(shè)備(共享IRQ線)相關(guān)的函數(shù),因為不可能預(yù)先知道哪個特定的設(shè)備產(chǎn)生IRQ,因此每個ISR都執(zhí)行,以驗證它的設(shè)備是否需要關(guān)注,如果是,當(dāng)設(shè)備產(chǎn)生中斷時就執(zhí)行需要執(zhí)行的所有操作。2)IRQ動態(tài)分配:一條IRQ線在可能的最后時刻才與一個設(shè)備驅(qū)動程序相關(guān)聯(lián),這樣,即使幾個硬件設(shè)備并不共享IRQ線,同一個IRQ向量也可以由這幾個設(shè)備在不同時刻使用。第二十頁,共四十二頁,2022年,8月28日所有I/O中斷處理程序都執(zhí)行四個相同的基本操作:在內(nèi)核態(tài)堆棧中保存IRQ的值和寄存器的內(nèi)容。為正在給IRQ線服務(wù)的PIC發(fā)送一個應(yīng)答,這將允許PIC進一步發(fā)出中斷。執(zhí)行共享這個IRQ的所有設(shè)備的中斷服務(wù)例程(ISR)。跳到ret_from_intr()的地址后終止。第二十一頁,共四十二頁,2022年,8月28日中斷向量第二十二頁,共四十二頁,2022年,8月28日IRQ數(shù)據(jù)結(jié)構(gòu)每個中斷向量都有它自己的irq_desc_t描述符,其字段如下表,所有的這些描述符組織在一起形成irq_desc數(shù)組。第二十三頁,共四十二頁,2022年,8月28日第二十四頁,共四十二頁,2022年,8月28日IRQ在多處理器系統(tǒng)上的分發(fā)
Linux遵循對稱多處理模型(SMP),因此內(nèi)核試圖以輪轉(zhuǎn)的方式把來自硬件設(shè)備的IRQ信號在所有的CPU之間分發(fā),所有CPU服務(wù)于I/O中斷的執(zhí)行時間片幾乎相同。當(dāng)硬件設(shè)備產(chǎn)生了一個中斷信號時,多APIC系統(tǒng)就選擇其中的一個CPU,并把該信號傳遞給相應(yīng)的本地APIC,本地APIC又一次中斷它的CPU,這個事件不通報給其他所有的CPU。所有這些都由硬件完成,但在有些情況下,硬件不能以公平的方式在微處理器之間成功的分配中斷,因此在必要的時候,Linux2.6利用kirqd特殊內(nèi)核線程來糾正對CPU進行的IRQ的自動分配。多種類型的內(nèi)核棧每個進程的thread_info描述符和thread_union結(jié)構(gòu)中的內(nèi)核棧緊鄰,而根據(jù)內(nèi)核編譯時的選項不同,thread_union結(jié)構(gòu)可能占一個頁框或兩個頁框。如果thread_union結(jié)構(gòu)的大小為8KB,那么當(dāng)前進程的內(nèi)核棧被用于所有類型的內(nèi)核控制路徑:異常、中斷和可延遲函數(shù)。如果thread_union結(jié)構(gòu)的大小為4KB,內(nèi)核就使用三種類型的內(nèi)核棧:異常棧(處理異常)、硬中斷請求棧(處理中斷)和軟中斷請求棧(處理可延遲的函數(shù))。第二十五頁,共四十二頁,2022年,8月28日為中斷處理程序保存寄存器的值保存寄存器是中斷處理程序做的第一件事情,IRQn中斷處理程序的地址開始存在interrupt[n]中,然后復(fù)制到IDT相應(yīng)表項的中斷門中。通過文件arch/i386/kernel/entry.S中的幾條匯編語言指令建立interrupt數(shù)組,數(shù)組中索引為n的元素中存放下面兩條匯編語言指令的地址:pushl$n-256jmpcommon_interrupt結(jié)果是把終端號減256的結(jié)果保存在棧中,內(nèi)核用負數(shù)表示所有的中斷(正數(shù)表示系統(tǒng)調(diào)用)。當(dāng)引用這個數(shù)時,可以對所有的中斷處理程序都執(zhí)行相同的代碼,這段代碼開始于標(biāo)簽common_interrupt處,包含的匯編指令和宏如下:common_interrupt:SAVE_ALLmovl%esp,%eaxcalldo_IRQjmpret_from_intr
SAVE_ALL可以在棧中保存中斷處理程序可能會使用的所有CPU寄存器,但eflags、cs、eip、ss和esp除外,因為這幾個寄存器已經(jīng)由控制單元自動保存了。然后這個宏把用戶數(shù)據(jù)段的選擇符裝到ds和es寄存器。保存寄存器的值以后,棧頂?shù)牡刂繁淮娣诺絜ax寄存器中,然后中斷處理程序調(diào)用do_IRQ()函數(shù),執(zhí)行到ret指令時,控制轉(zhuǎn)到ret_from_intr()。第二十六頁,共四十二頁,2022年,8月28日挽救丟失的中斷第二十七頁,共四十二頁,2022年,8月28日中斷服務(wù)例程一個中斷服務(wù)例程(ISR)實現(xiàn)一種特定設(shè)備的操作。當(dāng)中斷處理程序必須執(zhí)行ISR時,它就調(diào)用handle_IRQ_event()函數(shù),這個函數(shù)執(zhí)行以下操作:第二十八頁,共四十二頁,2022年,8月28日所有的ISR都作用于相同的參數(shù)(分別通過eax、edx和ecx寄存器傳遞):irq IRQ號dev_id 設(shè)備標(biāo)識符regs 指向內(nèi)核(異常)棧的pt_regs結(jié)構(gòu)的指針,棧中含有中斷發(fā)生后隨即 保存的寄存器。第一個參數(shù)允許一個單獨的ISR處理幾條IRQ線,第二個參數(shù)允許一個單獨的ISR照顧幾個同類型的設(shè)備,第三個參數(shù)允許ISR訪問被中斷的內(nèi)核控制路徑的上下文。每個中斷服務(wù)例程在成功處理完中斷后都返回1,否則返回0.IRQ線的動態(tài)分配
在激活一個準(zhǔn)備利用的IRQ線的設(shè)備之前,其相應(yīng)的驅(qū)動程序調(diào)用request_irq()。這個函數(shù)建立一個新的irqaction描述符,并用參數(shù)值初始化它,然后調(diào)用setup_irq()函數(shù)把這個描述符插入到合適的IRQ鏈表,如果setup_irq()返回一個出錯碼,設(shè)備驅(qū)動程序中止操作,這意味著IRQ線已經(jīng)已由另一個設(shè)備所使用,而這個設(shè)備部允許中斷共享。當(dāng)設(shè)備操作結(jié)束時,驅(qū)動程序調(diào)用free_irq()函數(shù)從IRQ鏈表中刪除這個描述符,并釋放相應(yīng)的內(nèi)存區(qū)。第二十九頁,共四十二頁,2022年,8月28日處理器間中斷處理第三十頁,共四十二頁,2022年,8月28日處理器間中斷程序的匯編語言代碼是由BUILD_INTERRUPT宏產(chǎn)生的:它保存寄存器,從棧頂壓入向量號減256的值,然后調(diào)用高級C函數(shù),其名字就是低級處理程序的名字加前綴smp_。每個該機處理程序應(yīng)答本地APIC上的處理器間中斷,然后執(zhí)行由中斷觸發(fā)的特定操作。第三十一頁,共四十二頁,2022年,8月28日4.7軟中斷和tasklet軟中斷和tasklet有密切關(guān)系,tasklet是在軟中斷之上實現(xiàn)。事實上,出現(xiàn)在內(nèi)核代碼中的術(shù)語“軟中斷softirq”常常表示可延遲函數(shù)的所有種類。另外一種經(jīng)常使用的術(shù)語是“中斷上下文”;表示中斷當(dāng)前正在執(zhí)行一個中斷處理程序或者一個可延遲的函數(shù)。軟中斷的分配是靜態(tài)的(在編譯時定義),而tasklet的分配和初始化可以在運行時進行。軟中斷(即便是同一種類型的中斷)可以并發(fā)的運行多個CPU上。因此,軟中斷是可重入函數(shù)而且必須明確的使用自鎖保護其數(shù)據(jù)結(jié)構(gòu)。tasklet不必擔(dān)心這些問題,因為內(nèi)核對tasklet的執(zhí)行有了更加嚴(yán)格的控制。相同的tasklet總是串行執(zhí)行的。,換句話說,就是不能在cpu上同時運行兩個相當(dāng)同類型的tasklet。但是。類型不同的tasklet可以在幾個cpu上并發(fā)執(zhí)行。tasklet的串行化使tasklet函數(shù)不必是可重入的,因此簡化了設(shè)備驅(qū)動程序開發(fā)者的工作。一般而言,在可延遲函數(shù)上可以執(zhí)行四種操作:初始化:定義一個新的可延遲函數(shù),這個操作通常在內(nèi)核自身初始化或者加載模塊時進行。激活:標(biāo)記一個可延遲函數(shù)為“掛起”(在可延遲函數(shù)的下一輪調(diào)度中執(zhí)行。)激活可以在任何時候執(zhí)行(即使正在處理中斷)。屏蔽:有選擇的屏蔽一個可延遲函數(shù),這樣,即使他被激活,內(nèi)核也不執(zhí)行它。執(zhí)行:執(zhí)行一個掛起的可執(zhí)行函數(shù)和同類型的所有掛起的可延遲函數(shù);執(zhí)行是在特定的時間進行的。第三十二頁,共四十二頁,2022年,8月28日軟中斷一個軟中斷的下標(biāo)決定了它的優(yōu)先級:低下標(biāo)意味著高優(yōu)先級,因為軟中斷函數(shù)將從下表0開始執(zhí)行。軟中斷使用的數(shù)據(jù)結(jié)構(gòu)是softirq_vec數(shù)組,該數(shù)組包含類型為softirq_action的32個元素。一個軟中斷的優(yōu)先級是相應(yīng)的soft_action元素在數(shù)組內(nèi)的下標(biāo)。Soft_action數(shù)據(jù)結(jié)構(gòu)包括兩個字段:指向軟中斷函數(shù)的一個action指針和指向軟中斷函數(shù)需要的通用數(shù)據(jù)結(jié)構(gòu)的data指針。另外一個關(guān)鍵字段是32位的preempt_count字段,用它來跟蹤內(nèi)核搶占和內(nèi)核控制路徑的嵌套,該字段存放在每個進程描述符的thread_info字段中。第三十三頁,共四十二頁,2022年,8月28日實現(xiàn)軟中斷的最后一個關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)是每個cpu都有的32位掩碼,他存放在irq_cpustar_t數(shù)據(jù)結(jié)構(gòu)的__softirq_pending字段中。為了獲取或設(shè)置位掩碼的值,內(nèi)核使用宏local_softirq_pending(),它選擇本地cpu的軟中斷位掩碼。處理軟中斷open_softirq()函數(shù)處理軟中斷的初始化。它使用三個參數(shù):軟中斷下標(biāo),指向要執(zhí)行的軟中斷函數(shù)指針及指向可能由軟中斷函數(shù)使用的數(shù)據(jù)結(jié)構(gòu)的指針。Open_softirq()限制自己初始化softirq_vec數(shù)組中適當(dāng)?shù)牡脑亍?/p>
raise_softirq()函數(shù)用來激活軟中斷,它接受軟中斷下標(biāo)nr作為參數(shù),執(zhí)行下面操作。1.執(zhí)行l(wèi)ocal_irq_save宏以保存eflags寄存器IF標(biāo)志的狀態(tài)值并禁用本地cpu上的中斷。2.把軟中斷標(biāo)記為掛起狀態(tài),這是通過設(shè)置本地的cpu的軟中斷掩碼中與下標(biāo)nr相關(guān)的位來實現(xiàn)。3.如果in_interrupt()產(chǎn)生為1的值,則跳轉(zhuǎn)到第5步。這種情況說明,要么已經(jīng)在中斷上下文中調(diào)用了raise_softirq(),要么當(dāng)前禁用了軟中斷。4.否則,就在需要的時候去調(diào)用wakeup_softirq()以喚醒本地cpu的ksoftirqd內(nèi)核線程。5.執(zhí)行l(wèi)ocal_irq_restore宏,恢復(fù)在第1步保存的IF標(biāo)志的狀態(tài)值。第三十四頁,共四十二頁,2022年,8月28日應(yīng)該周期性的檢查活動的軟中斷,檢查是在內(nèi)核代碼的幾個點上進行的。這在下列幾種情況下進行,:1.當(dāng)內(nèi)核調(diào)用local_bh-enable()函數(shù)激活本地cpu的軟中斷時。2.當(dāng)do_IRQ()完成了I/O中斷的處理時或調(diào)用irq_exit()宏時。3.如果系統(tǒng)使用I/OAPIC,則當(dāng)smp_apic_timer_interrupt()函數(shù)處理完本地的定時器中斷時。4.在多處理器系統(tǒng)中,當(dāng)cpu處理完被CALL_FUNCTION_VECTOR處理器間中斷所觸發(fā)的函數(shù)時。5.當(dāng)一個特殊的ksoftirqd/n內(nèi)核線程被喚醒時。tasklettasklet是I/O驅(qū)動程序中實現(xiàn)可延遲函數(shù)的首選方法。如前所述,tasklet建立在兩個叫做HI_SOFTIRQ的軟中斷之上。幾個tasklet可以與同一個軟中斷相關(guān)聯(lián),每個tasklet執(zhí)行自己的函數(shù)。兩個軟中斷之間沒有真正的區(qū)別,只不過do-softirq()先執(zhí)行HI_SOFTIRQ的tasklet,后執(zhí)行TASKLET_SOFTIRQ的tasklet。tasklet和高優(yōu)先級的tasklet分別存放在tasklet_vec和tasklet_hi_vec數(shù)組中,二者都包含類型為tasklet_head的NR_CPUS個元素,每個元素都有一個指向tasklet描述符鏈表的指針組成。tasklet描述符是一個tasklet_struct類型的數(shù)據(jù)結(jié)構(gòu),其字段如下表:第三十五頁,共四十二頁,2022年,8月28日第三十六頁,共四十二頁,2022年,8月28日調(diào)用tasklet_disable_nosync()或tasklet_disable()可以選擇性的禁止tasklet。這兩個函數(shù)都增加tasklet描述符的count字段,但是最后一個函數(shù)只有在tasklet函數(shù)已經(jīng)運行的實例結(jié)束后才返回。為了重新激活tasklet,調(diào)用tasklet_enable()函數(shù)。為了激活tasklet,應(yīng)該根據(jù)tasklet需要的優(yōu)先級,調(diào)用tasklet_schedule()函數(shù)或tasklet_hi_schedule()函數(shù),這兩個函數(shù)非常相似,其中每個都執(zhí)行下列操作:1.檢查TASKLET_STATE_SCHED()標(biāo)志;如果設(shè)置則返回。2.調(diào)用local_irq_save保存IF標(biāo)志的狀態(tài)并禁用本地中斷。3.在tasklet_vec[n]指向的鏈表的起始處增加tasklet描述符。4.調(diào)用raise_softirq_irqoff()激活TASKLET_SOFTIRQ或HI_SOFTIRQ類型的軟中斷。5.調(diào)用local_irq_restore恢復(fù)IF標(biāo)志的狀態(tài)。軟中斷函數(shù)一旦被激活,do_softirq()函數(shù)執(zhí)行。與HI_SOFTIRQ軟中斷相關(guān)的軟中斷函數(shù)叫做tasklet_hi_action()。這兩個函數(shù)非常相似,他們都執(zhí)行下列操作:1.禁用本地中斷。2.獲得本地cpu的邏輯號n。3.把tasklet_vec[n]或tasklet_hi_vec[n]指向的鏈表的地址存入局部變量list。第三十七頁,共四十二頁,2022年,8月28日4.把tasklet_vec[n]或asklet_hi_vec[n]的值賦為null,因此,已調(diào)度的tasklet描述符的鏈表被清空。5.打開本地中斷。6.對于list指向的鏈表中的每個tasklet描述符:a.在多處理系統(tǒng)上,檢查tasklet的tasklet_STATE_RUN標(biāo)志。 如果該標(biāo)志被設(shè)置,說明同類型的一個tasklet正在cpu上運行,因 此,把任務(wù)描述符重新插入到由tasklet_vec[n]或tasklet_hi_vec[n]指 向的鏈表中,并再次激活tasklet_softirq或HI_SOFTIRQ軟中斷。 如果未被設(shè)置,tasklet就沒有在其他cpu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年機械儀表項目合作計劃書
- 美國的關(guān)稅匯率的兩面
- 振動傳遞路徑分析企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 微生物除臭劑應(yīng)用研究行業(yè)深度調(diào)研及發(fā)展戰(zhàn)略咨詢報告
- 任務(wù)墻柱面裝飾工程工程量的計算墻柱面工程課件
- 生物修復(fù)技術(shù)企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 高性能交聯(lián)劑生產(chǎn)行業(yè)跨境出海戰(zhàn)略研究報告
- 環(huán)球美食行業(yè)跨境出海戰(zhàn)略研究報告
- 水性環(huán)氧防腐涂料行業(yè)跨境出海戰(zhàn)略研究報告
- 工業(yè)廢渣阻燃劑原料行業(yè)深度調(diào)研及發(fā)展戰(zhàn)略咨詢報告
- 2025年建筑行業(yè)高空作業(yè)安全生產(chǎn)合同
- 3.2依法行使權(quán)利 課件 -2024-2025學(xué)年統(tǒng)編版道德與法治八年級下冊
- 2025年貴州遵義正安縣事業(yè)單位招聘工作人員歷年高頻重點模擬試卷提升(共500題附帶答案詳解)
- 2025年安徽電氣工程職業(yè)技術(shù)學(xué)院高職單招職業(yè)技能測試近5年??及鎱⒖碱}庫含答案解析
- 教科版2024-2025學(xué)年六年級下冊科學(xué)3.1《太陽系大家庭》同步練習(xí)(附參考答案)
- Polarion-ALM支持機載軟件研發(fā)生命周期管理和合規(guī)性認證最佳實踐
- 2025年寧夏寧東開發(fā)投資有限公司招聘筆試參考題庫含答案解析
- 《半導(dǎo)體行業(yè)發(fā)展歷程》課件
- 上海市智算中心建設(shè)導(dǎo)則(2025年版)
- 2025山東能源集團中級人才庫選拔高頻重點提升(共500題)附帶答案詳解
- 中央2024年農(nóng)業(yè)農(nóng)村部機關(guān)服務(wù)局招聘事業(yè)編制工作人員筆試歷年典型考點(頻考版試卷)附帶答案詳解
評論
0/150
提交評論