第四章中斷和異常_第1頁
第四章中斷和異常_第2頁
第四章中斷和異常_第3頁
第四章中斷和異常_第4頁
第四章中斷和異常_第5頁
已閱讀5頁,還剩37頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第四章中斷和異常第一頁,共四十二頁,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í)行順序的事件。中斷通常分為同步中斷和異步中斷。同步中斷:當指令執(zhí)行時由CPU控制單元產生的,只有在一條指令終止執(zhí)行后CPU才會發(fā)出中斷。異步中斷:由其他硬件設備依照CPU時鐘信號隨機產生的。

在Intel微處理器手冊中,把同步和異步中斷分別稱為異常和中斷。中斷是由間隔定時器和I/O設備產生的,而異常是由程序的錯誤產生的,或者是由內核必須處理的異常條件產生的。第三頁,共四十二頁,2022年,8月28日

中斷信號的作用是提供一種特殊的方式使處理器轉而去運行正??刂屏髦獾拇a。當一個中斷信號到達時,CPU必須停止它當前正在做的事情,并且切換到一個新的活動。

為了做到這一點,就要在內核態(tài)堆棧保存程序計數器的當前值(即eip和cs寄存器的內容),并把與中斷類型相關的一個地址放進程序計數器。中斷處理與進程切換的區(qū)別:

由中斷或異常處理程序執(zhí)行的代碼不是一個進程。中斷處理程序比一個進程要“l(fā)ight”(中斷的上下文很少,建立或終止中斷處理需要的時間很少)。第四頁,共四十二頁,2022年,8月28日中斷:1)可屏蔽中斷 I/O設備發(fā)出的所有中斷請求(IRQ)都產生可屏蔽中斷,可屏蔽中斷可以處于兩種狀態(tài):屏蔽的或非屏蔽的,一個屏蔽的中斷只要還是屏蔽的,控制單元就忽略它。2)非屏蔽中斷

只有幾個危急事件(如硬件故障)才引起非屏蔽中斷。非屏蔽中斷總是由CPU辨認。異常:1)處理器探測異常

當CPU執(zhí)行指令時探測到的一個反常條件所產生的異常??梢苑譃?組:包括故障,陷阱和異常終止。這取決于CPU控制單元產生異常時候保存在內核態(tài)堆棧eip寄存器中的值。2)編程異常

在編程者發(fā)出請求時發(fā)生。是由int或int3指令觸發(fā)的;當into(檢查溢出)和bound(檢查地址出界)指令檢查的條件不為真時,也引起編程異常??刂茊卧丫幊坍惓W鳛橄葳鍋硖幚?,編程異常通常也叫做軟中斷。編程異常有兩種用途:執(zhí)行系統(tǒng)調用和給調試程序通報一個特定的事件。第五頁,共四十二頁,2022年,8月28日每個能夠發(fā)出中斷請求的硬件設備控制器都有一條IRQ輸出線,所有現(xiàn)有的IRQ線都與一個可編程中斷控制器的輸入引腳相連,可編程控制器執(zhí)行以下動作:1.監(jiān)視IRQ線,檢查產生的信號。如果有兩條或兩條以上的IRQ線上產生信號,就選擇引腳編號較小的IRQ線。2.如果一個引發(fā)信號出現(xiàn)在IRQ線上: a)把接收到的引發(fā)信號轉換成對應的向量。 b)把這個向量存放在中斷控制器的一個I/O端口,從而允許CPU通過數 據總線讀此向量。 c)把引發(fā)信號發(fā)送到處理器的INTR引腳,即產生一個中斷。 d)等待,直到CPU通過把這個中斷信號寫進可編程中斷控制器的一個 I/O端口來確認它,當這種情況發(fā)生時,清INTR線。3.返回到第一步。IRQ線是從0開始編號的,第一條IRQ線通常表示成IRQ0,與IRQn關聯(lián)的Intel的缺省向量是n+32。可以有選擇的禁止每條IRQ線,可以對PCI編程從而禁止IRQ。而有選擇的激活/禁止IRQ線不同于可屏蔽中斷的全局屏蔽/非屏蔽,當eflags寄存器的IF標志被清0時,由PIC發(fā)布的每個可屏蔽中斷都由CPU暫時忽略,cli和sti匯編指令分別清除和設置該標志。第六頁,共四十二頁,2022年,8月28日目的:為了充分發(fā)揮多處理器體系結構的并行性,能夠把中斷傳遞給系統(tǒng)中的每個CPU。結構:每個CPU都含有一個本地APIC,每個本地APIC都有32位的寄存器,一個內部時鐘,一個本地定時設備以及為本地APIC中斷保留的兩條額外的IRQ線LINT0和LINT1。所有本地APIC都連接到一個外部I/OAPIC,形成一個多APIC的系統(tǒng)。I/OAPIC的組成:一組24條IRQ線,一張24項的中斷重定向表,可編程寄存器,以及通過APIC總線發(fā)送和接收APIC信息的一個信息單元。中斷重定向表中的信息用于把每個外部IRQ信號轉換為一條消息,然后通過APIC總線把消息發(fā)送給一個或多個本地APIC單元。來自外部硬件設備的中斷請求以下面兩種方式在可用CPU之間分發(fā):1)靜態(tài)分發(fā) IRQ信號傳遞給重定向表相應項中所列出的本地APIC。2)動態(tài)分發(fā)

