中斷和異常處理
中斷和異常是指明系統(tǒng)、處理器、或當(dāng)前執(zhí)行程序的某處出現(xiàn)一個(gè)事件,該事件需要處理器進(jìn)行處理。通常,這種事件會(huì)導(dǎo)致執(zhí)行控制被強(qiáng)迫從當(dāng)前運(yùn)行的程序轉(zhuǎn)移到被稱(chēng)為中斷處理程序或異常處理程序。
1 異常和中斷向量
每個(gè)需要被處理器進(jìn)行特殊處理的處理器定義的異常和中斷條件都被賦予一個(gè)表示號(hào),稱(chēng)為向量(vector)。 處理器把賦予異?;蛑袛嗟南蛄?br> 用作中斷的處理程序入口地點(diǎn)位置。
2 中斷描述符表
該表將每個(gè)異常或者中斷的向量號(hào)同它們的處理過(guò)程聯(lián)系起來(lái)。IDT也是由8字節(jié)長(zhǎng)的描述符組成的一個(gè)描述符表。
指令LIDT和SIDT 指令分別用于加載和保存IDTR寄存器的內(nèi)容。
3 IDT描述符
中斷門(mén)和陷阱門(mén)含有一個(gè)長(zhǎng)指針(即段選擇符和偏移值),處理器用這個(gè)長(zhǎng)指針把程序執(zhí)行權(quán)轉(zhuǎn)移到代碼段中異?;蛑袛嗟奶幚磉^(guò)程中。
任務(wù)門(mén)描述符中有一個(gè)任務(wù)TSS段的任務(wù)選擇符,該任務(wù)用于處理異常和中斷。
4 異常和中斷處理

