每個任務有一個任務狀態段TSS,用於保存任務的有關信息,在任務內變換特權級和任務切換時,要用到這些信息。為了控制任務內發生特權級變換的轉移,為了控制任務切換,一般要通過控制門進行這些轉移。本文將介紹任務狀態段和控制門。
<一>系統段描述符
系統段是為了實現存儲管理機制所使用的一種特別的段。在80386中,有兩種系統段:任務狀態段TSS和局部描述符表LDT段。用於描述系統段的描述符稱為系統段描述符。
1.系統段描述符的格式
系統段描述符的一般格式如下表所示。
系統段與存儲段描述符相比,它們很相似,區分的標志是屬性字節中的描述符類型位DT的值。DT=1表示存儲段,DT=0表示系統段。系統段描述符中的段基地址和段界限字段與存儲段描述符中的意義完全相同;屬性中的G位、AVL位、P位和DPL字段的作用也完全相同。存儲段描述符屬性中的D位在系統段描述符中不使用,現用符號X表示。系統段描述符的類型字段TYPE仍是4位,其編碼及表示的類型列於下表,其含義與存儲段描述符的類型卻完全不同。
系統段從上表可見,只有類型編碼為2、1、3、9和B的描述符才是真正的系統段描述符,它們用於描述系統段LDT和任務狀態段TSS,其它類型的描述符是門描述符。利用前文定義的存儲段描述符結構類型DESC仍能方便地在程序中說明系統段描述符。需要注意的是,系統段描述符的選擇子不能用來讀寫系統段,要想讀寫系統段,必須使用別名技術。
2.LDT段描述符
LDT段描述符描述任務的局部描述符表段。例如:下面的描述符LDTABLE描述一個局部描述符表段,基地址是654321H,以字節為單位的界限是1FH,描述符特權級是0。
LDTABLE DESC <1FH,4321H,65H,82H,,>
LDT段描述符必須安排在全局描述符表中才有效。在裝載LDTR寄存器時,描述符中的LDT段基地址和段界限等信息被裝入LDT段描述符高速緩沖寄存器中。
3.任務狀態段描述符
任務狀態段TSS用於保存任務的各種狀態信息。任務狀態段描述符描述某個任務狀態段TSS描述符分為286TSS和386TSS兩類。TSS描述符規定了任務狀態段的基地址和任務狀態段的大小等信息。例如,下面的描述符TempTask描述一個可用的386任務狀態段,基地址是123456H,以字節為單位的界限是104,描述符特權級是0。
TempTask DESC <104,3456H,12H,89H,,>
在裝載任務狀態段寄存器TR時,描述符中的段基地址和段界限等信息被裝入到TR的高速緩沖寄存器中。在任務切換或執行LTR指令時,要裝載TR寄存器。
TSS描述符中的類型規定:TSS要麼為“忙”,要麼為“可用”。如果一個任務是當前正執行的任務,或者是用TSS中的鏈接字段沿掛起任務鏈接到當前任務上的任務,那麼該任務是“忙”的任務;否則該任務為“可用”任務。
利用段間轉移指令JMP和段間調用指令CALL,直接通過TSS描述符或通過任務門可實現任務切換。
<二>門描述符
除存儲段描述符和系統段描述符外,還有一類門描述符。門描述符並不描述某種內存段,而是描述控制轉移的入口點。這種描述符好比一個同向另一代碼段的門。通過這種門,可實現任務內特權級的變換和任務間的切換。所以,這種門描述符也稱為控制門。
1.門描述符的一般格式
門描述符的一般格式如下圖所示。門描述符只有位於描述符內偏移5的類型字節與系統段保持一致,也由該字節標示門描述符和系統段描述符。該字節內的P和DPL的意義與其它描述符種中的意義相同。其它字節主要用於存放一個48位的全指針(16位的選擇子和32位的偏移量)。
門描述符 m+7 m+6 m+5 m+4 m+3 m+2 m+1 m+0 Offset(31...16) Attributes Selector Offset(15...0) 門描述根據上圖給出的門描述符的結構,可定義如下的門描述符結構類型:
GATE STRUC ;門結構類型定義 OFFSETL DW 0 ;32位偏移的低16位 SELECTOR DW 0 ;選擇子 DCOUNT DB 0 ;雙字計數字段 GTYPE DB 0 ;類型 OFFSETH DW 0 ;32位偏移的高16位 GATE ENDS
利用門描述符結構類型GATE能方便地在程序中說明門描述符。例如,下面的門描述符SUBRG描述一個386調用門,門內的選擇子是10H,入口偏移是123456H,門描述符特權級是3,雙字計數是0。
SUBRG GATE <3456,10H,,8CH+60H,12H>
從上述描述符類型的列表中可見,門描述符又可分為:任務門、調用門、中斷門和陷阱門,並且除任務門外,其它描述符還各分成286和386兩種。
2.調用門
調用門描述某個子程序的入口。調用門內的選擇子必須實現代碼段描述符,調用門內的偏移是對應代碼段內的偏移。利用段間調用指令CALL,通過調用門可實現任務內從外層特權級變換到內層特權級。
在上圖所示的門描述符內偏移4字節的位0至位4是雙字計數字段,該字段只在調用門描述符中有效,在其它門描述符中無效。主程序通過堆棧把入口參數傳遞給子程序,如果在利用調用門調用子程序時引起特權級的轉換和堆棧的改變,那麼就需要將外層堆棧中的參數復制到內層堆棧。該雙字計數字段就是用於說明這種情況發生時,要復制的雙字參數的數量。
3.任務門
任務門指示任務。任務門內的選擇子必須指示GDT中的任務狀態段TSS描述符,門中的偏移無意義。任務的入口點保存在TSS中。利用段間轉移指令JMP和段間調用指令CALL,通過任務門可實現任務切換。
4.中斷門和陷阱門
中斷門和陷阱門描述中斷/異常處理程序的人口點。中斷門和陷阱門內的選擇子必須指向代碼段描述符,門內的偏移就是對應代碼段的人口點的偏移。中斷門和陷阱門只有在中斷描述符表IDT中才有效。關於中斷門和陷阱門的區別將在以後的文章中論述。
<三>任務狀態段
任務狀態段(Task State Segment)是保存一個任務重要信息的特殊段。任務狀態段描述符用於描述這樣的系統段。任務狀態段寄存器TR的可見部分含有當前任務的任務狀態段描述符的選擇子,TR的不可見的高速緩沖寄存器部分含有當前任務狀態段的段基地址和段界限等信息。TSS在任務切換過程中起著重要作用,通過它實現任務的掛起和恢復。所謂任務切換是指,掛起當前正在執行的任務,恢復或啟動另一任務的執行。在任務切換過程中,首先,處理器中各寄存器的當前值被自動保存到TR所指定的TSS中;然後,下一任務的TSS的選擇子被裝入TR;最後,從TR所指定的TSS中取出各寄存器的值送到處理器的各寄存器中。由此可見,通過在TSS中保存任務現場各寄存器狀態的完整映象,實現任務的切換。任務狀態段TSS的基本格式如下圖所示。
任從圖中可見,TSS的基本格式由104字節組成。這104字節的基本格式是不可改變的,但在此之外系統軟件還可定義若干附加信息。基本的104字節可分為鏈接字段區域、內層堆棧指針區域、地址映射寄存器區域、寄存器保存區域和其它字段等五個區域。
1.寄存器保存區域
寄存器保存區域位於TSS內偏移20H至5FH處,用於保存通用寄存器、段寄存器、指令指針和標志寄存器。當TSS對應的任務正在執行時,保存區域是未定義的;在當前任務被切換出時,這些寄存器的當前值就保存在該區域。當下次切換回原任務時,再從保存區域恢復出這些寄存器的值,從而,使處理器恢復成該任務換出前的狀態,最終使任務能夠恢復執行。
從上圖可見,各通用寄存器對應一個32位的雙字,指令指針和標志寄存器各對應一個32位的雙字;各段寄存器也對應一個32位的雙字,段寄存器中的選擇子只有16位,安排再雙字的低16位,高16位未用,一般應填為0。
2.內層堆棧指針區域
為了有效地實現保護,同一個任務在不同的特權級下使用不同的堆棧。例如,當從外層特權級3變換到內層特權級0時,任務使用的堆棧也同時從3級變換到0級堆棧;當從內層特權級0變換到外層特權級3時,任務使用的堆棧也同時從0級堆棧變換到3級堆棧。所以,一個任務可能具有四個堆棧,對應四個特權級。四個堆棧需要四個堆棧指針。
TSS的內層堆棧指針區域中有三個堆棧指針,它們都是48位的全指針(16位的選擇子和32位的偏移),分別指向0級、1級和2級堆棧的棧頂,依次存放在TSS中偏移為4、12及20開始的位置。當發生向內層轉移時,把適當的堆棧指針裝入SS及ESP寄存器以變換到內層堆棧,外層堆棧的指針保存在內層堆棧中。沒有指向3級堆棧的指針,因為3級是最外層,所以任何一個向內層的轉移都不可能轉移到3級。
但是,當特權級由內層向外層變換時,並不把內層堆棧的指針保存到TSS的內層堆棧指針區域。實際上,處理器從不向該區域進行寫入,除非程序設計者認為改變該區域的值。這表明向內層轉移時,總是把內層堆棧認為是一個空棧。因此,不允許發生同級內層轉移的遞歸,一旦發生向某級內層的轉移,那麼返回到外層的正常途徑是相匹配的向外層返回。
3.地址映射寄存器區域
從虛擬地址空間到線性地址空間的映射由GDT和LDT確定,與特定任務相關的部分由LDT確定,而LDT又由LDTR確定。如果采用分頁機制,那麼由線性地址空間到物理地址空間的映射由包含頁目錄表起始物理地址的控制寄存器CR3確定。所以,與特定任務相關的虛擬地址空間到物理地址空間的映射由LDTR和CR3確定。顯然,隨著任務的切換,地址映射關系也要切換。
TSS的地址映射寄存器區域由位於偏移1CH處的雙字字段(CR3)和位於偏移60H處的字字段(LDTR)組成。在任務切換時,處理器自動從要執行任務的TSS中取出這兩個字段,分別裝入到寄存器CR3和LDTR。這樣就改變了虛擬地址空間到物理地址空間的映射。
但是,在任務切換時,處理器並不把換出任務但是的寄存器CR3和LDTR的內容保存到TSS中的地址映射寄存器區域。事實上,處理器也從來不向該區域自動寫入。因此,如果程序改變了LDTR或CR3,那麼必須把新值人為地保存到TSS中的地址映射寄存器區域相應字段中。可以通過別名技術實現此功能。
4.鏈接字段
鏈接字段安排在TSS內偏移0開始的雙字中,其高16位未用。在起鏈接作用時,地16位保存前一任務的TSS描述符的選擇子。
如果當前的任務由段間調用指令CALL或中斷/異常而激活,那麼鏈接字段保存被掛起任務的 TSS的選擇子,並且標志寄存器EFLAGS中的NT位被置1,使鏈接字段有效。在返回時,由於NT標志位為1,返回指令RET或中斷返回指令IRET將使得控制沿鏈接字段所指恢復到鏈上的前一個任務。
5.其它字段
為了實現輸入/輸出保護,要使用I/O許可位圖。任務使用的I/O許可位圖也存放在TSS中,作為TSS的擴展部分。在TSS內偏移66H處的字用於存放I/O許可位圖在TSS內的偏移(從TSS開頭開始計算)。關於I/O許可位圖的作用,以後的文章中將會詳細介紹。
在TSS內偏移64H處的字是為任務提供的特別屬性。在80386中,只定義了一種屬性,即調試陷阱。該屬性是字的最低位,用T表示。該字的其它位置被保留,必須被置為0。在發生任務切換時,如果進入任務的T位為1,那麼在任務切換完成之後,新任務的第一條指令執行之前產生調試陷阱。
6.用結構類型定義TSS
根據上圖給出的任務狀態段TSS的結構,可定義如下的TSS結構類型:
;---------------------------------------------------------------------------- ;任務狀態段結構類型定義 ;---------------------------------------------------------------------------- TSS STRUC TRLink DW 0 ;鏈接字段 DW 0 ;不使用,置為0 TRESP0 DD 0 ;0級堆棧指針 TRSS0 DW 0 ;0級堆棧段寄存器 DW 0 ;不使用,置為0 TRESP1 DD 0 ;1級堆棧指針 TRSS1 DW 0 ;1級堆棧段寄存器 DW 0 ;不使用,置為0 TRESP2 DD 0 ;2級堆棧指針 TRSS2 DW 0 ;2級堆棧段寄存器 DW 0 ;不使用,置為0 TRCR3 DD 0 ;CR3 TREIP DD 0 ;EIP TREFlag DD 0 ;EFLAGS TREAX DD 0 ;EAX TRECX DD 0 ;ECX TREDX DD 0 ;EDX TREBX DD 0 ;EBX TRESP DD 0 ;ESP TREBP DD 0 ;EBP TRESI DD 0 ;ESI TREDI DD 0 ;EDI TRES DW 0 ;ES DW 0 ;不使用,置為0 TRCS DW 0 ;CS DW 0 ;不使用,置為0 TRSS DW 0 ;SS DW 0 ;不使用,置為0 TRDS DW 0 ;DS DW 0 ;不使用,置為0 TRFS DW 0 ;FS DW 0 ;不使用,置為0 TRGS DW 0 ;GS DW 0 ;不使用,置為0 TRLDTR DW 0 ;LDTR DW 0 ;不使用,置為0 TRTrip DW 0 ;調試陷阱標志(只用位0) TRIOMap DW ___FCKpd___42 ;指向I/O許可位圖區的段內偏移 TSS ENDS