如果處理器正在執(zhí)行最低優(yōu)先級進程,IRQ信號就傳遞給這種處理器的本地APIC。

如果兩個或多個CPU共享最低優(yōu)先級,就利用仲裁技術分配CPU。第七頁,共四十二頁,2022年,8月28日仲裁技術:

在本地APIC的仲裁優(yōu)先級寄存器中,給每一個CPU都分配一個0(最低)~15(最高)范圍內的值。

每當中斷傳遞給一個CPU時,其相應的仲裁優(yōu)先級就自動置為0,而其他每個CPU的仲裁優(yōu)先級都增加1,當仲裁優(yōu)先級寄存器大于15時,就把它置為獲勝CPU的前一個仲裁優(yōu)先級加1。因此,中斷以輪轉的方式在CPU之間分發(fā),且具有相同的任務優(yōu)先級。處理器間中斷(IPI):

除了在處理器之間分發(fā)中斷外,多APIC系統(tǒng)還允許CPU產生處理器間中斷。當一個CPU希望把中斷發(fā)送給另一個CPU時,它就在自己本地APIC的中斷指令寄存器(ICR)中存放這個中斷向量和目標本地APIC的標識符。然后,通過APIC總線向目標本地APIC發(fā)送一條消息,從而向自己的CPU發(fā)出一條相應的中斷。 IPI被linux用來在CPU之間交換信息。第八頁,共四十二頁,2022年,8月28日80x86處理器發(fā)布了大約20種異常,內核必須為每種異常提供一個專門的異常處理程序,對于某些異常,CPU控制單元在開始執(zhí)行異常處理前會產生一個硬件出錯碼,并且壓入內核態(tài)堆棧。0Divideerror(故障)當一個程序試圖執(zhí)行整數被0除操作時產生1Debug(陷阱或故障)產生于設置eflags的TF標志或一條指令或操作數的地址落在一個活動debug寄存器的范圍之內時。未用

為非屏蔽中斷保留Breakpoint(陷阱)由int3(斷點)指令引起Overflow(陷阱)當eflags的OF標志被設置時,into指令被執(zhí)行。Boundscheck(故障)