中斷描述符中的選擇符指向中斷處理程序所在段基址,偏移值指向段中的特定的中斷處理函數(shù)。
5 任務(wù)管理
任務(wù)Task 是處理器可以分配調(diào)度、執(zhí)行和掛起的一個(gè)工作單元。
任務(wù)切換很像過(guò)程調(diào)用,但任務(wù)切換會(huì)保存更多的處理器狀態(tài)信息。任務(wù)切換會(huì)把控制權(quán)完全轉(zhuǎn)移到一個(gè)新的執(zhí)行環(huán)境。這種轉(zhuǎn)移要求保存處理器中幾乎 所有的寄存器的當(dāng)前內(nèi)容,包括標(biāo)志寄存器EFLAGS和所有段寄存器。與過(guò)程不同,任務(wù)不可以重入,任務(wù)切換不會(huì)把任何信息壓入到堆棧中。處理器的狀態(tài)信息否保存在內(nèi)存中稱(chēng)為任務(wù)狀態(tài)段的數(shù)據(jù)結(jié)構(gòu)中。
描述符中與任務(wù)相關(guān)的描述符有兩種: 任務(wù)狀態(tài)段描述符 和 任務(wù)門(mén) 。當(dāng)執(zhí)行權(quán)傳給這兩個(gè)中的一個(gè)的時(shí)候,就發(fā)生了任務(wù)切換。
任務(wù)切換很像函數(shù)調(diào)用,但是任務(wù)切換會(huì)保存更多的處理器信息,任務(wù)切換會(huì)把控制權(quán)完全轉(zhuǎn)移到一個(gè)新的環(huán)境中。
5.1 任務(wù)的結(jié)構(gòu)和狀態(tài)
一個(gè)任務(wù)由兩個(gè)部分構(gòu)成
:任務(wù)執(zhí)行空間和
任務(wù)狀態(tài)段TSS。
任務(wù)執(zhí)行空間包括 代碼段 、堆棧段和一個(gè)或多個(gè)數(shù)據(jù)段。TSS指定了構(gòu)成任務(wù)執(zhí)行空間的各個(gè)段,并且為任務(wù)狀態(tài)信息提供存儲(chǔ)空間。在多任務(wù)環(huán)境中,TSS也為任務(wù)之間的鏈接提供了處理方法。
一個(gè)任務(wù)使用指向其TSS的段選擇符來(lái)指定。當(dāng)一個(gè)任務(wù)被加載進(jìn)處理器中執(zhí)行時(shí),那么該任務(wù)的段選擇符、基地址、段限長(zhǎng)以及TSS段的描述符就會(huì)被加載進(jìn)
任務(wù)寄存器TR中。如果使用了分頁(yè)機(jī)制,那么任務(wù)使用的頁(yè)目錄表基地址就會(huì)被加載進(jìn)控制寄存器CR3中。當(dāng)前執(zhí)行任務(wù)的狀態(tài)由處理器中以下所有內(nèi)容組成:
5.2 任務(wù)的執(zhí)行
(1) 使用call指令明確調(diào)用一個(gè)任務(wù) 。
(2) 使用JMP指令跳轉(zhuǎn)到一個(gè)任務(wù)(linux使用的方式)。
(3)隱含調(diào)用一個(gè)中斷句柄處理任務(wù)。
(4)隱含調(diào)用一個(gè)異常句柄處理任務(wù)。
所有這些調(diào)度任務(wù)執(zhí)行的方法都需要一個(gè)指向任務(wù)門(mén)或者任務(wù)TSS段的選擇符來(lái)確定相應(yīng)的任務(wù)。
當(dāng)調(diào)度一個(gè)任務(wù)執(zhí)行時(shí),當(dāng)前運(yùn)行的任務(wù) 會(huì)和被調(diào)用的任務(wù)會(huì)發(fā)生任務(wù)切換。在任務(wù)切換期間,當(dāng)前正在運(yùn)行的任務(wù)會(huì)把執(zhí)行環(huán)境保存到
它的TSS中,并暫停該任務(wù)的執(zhí)行。此后新調(diào)用任務(wù)的上下文環(huán)境會(huì)被加載進(jìn)內(nèi)存處理器中,并從加載的EIP處,開(kāi)始執(zhí)行新的任務(wù)。
如果當(dāng)前執(zhí)行的任務(wù)調(diào)用了被調(diào)用的新任務(wù),那么當(dāng)前執(zhí)行任務(wù)的TSS段選擇符 會(huì)保存在被調(diào)用任務(wù)的TSS中。從而提供了一個(gè)返回調(diào)用者
的鏈接。
5.3 任務(wù)管理數(shù)據(jù)結(jié)構(gòu)
(1) 任務(wù)狀態(tài)段TSS
(2) TSS描述符
(3) 任務(wù)寄存器TR
(4)任務(wù)門(mén)描述符
(5)標(biāo)志寄存器EFLAGS中的NT標(biāo)志。
5.3.1任務(wù)狀態(tài)段
用于恢復(fù)一個(gè)處理器狀態(tài)的所有信息存儲(chǔ)在稱(chēng)為任務(wù)狀態(tài)段(TSS)的數(shù)據(jù)結(jié)構(gòu)中。
TSS的結(jié)構(gòu)圖如下:

