中斷和異常處理
中斷和異常是指明系統、處理器、或當前執行程序的某處出現一個事件,該事件需要處理器進行處理。通常,這種事件會導致執行控制被強迫從當前運行的程序轉移到被稱為中斷處理程序或異常處理程序。
1 異常和中斷向量
每個需要被處理器進行特殊處理的處理器定義的異常和中斷條件都被賦予一個表示號,稱為向量(vector)。 處理器把賦予異常或中斷的向量
用作中斷的處理程序入口地點位置。
2 中斷描述符表
該表將每個異常或者中斷的向量號同它們的處理過程聯系起來。IDT也是由8字節長的描述符組成的一個描述符表。
指令LIDT和SIDT 指令分別用于加載和保存IDTR寄存器的內容。
3 IDT描述符
中斷門和陷阱門含有一個長指針(即段選擇符和偏移值),處理器用這個長指針把程序執行權轉移到代碼段中異常或中斷的處理過程中。
任務門描述符中有一個任務TSS段的任務選擇符,該任務用于處理異常和中斷。
4 異常和中斷處理

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

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

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