對于有效地址范圍之外的操作數,bound指令被執(zhí)行。Invalidopcode(故障)CPU執(zhí)行單元檢測到一個無效操作碼。Devicenotavailable(故障)隨著cr0的TS標志被設置,ESCAPE、MMX或XMM指令被執(zhí)行。Doublefault(異常中止)正常情況下當CPU正試圖為前一個異常調用處理程序時,同時又檢測到一個異常,兩個異常能被串行的處理,然而在少數情況下,處理器不能串行的處理它們,因而產生這種異常。Coprocessorsegmentoverrun(異常中止)因外部的數學協(xié)處理器引起的問題。InvalidTSS(故障)CPU試圖讓一個上下文切換到有無效TSS的進程。第九頁,共四十二頁,2022年,8月28日Segmentnotpresent(故障)引用一個不存在的內存段。Stacksegmentfault(故障)試圖超過棧段界限的指令,或者ss標識的段不在內存。Generalprotection(故障)違反了80x86保護模式下的保護規(guī)則之一。Pagefault(故障)尋址的頁不在內存,相應的頁表項為空,或者違反了一種分頁保護機制。由Intel保留。Floatingpointerror(故障)集成到CPU芯片中的浮點單元用信號通知一個錯誤情形,如數字溢出或被0除。Alignmentcheck(故障)操作數的地址沒有被正確的對齊Machinecheck(異常中止)機器檢查機制檢測到一個CPU錯誤或總線錯誤。SIMDfloatingpointexception(故障)集成到CPU芯片中的SSE或SSE2單元對浮點操作用信號通知一個錯誤情形。20~31這些值由Intel留作將來開發(fā)。第十頁,共四十二頁,2022年,8月28日中斷描述符表是一個系統(tǒng)表,它與每一個中斷或異常向量相聯(lián)系,每一個向量在表中有相應的中斷或異常處理程序的入口地址,內核在允許中斷發(fā)生前,必須用lidt匯編指令初始化IDT。idtrCPU寄存器指定了IDT的線性基地址及其限制(最大長度),因此IDT可以位于內存的任何地方。IDT包含三種類型的描述符:1)任務門:

當中斷信號發(fā)生時,必須取代當前進程的那個進程的TSS選擇符存放在

任務門中。2)中斷門:

包含段選擇符和中斷或異常處理程序的段內偏移量。當控制權轉移到一

個適當的段時,處理器清IF標志,從而關閉將來會發(fā)生的可屏蔽中斷。3)陷阱門:

與中斷門相似,只是控制權傳遞到一個適當的段時處理器不修改IF標志。第十一頁,共四十二頁,2022年,8月28日當執(zhí)行了一條指令后,cs和eip寄存器包含下一條將要執(zhí)行指令的邏輯地址,在處理那條指令之前,控制單元會檢查在運行前一條指令時是否已經發(fā)生了一個中斷或異常,如果發(fā)生了一個中斷或異常,控制單元執(zhí)行以下操作:確定與中斷或異常關聯(lián)的向量i(0<=i<=255).讀由idtr寄存器指向的IDT表中的第i項。從gdtr寄存器獲得GDT的基地址,并在GDT中查找,以讀取IDT表項中的選擇符所標識的段描述符,這個描述符指定中斷或異常處理程序所在段的基地址。確信中斷是由授權的中斷發(fā)生源發(fā)出的。首先將當前特權級CPL與段描述符的描述符特權級DPL比較,如果CPL小于DPL,就產生一個“Generalprotection”異常,因為中斷處理程序的特權不能低于引起中斷的程序的特權。對于編程異常則做進一步的安全檢查:比較CPL與處于IDT中的門描述符的DPL,如果DPL小于CPL就產生一個“Generalprotection”異常。這最后一個檢查可以避免用戶應用程序訪問特殊的陷阱門或中斷門。檢查是否發(fā)生了特權級的變化,也就是說,CPL是否不同于所選擇的段描述符的DPL,如果是,控制單元必須開始使用與新的特權級相關的棧。如果故障已經發(fā)生,用引起異常的指令地址裝載cs和eip寄存器,從而使得這條指令能再次被執(zhí)行。第十二頁,共四十二頁,2022年,8月28日在棧中保存eflags、cs及eip的內容。如果異常產生了一個硬件出錯碼,則將它保存在棧中。裝載cs和eip寄存器,其值分別是IDT表中第i項門描述符的段選擇符和偏移量字段。這些值給出了中斷或者異常處理程序的第一條指令的邏輯地址。

控制單元所執(zhí)行的最后一步就是跳轉到中斷或異常的處理程序,即被選中處理程序的第一條指令。