TSS中的各個(gè)字段主要包括以下兩種:
(一) 動(dòng)態(tài)字段 : 當(dāng)任務(wù)切換的時(shí)候而被掛起的時(shí)候,處理器會(huì)自動(dòng)更新字段的內(nèi)容。 這些字段包括:
(1) 通用寄存器字段。用于保存 EAX ,ECX ,EDX ,EBX,ESP ,EBP,ESI,EDI。
(2) 段選擇符字段 用于保存ES,CS,SS,DS,FS,GS。
(3) 標(biāo)志寄存器EFLAGS 再切換之前保存EFLAGS
(4) 指令指針EIP 字段,在切換之前保存EIP寄存器的內(nèi)容。
(5) 先前任務(wù)連接字段,含有前一個(gè)任務(wù)的TSS段選擇符。該字段允許任務(wù)使用IRET指令切換到前一個(gè)字段。
(二)靜態(tài)字段 :處理器會(huì)讀取靜態(tài)字段的內(nèi)容,但是不會(huì)改變它們。這些任務(wù)內(nèi)容通常是在任務(wù)被創(chuàng)建的時(shí)候設(shè)置的。
(1) LDT段選擇符字段。含有任務(wù)的LDT段的選擇符。
(2)CR3控制寄存器字段。含有任務(wù)使用的頁(yè)目錄物理基地址。
(3) 特權(quán)級(jí)0,1和2的堆棧指針字段。這些堆棧指針由堆棧段選擇符(ss0 , ss1 ,ss2) 和棧中偏移指針(esp0 , esp1 ,esp2)組成。對(duì)于指定的一個(gè)任務(wù),這些字段的值是不會(huì)改變的。
(4)調(diào)試陷阱。
(5)I/O 位圖基地址字段。
5.3.2 TSS描述符
任務(wù)狀態(tài)段TSS也是由段描述符來(lái)描述的,
TSS描述符只能存放在GDT中。
類(lèi)型字段TYPE中的忙標(biāo)志B用于指明任務(wù)是否處于忙狀態(tài)。忙狀態(tài)的任務(wù)是指當(dāng)前正在運(yùn)行的任務(wù)或者等待的任務(wù)。
任務(wù)是不可以遞歸執(zhí)行的,因此處理器使用忙標(biāo)志B來(lái)檢測(cè)任何對(duì)被中斷執(zhí)行的任務(wù)的調(diào)用。
其中基地址、段限長(zhǎng)、描述符特權(quán)級(jí)DPL、顆粒度G和存在位具有與數(shù)據(jù)段描述符中相應(yīng)字段的同樣功能。
使用調(diào)用或者跳轉(zhuǎn)指令,任何可以訪問(wèn)TSS描述符的程序都能夠造成任務(wù)切換。
把TSS描述符加載進(jìn)任何段寄存器將導(dǎo)致一個(gè)異常。
5.3.3 任務(wù)寄存器
任務(wù)寄存器TR中存放
著16位的段選擇符(可見(jiàn)部分)以及當(dāng)前任務(wù)TSS段的整個(gè)描述符(
不可見(jiàn)部分)。這些信息是從GDT中當(dāng)前任務(wù)的TSS描述符中復(fù)制過(guò)來(lái)的。
LTR 和 STR指令分別用于保存和加載TSS描述符中的可見(jiàn)部分,即TSS段的選擇符。
5.3.4 任務(wù)門(mén)描述符
任務(wù)門(mén)描述符提供一個(gè)任務(wù)間接受保護(hù)引用。任務(wù)門(mén)描述符可以存放在 GDT LDT IDT中。
任務(wù)門(mén)描述符中的TSS選擇符字段指向GDT中的一個(gè)TSS段描述符。
5.3.5 任務(wù)切換
處理器可以使用以下4種方式之一執(zhí)行任務(wù)切換操作。
(1) 當(dāng)前任務(wù)對(duì)GDT 中的TSS描述符執(zhí)行JMP 或 CALL 指令。
(2) 當(dāng)前任務(wù)對(duì)GDT和LDT中的任務(wù)門(mén)描述符執(zhí)行JMP和CALL指令。
(3) 中斷或者異常向量指向IDT表中的任務(wù)門(mén)描述符。
(4) 當(dāng)EFLAGS 中的NT標(biāo)志置位時(shí),當(dāng)前任務(wù)執(zhí)行IRET指令。