中斷或異常處理完后,相應的處理程序必須產生一條iret指令,把控制權交給被中斷的進程,這時控制單元執(zhí)行以下操作:用保存在棧中的值裝載cs、eip或eflags寄存器。如果一個硬件出錯碼曾被壓入棧中,并且在eip內容的上面,那么執(zhí)行iret指令前必須先彈出這個硬件出錯碼。檢查處理程序的CPL是否等于cs中最低兩位的值(這意味著被中斷的進程與處理程序運行在同一特權級),如果是,iret終止執(zhí)行,否則轉入下一步。從棧中裝載ss和esp寄存器,因此返回到與舊特權級相關的棧。檢查ds、es、fs及gs段寄存器的內容,如果其中一個寄存器包含的選擇符是一個段描述符,并且其DPL小于CPL,那么清相應的段寄存器。這是為了禁止用戶態(tài)的程序(CPL=3)利用內核以前所用的段寄存器(DPL=0),如果不清這些寄存器,懷有惡意的用戶態(tài)程序就可能利用它們來訪問內核地址空間。第十三頁,共四十二頁,2022年,8月28日

每個中斷或異常都會引起一個內核控制路徑,或者說代表當前進程在內核態(tài)執(zhí)行單獨的指令序列。內核控制路徑可以任意嵌套,一個中斷程序可以被另一個中斷程序“中斷”,因此引起內核控制路徑的嵌套執(zhí)行。其結果是:對中斷進行處理的內核控制路徑的最后一部分指令并不總能使當前進程返回到用戶態(tài):如果嵌套深度大于1,這些指令將執(zhí)行上次被打斷的內核控制路徑,此時的CPU依然運行在內核態(tài)。允許內核控制路徑嵌套執(zhí)行必須要求中斷處理程序永不阻塞,即中斷處理程序運行期間不能發(fā)生進程切換。在內核沒有bug的情況下,大多數異常在在CPU處于用戶態(tài)時發(fā)生。異常要么是由編程錯誤引起,要么是由調試程序觸發(fā),但是缺頁異常發(fā)生在內核態(tài)。一個中斷處理程序既可以搶占其他的中斷處理程序,也可以搶占異常處理程序,相反,異常處理程序從不搶占中斷處理程序。在內核態(tài)能觸發(fā)的唯一異常就是缺頁異常,但中斷處理程序從不執(zhí)行可以導致缺頁的操作。在多處理器系統(tǒng)上,幾個內核控制路徑可以并發(fā)的執(zhí)行,此外與異常相關的內核控制路徑可以開始在一個CPU上執(zhí)行,并且由于進程切換而移往另一個CPU上執(zhí)行。第十四頁,共四十二頁,2022年,8月28日4.4初始化中斷描述符表內核啟用中斷以前,必須把IDT表的初始地址裝到idtr寄存器,并初始化表中的每一項。這項工作是在初始化系統(tǒng)的時候完成的。Linux中中斷描述符表分類如下:中斷門:用戶態(tài)進程不能訪問的一個Intel中斷門,門的DPL字段為0,所有的Linux中斷處理程序都通過中斷門激活,并全部限制在內核態(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相關的異常處理程序是由系統(tǒng)中斷門激活的,因此在用戶態(tài)可以使用匯編語言指令int3.陷阱門:用戶態(tài)的進程不能訪問的一個Intel陷阱門,DPL字段為0,大部分Linux異常處理程序都通過陷阱門來激活。任務門:不能被用戶態(tài)進程訪問的一個Intel任務門,DPL字段為0,Linux對“doublefault”異常的處理程序是由任務門激活的。第十五頁,共四十二頁,2022年,8月28日IDT的初步初始化當計算機還運行在實模式時,IDT被初始化并由BIOS例程使用,一旦Linux接管,IDT就被移到RAM的另一個區(qū)域,并進行第二次初始化,因為Linux沒有利用任何BIOS例程。

IDT存放在idt_table表中,有256個表項,6字節(jié)的idt_descr變量指定了IDT的大小和它的地址。在內核初始化過程中,setup_idt()匯編語言函數用同一個中斷門(即指向ignore_int()中斷處理程序)來填充所有這256個idt_table表項。Ignore_int()中斷處理程序執(zhí)行以下操作:在棧中保存一些寄存器的內容。調用printk()函數打印“Unknowninterrupt”系統(tǒng)消息。從?;謴图拇嫫鞯膬热荨?zhí)行iret指令以恢復被中斷的程序。 緊接著這個預初始化,內核將在IDT中進行第二遍初始化,用有意義的陷阱和中斷處理程序替換這個空處理程序。第十六頁,共四十二頁,2022年,8月28日4.5異常處理異常處理程序的標準結構,由三部分組成:在內核堆棧中保存大多數寄存器的內容(匯編語言實現(xiàn))。用高級的C函數處理異常。通過ret_from_exception()函數從異常處理程序退出。第十七頁,共四十二頁,2022年,8月28日為異常處理程序保存寄存器的值用handler_name表示一個通用的異常處理程序的名字,則每一個異常處理程序都以下面的匯編指令開始:handler_name: pushl$0/*onlyforsomeexceptions*/ pushl$do_handler_name jmperror_code其中error_code匯編語言代碼執(zhí)行以下步驟:把高級C函數可能用到的寄存器保存在棧中。產生一條cld指令來清eflags的方向標志DF,以確保調用字符串指令時會自動增加edi和esi寄存器的值。把棧中位于esp+36處的硬件出錯碼拷貝到edx中,給棧中這一位置存上值-1,這個值用來把0x80異常與其他異常隔離開。把保存在棧中的esp+32位置的do_handler_name()高級C函數的地址裝入edi寄存器中,然后在棧的這個位置寫入es值。第十八頁,共四十二頁,2022年,8月28日把內核棧的當前棧頂拷貝到eax寄存器。這個地址表示內存單元的地址,在這個單元中存放的是第一步所保存的最后一個寄存器的值。把用戶數據段選擇符拷貝到ds和es寄存器中。調用地址在edi中的高級C函數。進入和離開異常處理函數執(zhí)行異常處理程序的C函數名總是由do_前綴和處理程序名組成。其中大部分函數把硬件出錯碼和異常向量保存在當前進程的描述符中,然后向當前進程發(fā)送一個適當的信號。異常處理程序剛一終止,當前進程就關注這個信號,該信號要么在用戶態(tài)由進程自己的信號處理程序來處理,要么由內核來處理。在后一種情況下,內核一般會殺死這個進程。異常處理程序總是檢查異常時發(fā)生在用戶態(tài)還是在內核態(tài),在內核態(tài)時還要檢查是否由系統(tǒng)調用的無效參數引起。出現(xiàn)在內核態(tài)的任何其他異常都是由于內核的bug引起的,在這種情況下異常處理程序認為是內核行為失常了。為了避免硬盤上的數據崩潰,處理程序調die()函數,該函數在控制臺上打印出所有CPU寄存器內容,并調用do_exit()來終止當前進程。當執(zhí)行異常處理的C函數終止時,程序執(zhí)行一條jmp指令以跳轉到ret_from_exception()函數。第十九頁,共四十二頁,2022年,8月28日4.6中斷處理中斷處理依賴于中斷類型,中斷類型主要分三類:I/O中斷、時鐘中斷和處理器間中斷。I/O中斷處理:一般情況下,I/O中斷處理程序必須足夠靈活以給多個設備同時提供服務。其靈活性是以兩種不同的方式實現(xiàn)的:1)IRQ共享:中斷處理程序執(zhí)行多個中斷服務例程(ISR),每個ISR是一個與單獨設備(共享IRQ線)相關的函數,因為不可能預先知道哪個特定的設備產生IRQ,因此每個ISR都執(zhí)行,以驗證它的設備是否需要關注,如果是,當設備產生中斷時就執(zhí)行需要執(zhí)行的所有操作。2)IRQ動態(tài)分配:一條IRQ線在可能的最后時刻才與一個設備驅動程序相關聯(lián),這樣,即使幾個硬件設備并不共享IRQ線,同一個IRQ向量也可以由這幾個設備在不同時刻使用。第二十頁,共四十二頁,2022年,8月28日所有I/O中斷處理程序都執(zhí)行四個相同的基本操作:在內核態(tài)堆棧中保存IRQ的值和寄存器的內容。為正在給IRQ線服務的PIC發(fā)送一個應答,這將允許PIC進一步發(fā)出中斷。執(zhí)行共享這個IRQ的所有設備的中斷服務例程(ISR)。跳到ret_from_intr()的地址后終止。第二十一頁,共四十二頁,2022年,8月28日中斷向量第二十二頁,共四十二頁,2022年,8月28日IRQ數據結構每個中斷向量都有它自己的irq_desc_t描述符,其字段如下表,所有的這些描述符組織在一起形成irq_desc數組。第二十三頁,共四十二頁,2022年,8月28日第二十四頁,共四十二頁,2022年,8月28日IRQ在多處理器系統(tǒng)上的分發(fā)

Linux遵循對稱多處理模型(SMP),因此內核試圖以輪轉的方式把來自硬件設備的IRQ信號在所有的CPU之間分發(fā),所有CPU服務于I/O中斷的執(zhí)行時間片幾乎相同。當硬件設備產生了一個中斷信號時,多APIC系統(tǒng)就選擇其中的一個CPU,并把該信號傳遞給相應的本地APIC,本地APIC又一次中斷它的CPU,這個事件不通報給其他所有的CPU。所有這些都由硬件完成,但在有些情況下,硬件不能以公平的方式在微處理器之間成功的分配中斷,因此在必要的時候,Linux2.6利用kirqd特殊內核線程來糾正對CPU進行的IRQ的自動分配。多種類型的內核棧每個進程的thread_info描述符和thread_union結構中的內核棧緊鄰,而根據內核編譯時的選項不同,thread_union結構可能占一個頁框或兩個頁框。如果thread_union結構的大小為8KB,那么當前進程的內核棧被用于所有類型的內核控制路徑:異常、中斷和可延遲函數。如果thread_union結構的大小為4KB,內核就使用三種類型的內核棧:異常棧(處理異常)、硬中斷請求棧(處理中斷)和軟中斷請求棧(處理可延遲的函數)。第二十五頁,共四十二頁,2022年,8月28日為中斷處理程序保存寄存器的值保存寄存器是中斷處理程序做的第一件事情,IRQn中斷處理程序的地址開始存在interrupt[n]中,然后復制到IDT相應表項的中斷門中。通過文件arch/i386/kernel/entry.S中的幾條匯編語言指令建立interrupt數組,數組中索引為n的元素中存放下面兩條匯編語言指令的地址:pushl$n-256jmpcommon_interrupt結果是把終端號減256的結果保存在棧中,內核用負數表示所有的中斷(正數表示系統(tǒng)調用)。當引用這個數時,可以對所有的中斷處理程序都執(zhí)行相同的代碼,這段代碼開始于標簽common_interrupt處,包含的匯編指令和宏如下:common_interrupt:SAVE_ALLmovl%esp,%eaxcalldo_IRQjmpret_from_intr