任務(wù)切換示意圖 如上 。
5.3.6任務(wù)鏈
TSS中的前任務(wù)鏈字段以及EFLAGS中的NT標(biāo)志用于返回到前一個(gè)任務(wù)操作中。NT標(biāo)志指出了當(dāng)前執(zhí)行的任務(wù)是否嵌套在另一個(gè)任務(wù)中執(zhí)行,并且當(dāng)前任務(wù)的前一個(gè)
任務(wù)鏈字段中存放著嵌套層中更高層的TSS選擇符。
當(dāng)使用CALL 指令,中斷或者異常造成任務(wù)切換的時(shí)候,處理器把當(dāng)前TSS段的選擇符復(fù)制到新任務(wù)TSS段的前一任務(wù)鏈字段中,并且在EFLAGS中設(shè)置NT標(biāo)志,NT標(biāo)志指明TSS的前一任務(wù)鏈字段中存放有保存的TSS段選擇符。如果軟件使用了IRET指令掛起新任務(wù),處理器就會(huì)使用前一任務(wù)鏈中的值和NT標(biāo)志返回到前一個(gè)任務(wù)中。
注意如果當(dāng)前任務(wù)的切換是由JMP指令造成的,那么新任務(wù)就不被嵌套。
6 任務(wù)地址空間
任務(wù)的地址空間由任務(wù)能夠訪問(wèn)的段構(gòu)成。這些段包括代碼段、數(shù)據(jù)段、堆棧段、TSS中引用的系統(tǒng)段以及任務(wù)代碼段能夠訪問(wèn)的任何其他段。
TSS中的LDT字段可以用于給出每個(gè)任務(wù)自己的LDT。對(duì)于一個(gè)給定的任務(wù),通過(guò)把任務(wù)相關(guān)的所有段描述符都放入LDT中,任務(wù)的地址空間可以與其他任務(wù)
相隔離。
如果開(kāi)啟了分頁(yè)機(jī)制,則TSS中的CR3寄存器字段可以讓每個(gè)任務(wù)有它自己的頁(yè)表?;蛘撸瑤讉€(gè)任務(wù)能夠共享相同的頁(yè)表集。
(1) 把任務(wù)映射到線性和物理地址空間
所有任務(wù)共享一個(gè)線性到物理地址空間的映射。當(dāng)沒(méi)開(kāi)啟分頁(yè)機(jī)制時(shí),就只能夠使用這個(gè)方法。當(dāng)開(kāi)啟了分頁(yè)機(jī)制,就可以讓所有的任務(wù)使用同一個(gè)頁(yè)目錄的方法
來(lái)實(shí)現(xiàn)。
(2)每個(gè)任務(wù)有自己的線性地址空間,并映射到物理地址空間。
通過(guò)讓每個(gè)任務(wù)使用不同的頁(yè)目錄,我們就可以使用這種映射技術(shù)。
6.1任務(wù)邏輯地址空間
為了在任務(wù)之間共享數(shù)據(jù),可以使用以下方法之一來(lái)為數(shù)據(jù)段建立共享的邏輯到物理地址空間的映射:
(1) 通過(guò)使用GDT中的段描述符,所有任務(wù)必須能夠訪問(wèn)GDT的段描述符,如果GDT中的某些段描述符能夠指向線性地址空間的一些段,并且這些段被映射到所有任務(wù)共享的物理地址空間中,那么所有的任務(wù)都可以共享這些段中的代碼和數(shù)據(jù)。
(2) 通過(guò)共享的LDT。
(3) 通過(guò)映射到線性地址空間公共地址區(qū)域的不同LDT中的段描述符。
這種方式最好。 7 保護(hù)模式編程初始化
7.1 進(jìn)入保護(hù)模式時(shí)的初始化操作
操作系統(tǒng)加載和初始化軟件(bootsect.s setup.s 和 head.s) 必須在內(nèi)存中先設(shè)置好保護(hù)模式下使用的數(shù)據(jù)結(jié)構(gòu)的基本信息。
(1) 保護(hù)模式中斷描述符表IDT。
(2) 任務(wù)狀態(tài)段TSS。
(3) 局部描述符表LDT。
(4) 若使用分頁(yè)機(jī)制,則起碼設(shè)置一個(gè)頁(yè)目錄和一個(gè)頁(yè)表。
(5) 處理器切換到保護(hù)模式下運(yùn)行的代碼段。
(6) 含有中斷和異常處理程序的代碼段。
(7)全局描述符表GDT
在能夠切換到保護(hù)模式之前,初始化代碼還必須設(shè)置以下系統(tǒng)寄存器。
(1) 全局描述符表基地址 寄存器GDTR 。
(2) 中斷描述符表基地址寄存器 IDTR 。
(3) 控制寄存器CR1- CR3。
在初始化了這些數(shù)據(jù)結(jié)構(gòu)、代碼模塊和系統(tǒng)寄存器之后,通過(guò)設(shè)置CR0寄存器的保護(hù)模式標(biāo)志位PE(位0),處理器就會(huì)切換到保護(hù)模式下運(yùn)行。
7.2 保護(hù)模式系統(tǒng)結(jié)構(gòu)表
LDT表的段描述符還要求存放在GDT表中。軟件初始化代碼必須設(shè)置一個(gè)保護(hù)模式IDT,其中最少需要含有處理器可能產(chǎn)生的每個(gè)異常向量對(duì)應(yīng)的門(mén)描述符,
在使用IDT之前,必須使用LIDT指令把IDT表的基地址和長(zhǎng)度加載到IDTR寄存器中。
分頁(yè)機(jī)制初始化 : 分頁(yè)機(jī)制由控制寄存器CR0中的PG標(biāo)志位設(shè)置。當(dāng)設(shè)置PG標(biāo)志之前,必須先初始化以下數(shù)據(jù)結(jié)構(gòu)和寄存器:
(1) 軟件必須在物理內(nèi)存中建立至少一個(gè)頁(yè)目錄和一個(gè)頁(yè)表。
(2) 把頁(yè)目錄表的物理基地址加載到CR3寄存器中。
(3) 處理器處于保護(hù)模式下,如果滿(mǎn)足其他限制,則PG和PE標(biāo)志可以同時(shí)設(shè)置。
多任務(wù)初始化:
在處理器切換到保護(hù)模式之后,使用LTR指令將TSS段描述符的選擇符加載到任務(wù)寄存器TR中,這個(gè)指令會(huì)把TSS標(biāo)記成忙狀態(tài),但是并不是執(zhí)行任務(wù)切換。
然后處理器可以使用這個(gè)TSS來(lái)定位特權(quán)級(jí)0 , 1 ,2 的堆棧,在保護(hù)模式中,軟件進(jìn)行第一次任務(wù)切換之前必須首先加載TSS段的選擇符,因?yàn)槿蝿?wù)切換
會(huì)把當(dāng)前任務(wù)狀態(tài)復(fù)制到TSS中。
7.3 模式切換
7.3.1 切換到保護(hù)模式
(1) 禁止中斷。使用CLI 指令禁止了可屏蔽硬件中斷。
(2) LGDT 指令把GDT表的基地址加載進(jìn)GDTR寄存器。
(3) 執(zhí)行在控制寄存器中CR0 ,設(shè)置PE標(biāo)志的MOV CR0指令。
(4) 在MOV CR0 之后,立刻執(zhí)行一個(gè)遠(yuǎn)跳轉(zhuǎn)JMP 或遠(yuǎn)調(diào)用CALL指令。
(5) 若要使用局部描述符表,則執(zhí)行LLDT指令把LDT段的選擇符加載到LDTR寄存器中。
(6) 執(zhí)行LTR指令,用初始保護(hù)模式任務(wù)的段選擇符或者可寫(xiě)內(nèi)存區(qū)域的段描述符加載到任務(wù)寄存器TR中。
(7) 執(zhí)行LIDT指令把保護(hù)模式IDT表的基地址和長(zhǎng)度加載到IDTR寄存器中。
(8) 執(zhí)行STI指令開(kāi)啟可屏蔽硬件中斷,并且執(zhí)行必要的硬件操作開(kāi)啟NMI中斷。
7.3.2 換回實(shí)地址模式
若想切換回實(shí)地址模式,則可以使用MOV CR0 指令把控制寄存器CR0中的PE標(biāo)志位清 0 。
(1) 禁止中斷。
(2) 如果已經(jīng)開(kāi)啟分頁(yè)機(jī)制,那么需要執(zhí)行
把程序的控制轉(zhuǎn)移到對(duì)等映射的線性地址處。
確保GDT和IDT在對(duì)等映射的頁(yè)面上。
清除CR0中斷的PG標(biāo)志 。
CR3寄存器設(shè)置為0x00,用于刷新新TLB緩沖。
(3) 把程序的控制轉(zhuǎn)移到長(zhǎng)度為64kb的可讀段中。
(4) 使用特定的值來(lái)設(shè)置加載SS , DS , ES , FS ,GS 段寄存器。
(5) 執(zhí)行LIDT指令來(lái)指向在1MB實(shí)模式地址范圍的實(shí)地址模式中斷表。
(6) 清除CR0中的PE標(biāo)志來(lái)切換到實(shí)地址模式。
(7) 執(zhí)行一個(gè)遠(yuǎn)跳轉(zhuǎn)指令到一個(gè)實(shí)模式程序中。
(8) 加載實(shí)地址模式程序代碼會(huì)使用的SS , DS , ES ,FS ,GS。
(9) STI 開(kāi)啟硬件中斷。