SAVE_ALL可以在棧中保存中斷處理程序可能會使用的所有CPU寄存器,但eflags、cs、eip、ss和esp除外,因為這幾個寄存器已經由控制單元自動保存了。然后這個宏把用戶數據段的選擇符裝到ds和es寄存器。保存寄存器的值以后,棧頂的地址被存放到eax寄存器中,然后中斷處理程序調用do_IRQ()函數,執(zhí)行到ret指令時,控制轉到ret_from_intr()。第二十六頁,共四十二頁,2022年,8月28日挽救丟失的中斷第二十七頁,共四十二頁,2022年,8月28日中斷服務例程一個中斷服務例程(ISR)實現(xiàn)一種特定設備的操作。當中斷處理程序必須執(zhí)行ISR時,它就調用handle_IRQ_event()函數,這個函數執(zhí)行以下操作:第二十八頁,共四十二頁,2022年,8月28日所有的ISR都作用于相同的參數(分別通過eax、edx和ecx寄存器傳遞):irq IRQ號dev_id 設備標識符regs 指向內核(異常)棧的pt_regs結構的指針,棧中含有中斷發(fā)生后隨即 保存的寄存器。第一個參數允許一個單獨的ISR處理幾條IRQ線,第二個參數允許一個單獨的ISR照顧幾個同類型的設備,第三個參數允許ISR訪問被中斷的內核控制路徑的上下文。每個中斷服務例程在成功處理完中斷后都返回1,否則返回0.IRQ線的動態(tài)分配

在激活一個準備利用的IRQ線的設備之前,其相應的驅動程序調用request_irq()。這個函數建立一個新的irqaction描述符,并用參數值初始化它,然后調用setup_irq()函數把這個描述符插入到合適的IRQ鏈表,如果setup_irq()返回一個出錯碼,設備驅動程序中止操作,這意味著IRQ線已經已由另一個設備所使用,而這個設備部允許中斷共享。當設備操作結束時,驅動程序調用free_irq()函數從IRQ鏈表中刪除這個描述符,并釋放相應的內存區(qū)。第二十九頁,共四十二頁,2022年,8月28日處理器間中斷處理第三十頁,共四十二頁,2022年,8月28日處理器間中斷程序的匯編語言代碼是由BUILD_INTERRUPT宏產生的:它保存寄存器,從棧頂壓入向量號減256的值,然后調用高級C函數,其名字就是低級處理程序的名字加前綴smp_。每個該機處理程序應答本地APIC上的處理器間中斷,然后執(zhí)行由中斷觸發(fā)的特定操作。第三十一頁,共四十二頁,2022年,8月28日4.7軟中斷和tasklet軟中斷和tasklet有密切關系,tasklet是在軟中斷之上實現(xiàn)。事實上,出現(xiàn)在內核代碼中的術語“軟中斷softirq”常常表示可延遲函數的所有種類。另外一種經常使用的術語是“中斷上下文”;表示中斷當前正在執(zhí)行一個中斷處理程序或者一個可延遲的函數。軟中斷的分配是靜態(tài)的(在編譯時定義),而tasklet的分配和初始化可以在運行時進行。軟中斷(即便是同一種類型的中斷)可以并發(fā)的運行多個CPU上。因此,軟中斷是可重入函數而且必須明確的使用自鎖保護其數據結構。tasklet不必擔心這些問題,因為內核對tasklet的執(zhí)行有了更加嚴格的控制。相同的tasklet總是串行執(zhí)行的。,換句話說,就是不能在cpu上同時運行兩個相當同類型的tasklet。但是。類型不同的tasklet可以在幾個cpu上并發(fā)執(zhí)行。tasklet的串行化使tasklet函數不必是可重入的,因此簡化了設備驅動程序開發(fā)者的工作。一般而言,在可延遲函數上可以執(zhí)行四種操作:初始化:定義一個新的可延遲函數,這個操作通常在內核自身初始化或者加載模塊時進行。激活:標記一個可延遲函數為“掛起”(在可延遲函數的下一輪調度中執(zhí)行。)激活可以在任何時候執(zhí)行(即使正在處理中斷)。屏蔽:有選擇的屏蔽一個可延遲函數,這樣,即使他被激活,內核也不執(zhí)行它。執(zhí)行:執(zhí)行一個掛起的可執(zhí)行函數和同類型的所有掛起的可延遲函數;執(zhí)行是在特定的時間進行的。第三十二頁,共四十二頁,2022年,8月28日軟中斷一個軟中斷的下標決定了它的優(yōu)先級:低下標意味著高優(yōu)先級,因為軟中斷函數將從下表0開始執(zhí)行。軟中斷使用的數據結構是softirq_vec數組,該數組包含類型為softirq_action的32個元素。一個軟中斷的優(yōu)先級是相應的soft_action元素在數組內的下標。Soft_action數據結構包括兩個字段:指向軟中斷函數的一個action指針和指向軟中斷函數需要的通用數據結構的data指針。另外一個關鍵字段是32位的preempt_count字段,用它來跟蹤內核搶占和內核控制路徑的嵌套,該字段存放在每個進程描述符的thread_info字段中。第三十三頁,共四十二頁,2022年,8月28日實現(xiàn)軟中斷的最后一個關鍵的數據結構是每個cpu都有的32位掩碼,他存放在irq_cpustar_t數據結構的__softirq_pending字段中。為了獲取或設置位掩碼的值,內核使用宏local_softirq_pending(),它選擇本地cpu的軟中斷位掩碼。處理軟中斷open_softirq()函數處理軟中斷的初始化。它使用三個參數:軟中斷下標,指向要執(zhí)行的軟中斷函數指針及指向可能由軟中斷函數使用的數據結構的指針。Open_softirq()限制自己初始化softirq_vec數組中適當的的元素。

raise_softirq()函數用來激活軟中斷,它接受軟中斷下標nr作為參數,執(zhí)行下面操作。1.執(zhí)行l(wèi)ocal_irq_save宏以保存eflags寄存器IF標志的狀態(tài)值并禁用本地cpu上的中斷。2.把軟中斷標記為掛起狀態(tài),這是通過設置本地的cpu的軟中斷掩碼中與下標nr相關的位來實現(xiàn)。3.如果in_interrupt()產生為1的值,則跳轉到第5步。這種情況說明,要么已經在中斷上下文中調用了raise_softirq(),要么當前禁用了軟中斷。4.否則,就在需要的時候去調用wakeup_softirq()以喚醒本地cpu的ksoftirqd內核線程。5.執(zhí)行l(wèi)ocal_irq_restore宏,恢復在第1步保存的IF標志的狀態(tài)值。第三十四頁,共四十二頁,2022年,8月28日應該周期性的檢查活動的軟中斷,檢查是在內核代碼的幾個點上進行的。這在下列幾種情況下進行,:1.當內核調用local_bh-enable()函數激活本地cpu的軟中斷時。2.當do_IRQ()完成了I/O中斷的處理時或調用irq_exit()宏時。3.如果系統(tǒng)使用I/OAPIC,則當smp_apic_timer_interrupt()函數處理完本地的定時器中斷時。4.在多處理器系統(tǒng)中,當cpu處理完被CALL_FUNCTION_VECTOR處理器間中斷所觸發(fā)的函數時。5.當一個特殊的ksoftirqd/n內核線程被喚醒時。tasklettasklet是I/O驅動程序中實現(xiàn)可延遲函數的首選方法。如前所述,tasklet建立在兩個叫做HI_SOFTIRQ的軟中斷之上。幾個tasklet可以與同一個軟中斷相關聯(lián),每個tasklet執(zhí)行自己的函數。兩個軟中斷之間沒有真正的區(qū)別,只不過do-softirq()先執(zhí)行HI_SOFTIRQ的tasklet,后執(zhí)行TASKLET_SOFTIRQ的tasklet。tasklet和高優(yōu)先級的tasklet分別存放在tasklet_vec和tasklet_hi_vec數組中,二者都包含類型為tasklet_head的NR_CPUS個元素,每個元素都有一個指向tasklet描述符鏈表的指針組成。tasklet描述符是一個tasklet_struct類型的數據結構,其字段如下表:第三十五頁,共四十二頁,2022年,8月28日第三十六頁,共四十二頁,2022年,8月28日調用tasklet_disable_nosync()或tasklet_disable()可以選擇性的禁止tasklet。這兩個函數都增加tasklet描述符的count字段,但是最后一個函數只有在tasklet函數已經運行的實例結束后才返回。為了重新激活tasklet,調用tasklet_enable()函數。為了激活tasklet,應該根據tasklet需要的優(yōu)先級,調用tasklet_schedule()函數或tasklet_hi_schedule()函數,這兩個函數非常相似,其中每個都執(zhí)行下列操作:1.檢查TASKLET_STATE_SCHED()標志;如果設置則返回。2.調用local_irq_save保存IF標志的狀態(tài)并禁用本地中斷。3.在tasklet_vec[n]指向的鏈表的起始處增加tasklet描述符。4.調用raise_softirq_irqoff()激活TASKLET_SOFTIRQ或HI_SOFTIRQ類型的軟中斷。5.調用local_irq_restore恢復IF標志的狀態(tài)。軟中斷函數一旦被激活,do_softirq()函數執(zhí)行。與HI_SOFTIRQ軟中斷相關的軟中斷函數叫做tasklet_hi_action()。這兩個函數非常相似,他們都執(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,因此,已調度的tasklet描述符的鏈表被清空。5.打開本地中斷。6.對于list指向的鏈表中的每個tasklet描述符:a.在多處理系統(tǒng)上,檢查tasklet的tasklet_STATE_RUN標志。 如果該標志被設置,說明同類型的一個tasklet正在cpu上運行,因 此,把任務描述符重新插入到由tasklet_vec[n]或tasklet_hi_vec[n]指 向的鏈表中,并再次激活tasklet_softirq或HI_SOFTIRQ軟中斷。 如果未被設置,tasklet就沒有在其他cpu

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論