《80X86匯編語言程序設計教程》十二 任務狀態段、控制門和控制轉移
1、 每個任務有一個任務狀態段TSS,用於保存相關信息,以便在任務內變化特權級和任務切換時使用。控制任務內特權級變換的轉移以及控制各個任務的切換,都需要通過控制門。
2、 系統描述符
在之前介紹存儲段描述符的時候曾提過,描述符分為3種:存儲段描述符、系統段描述符、門描述符(控制描述符),這裏將介紹到接下來的兩種。
系統段是為了實現存儲管理機制所使用的一種特別的段,80386有兩種系統段:任務狀態段TSS和局部描述符表LDT段。用於描述系統段的描述符又叫系統描述符,也被稱為特殊段描述符。
1) 系統段描述符的一般格式
m + 7 |
m + 6 |
m + 5 |
m + 4 |
m + 3 |
m + 2 |
m + 1 |
m |
Base 31…24 |
Attributes |
Segment Base 23…0 |
Segment Limit 15…0 |
其中段屬性Attributes具體內容如下:
m + 6 |
m + 5 |
||||||||||||||
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
G |
X |
0 |
AVL |
Limit(19…16) |
P |
DPL |
DT |
TYPE |
|||||||
它與存儲段描述符很相像,標識位是DT,當DT = 1的時候是存儲段描述符,而當DT = 0的時候是系統段描述符。其中X位不用,在存儲段描述符中對應於D位。除了TYPE表達的類型意義不一樣以外,其它的各個域都與存儲段描述符一致(參考“《80X86匯編語言程序設計教程》九 分段管理機制及純DOS環境搭建”)。TYPE域各值對應意義如下:
類型編碼 |
說明 |
類型編碼 |
說明 |
0 |
未定義 |
8 |
未定義 |
1 |
可用286TSS |
9 |
可用386TSS |
2 |
LDT |
A |
未定義 |
3 |
忙的286TSS |
B |
忙的386TSS |
4 |
286調用門 |
C |
386調用門 |
5 |
任務門 |
D |
未定義 |
6 |
286中斷門 |
E |
386中斷門 |
7 |
286陷阱門 |
F |
386陷阱門 |
可見,只有編碼為1、2、3、9、B的描述符才是真正的系統段描述符(LDT或者TSS),其它類型描述符是門描述符(可見,通過DT位,可以判斷是否為存儲段描述符,如果DT=0,則則根據TYPE進一步確定具體是哪種門描述符還是哪種系統段描述符)。在系統描述符中,只有2(LDT)、9(可用386TSS)、B(忙的TSS)用於386。
2) LDT段描述符
用於描述任務的局部描述符表段,LDT段描述符必須安排在GDT中才有效,在裝載LDTR寄存器時,描述符中的LDT段基址和段界限等信息裝入LDTR的高速緩沖寄存器中。更詳細參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎”的“系統地址寄存器”中關於“局部描述符表寄存器LDTR”的介紹,簡要說明了LDTR、如何轉載它以及它對應的高速緩沖寄存器的相關內容。
LDT描述符結構類型可定義如下:
1 DESCRIPTOR struct 2 LimitL dw 0 ;段界限低16位 3 BaseL dw 0 ;基地址低16位 4 BaseM db 0 ;基地址中間8位 5 Attributes dw 0 ;段屬性(含段界限高4位) 6 BaseH db 0 ;基地址高8位 7 DESCRIPTOR ends
3) TSS描述符
用於保存任務的各種狀態信息。TSS描述符規定當前任務狀態段的基地址與任務狀態段的大小。在裝載任務狀態寄存器TR時,描述符中的TSS段基地址和段界限等信息被載入TR對應的高速緩沖寄存器中。在任務切換或執行LTR指令時,要裝載TR寄存器。參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎” 的“系統地址寄存器”中關於“任務狀態段寄存器TR”的介紹。
TSS中的類型規定,TSS要麽為“忙”,要麽為“可用”。如果一個任務是當前正執行的任務,或者是用TSS中的鏈接字段沿掛起任務鏈接到當前任務上的任務,那麽該任務就是“忙”的任務,否則為“可用”任務。利用段間轉移指令JMP和段間調用指令CALL,直接通過TSS描述可實現任務切換。任務狀態段以及TSS描述符結構類型定義後續。
3、 門描述符
描述的不是內存段,而是控制轉移的入口點。好比一個通向另一代碼段的門,通過門,可以實現任務內特權級的變換和任務間的切換,因此門描述符也叫做控制門。它們存在於GDT中。
1) 門描述符的一般格式
m + 7 |
m + 6 |
m + 5 |
m + 4 |
m + 3 |
m + 2 |
m + 1 |
m |
Offset 31…16 |
Attributes |
selector |
Offset 15…0 |
其中段屬性Attributes具體內容如下:
m + 5 |
m + 4 |
||||||||||||||
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
P |
DPL |
DT |
TYPE |
0 0 0 |
Dword Count |
||||||||||
其中偏移字節5與系統段描述符保持一致,selector是16位選擇子,而offset是32位的偏移量。DT = 0。TYPE的值從上面的TYPE表格中取,可選值為4、5、6、7、C、E、F,其中386可取5、C、E、F。從表中可看到,門分為:調用門、任務門、中斷門、陷阱門
門描述符結構類型可定義如下:
1 GATE struct 2 OffsetL dw 0 ;偏移量(0~15) 3 Selector dw 0 ;選擇子 4 Dcount db 0 ;雙字計數字段 5 GType db 0 ;門類型 6 OffsetH dw 0 ;偏移量(16~31) 7 GATE ends
2) 調用門
DT = 0且TYPE = 4(286調用門)或者TYPE = C(386調用門)。描述某個子程序入口(相當於一個訪問接口,保存了一個局部入口地址與若幹屬性)。調用門內的選擇子必須指向代碼段描述符,調用門內的偏移是對應代碼段內的偏移。利用段間調用指令CALL,可通過調用門實現從任務內外層特權級切換到內層特權級。“Dword Count”字段只在調用門中有效,傳輸傳遞時,如果需要特權等級切換,就要將外層堆棧中的參數復制到內存堆棧。該雙字用於說明要復制的雙字參數的數量。
3) 任務門
用於指示任務。其選擇子必須指向GDT中的任務狀態段TSS描述符,門中的偏移沒有意義。任務的入口點保存在TSS中。利用段間轉移指令JMP和段間調用指令CALL,通過任務門可實現任務切換。
4) 中斷門和陷阱門
描述中斷/異常處理程序的入口點。選擇子必須指向代碼段描述符,門內的偏移就是對應代碼段的入口點偏移。中斷門和陷阱門只有在中斷描述符表IDT中才生效。
4、 任務狀態段
TSS(Task State Segment)用於保存任務重要信息的特殊段,使用TSS描述符來描述。TR可見的16位部分含有當前任務的任務狀態段描述符的選擇子,TR不可見部分含有當前任務狀態段的段基址和段界限等信息。
TSS在任務的切換(掛起和恢復)起重要作用,切換時,首先處理器將當前相關信息自動保存到TR所指定的TSS中(現場保護),然後下一個任務的TSS選擇子裝載入TS,最後根據TS指定的TSS中讀取下一個任務在上次保存的信息(現場恢復)。TSS格式如下:
區域 |
31~16 |
15~0 |
偏移 |
|
鏈接字段 |
0000000000000000 |
鏈接字段 |
00H |
|
內存堆棧指針區域
|
ESP0 |
04H |
||
000000000000000 |
SS0 |
08H |
||
ESP1 |
0CH |
|||
000000000000000 |
SS1 |
10H |
||
ESP2 |
14H |
|||
000000000000000 |
SS2 |
18H |
||
地址映射寄存器區域 |
CR3 |
1CH |
||
寄存器保存區域
|
EIP |
20H |
||
EFLAGS |
24H |
|||
EAX |
28H |
|||
ECX |
2CH |
|||
EDX |
30H |
|||
EBX |
34H |
|||
ESP |
38H |
|||
EBP |
3CH |
|||
ESI |
40H |
|||
EDI |
44H |
|||
000000000000000 |
ES |
48H |
||
000000000000000 |
CS |
4CH |
||
000000000000000 |
SS |
50H |
||
000000000000000 |
DS |
54H |
||
000000000000000 |
FS |
58H |
||
000000000000000 |
GS |
5CH |
||
地址映射寄存器區域 |
000000000000000 |
LDT |
60H |
|
其它字段 |
I/O許可位圖I偏移 |
00000000000000 |
T |
64H |
TSS基本格式有104個字節,分為鏈接字段、內存堆棧指針區域、地址映射寄存器區域、寄存器保存區域、地址映射寄存器和其它字段5個區域。
1) 寄存器保存區域
TSS正在進行時,該區域未定義,在切換任務時用來保護各個寄存器。下次切換回任務時,再從中恢復各個寄存器的值。
2) 內存堆棧指針區域
保護一個任務在不同特權等級下使用的不同堆棧。特權級0~特權級2分別對應SS0:ESP0~SS2:ESP2,最外層特權級3的堆棧信息已經在寄存器保存區域中的SS:ESP中保存。一個任務可能有4個特權級的代碼,在代碼特權級切換時堆棧做相應的切換。在向內層轉移時,內存堆棧總是被認為是一個空棧,內層堆棧指針裝載到SS:ESP,而外層原來的堆棧指針被暫存到內層堆棧中。由內層轉移到外層時,從堆棧中取出外層堆棧指針並進行恢復。
3) 地址映射寄存器區域
由虛擬地址空間到線性地址空間的映射由GDT和LDT確定,GDT整個系統只有一張表,起始地址被保存在GDTR寄存器中,而LDT每個任務可以有一張表(也可以沒有),選擇子被保存在LDTR中,在任務切換時(或者初始化時)系統自動查表。如果沒有開啟分頁機制(CR0中的PG位為0),那麽線性地址就是物理地址;如果開啟了分頁機制,那麽線性地址轉換為物理地址通過分頁管理機制實現,每個任務有自己獨立的一套頁表,頁表分為2級,一級頁表也叫目錄表,它的起始物理地址被保存到CR3中(唯一一個存放物理地址的寄存器),所以線性地址空間到物理地址空間的映射由LDTR和CR3確定(具體的轉換步驟參考“《天書夜讀:從匯編語言到windows內核編程》十四 CPU權限級與分頁機制”)。任務切換時,處理器自動從TSS中取出CR3和LDTR的值裝載到相應寄存器,從而確定了每個任務各自不同的虛擬空間到物理空間的映射。需要註意的是:在切換任務前的保護現場過程中,處理器並不會自動將當前的CR3與LDTR保存到TSS的地址映射寄存器區域,所以,如果程序改動了它們的值,程序要自行負責保存它們到地址映射寄存器區域。
4) 鏈接字段
鏈接字段起鏈接作用,低16位保存前一個任務的TSS描述符的選擇子。如果當前任務由段間調用指令CALL或者中斷/異常而激活,那麽鏈接字段保存被掛起任務TSS選擇子,而且EFLAGS中的NT位(14位,嵌套任務標誌)被置1,使鏈接字段有效。返回時,由於NT位為1,中斷返回指令IRET將使得控制沿著鏈接字段所指恢復到鏈上的上一個任務。
5) 其它字段
I/O許可位圖位用於實現輸入/輸出保護,作為TSS的擴展部分存在,關於它的詳細介紹後續。T位為調試陷阱位,該字的其他位被保留,必須被置為0,在發生任務切換時,如果T = 1,那麽任務切換完成後,新任務的第一條指令執行前將產生調試陷阱。
6) 用結構類型定義TSS
TSS描述符結構類型可定義如下:
1 TASKSS struct 2 TRLink dw ?,0 ;鏈接字 3 TRESP0 dd ? ;0級堆棧指針 4 TRSS0 dw ?,0 ; 5 TRESP1 dd ? ;1級堆棧指針 6 TRSS1 dw ?,0 ; 7 TRESP2 dd ? ;2級堆棧指針 8 TRSS2 dw ?,0 ; 9 TRCR3 dd ? ; CR3 10 TEIP dd ? ;EIP 11 TREFLAGES dw ?,? ;EFLAGS 12 TREAX dd ? ;EAX 13 TRECX dd ? ;ECX 14 TREDX dd ? ;EDX 15 TREBX dd ? ;EBX 16 TRESP dd ? ;ESP 17 TREBP dd ? ;EBP 18 TRESI dd ? ;ESI 19 TREDI dd ? ;EDI 20 TRES dw ?,0 ;ES 21 TRCS dw ?,0 ;CS 22 TRSS dw ?,0 ;SS 23 TRDS dw ?,0 ;DS 24 TRFS dw ?,0 ;FS 25 TRGS dw ?,0 ;GS 26 TRLDT dw ?,0 ;LDT 27 TRFLAG dw 0 ;TSS的特別屬性字 28 TRTRAP dw 0 ;調試陷阱標誌(只用位0) 29 TRIOMAP dw $+2 ;指向I/O許可位圖的指針 30 TASKSS ends
5、 控制轉移
可分為兩類:同一任務內的控制轉移和任務間的控制轉移(任務切換)。同一任務內的控制轉移又分為:段內轉移、特權級不變的段間轉移、特權級變化的段間轉移。與實模式相似,JMP、CALL可分為段間直接轉移(指令中直接含有目標地址指針)與段間間接轉移(指令中含有指向包含目標地址指針的門描述符或者TSS描述符的指針---此時選擇子有效,偏移無效),實際上,當指令中的選擇子部分指示的是代碼段描述符,那麽就是段間直接轉移(描述符中的段基址與指令中的偏移部分共同表示目標代碼入口點);當選擇子指示的是門描述符或TSS描述符時,就是段間間接轉移(入口地址的段基址與偏移包含在對應的描述符中)。向目標代碼段轉移的一般步驟如下:
a)判斷目標地址指針內的段選擇子是否為空描述符,如果為空,且TI = 0(即前14位為0),那麽指向了GDT的第0個描述符,引發保護異常。
b)從GDT或者LDT表中讀出目標代碼段描述符。
c)檢測描述符類型是否正確(包括目標地址是不是為代碼段描述符、門描述符或者TSS描述符),根據情況選擇調整或者不調整RPL---請求特權等級,段選擇子最低2位(比如說在調用門中就會將RPL調整為0)。
d)把目標代碼段描述符內的有關內容裝載到CS高速緩沖寄存器中,根據情況類似裝載其它段描述符到對應高速緩沖寄存器中。進行保護檢測(或者說特權檢測,保護檢測的情況比較復雜,各種不同的情況檢測的條件不同)。
e)判斷目標地址指針內偏移量是否越界(根據段界限Limit判斷,具體參考“《80X86匯編語言程序設計教程》九 分段管理機制及純DOS環境搭建”中關於段界限的介紹)
f)裝載CS段寄存器(此時CPL = 段選擇子的RPL)和指令指針寄存器EIP;根據情況跳轉前CPL存入或者不存入CS內選擇子的RPL字段(存入,則將跳轉前CPL覆蓋當前段選擇子RPL,實現無權限等級變換的轉移)。
以上的一般步驟主要有幾個變數,它們在不同情況下會執行不同的操作:一個是RPL是否調整,一個是檢測保護的具體機制、還有一個是CPL是否裝載的問題。這些具體分支判斷步驟根據具體情況各不相同,特別是保護檢測部分。在開始介紹控制轉移前,須明確幾個概念,接下來的內容將圍繞著它們:
a)CPL(Current Priviliege Level):代表了當前代碼段的特權等級,存在於CS段選擇子的最低2位。通常情況下是程序當前執行代碼所在段的特權級。CPL = CS.RPL。
b)DPL(Descriptor Priviliege Level):表示段或者門的特權等級。它存儲在段或者門描述符的DPL字段中。當當前代碼段試圖訪問一個段或者門時,DPL將會和CPL以及RPL作比較,根據段或者門類型的不同,DPL將會被區別對待:
i)在數據段描述符中:DPL規定了訪問該數據段的最外層特權級。一般要求CPL<=DPL,RPL<=DPL才能訪問。
ii)在代碼段描述符中:DPL規定了執行該代碼段所須的CPL。要求比較復雜,分一致代碼段和非一致代碼段,jmp指令與call指令的區別,具體見“任務內不同特權級的變換”。
iii)在調用門和任務門描述符中:DPL規定了訪問門的最外層特權級。要求同數據段描述符。
iv)在任務狀態段(TSS)描述符中:DPL規定訪問TSS的最外層權限級。要求同數據段描述符。
c)RPL(Requested Priviliege Level):表示請求特權級,存在於段選擇子的最低2位。RPL是對於段選擇子而言的,段選擇子中的段描述符索引相同時,總是可以索引到同一個段,這類具有相同索引而不同RPL的段選擇子,其中的RPL就代表了它們各自請求特權級,到底允不允許被調用,這個由CPL以及RPL和DPL的關系來決定。所以,它一般用於特權檢查。特別是在切入內層一致代碼段後的返回時,為了保證特權級不變,必須使用到RPL。
此外,在任務內代碼權限等級轉移時,有如下定律:
a)所有跳轉,CPU不會將選擇子的RPL直接賦值給跳轉後程序的CPL(CS.RPL)
b)對於無特權級變換的轉移,跳轉後CPL(CS.RPL) = 跳轉前CPL(CS.RPL)
c)對於有特權級變換的轉移,跳轉後CPL(CS.RPL) = 跳轉後CS段描述符中的DPL
各種轉移在一般步驟上的具體區別如下:
1) 任務內無特權級變換的轉移
各種段內轉移與實方式下相似,不涉及特權等級和任務切換。而段間無特權變換的轉移是指:在轉移到新的代碼段時,當前的CPL保存不變(一般步驟中的第6點中CPL存入CS選擇子的RPL字段,從而使CPL保持不變)。
a)段間轉移指令
同實模式,JMP、CALL、RET、INT(總是)、IRET(總是)都可引起段間轉移,中斷/異常也將引起段間轉移。32位實模式的段間轉移總是使用48位全指針(16位段選擇子+32位段內偏移)。
b)利用段間直接轉移指令JMP或CALL
表示指令中地址指針指示的是一個代碼段描述符的情況,CALL與JMP區別在於是否將返回地址壓入堆棧,除了這個區別,它們都是直接開始上面的一般轉移步驟。其中,除了第6步不調整CPL外,還有第3步中不調整RPL。由此可見,利用它們不能進行任務內特權等級變換的轉移。
c)利用段間返回指令RET
表示從堆棧段彈出的地址指針指示的是一個代碼段且目標代碼段RPL = 當前CPL的情況,通常段間返回指令RET與段間調用指令CALL對應,由於調用時沒有特權等級的變化,那麽返回時也一定沒有特權等級的變換,所以必定滿足RPL = CPL(CS.RPL)。
d)利用調用門和其它途徑
利用調用門的情況在本章的“任務內不同特權級的變換”一節中介紹,而其它途徑在“《80x86匯編》十六 80386的中斷和異常”中介紹。
e)裝載代碼段寄存器時的特權檢測
i)對於非一致代碼段,要求CPL = DPL,RPL <= DPL;對於一致代碼段,要求CPL >= DPL(RPL不做檢查)。
ii)代碼段必須存在,即P = 1。
f)裝載數據段和堆棧段寄存器特權檢測
i)把選擇子裝入段寄存器DS、ES、FS或GS時,要進行的檢測:
選擇子不能為空
選擇子指定的描述符類型必須是數據段描述符、可讀可執行的代碼段或一致可讀可執行代碼段
對於數據段和可讀可執行代碼段,要求CPL<=DPL,RPL<=DPL
對應段必須存在
ii)把選擇子裝入段寄存器SS時要進行的檢測:
選擇子不能為空
選擇子指定的描述符類型必須為可讀可寫數據段描述符
要求CPL = RPL = DPL
對應段必須存在
g)實例演示參見“《80x86匯編》十三 任務內無特權級變換轉移實例”
2) 任務內不同特權級的變換
同一任務內可存在4種特權級,實現從外層到內層變化的普通途徑是:使用段間調用指令CALL,通過調用門進行轉移;實現特權級從內層到外層變換的普通途徑是:使用段間返回指令RET。須註意:不能使用JMP指令實現任務內不同特權級的變化。
a)通過調用門的轉移
當段間轉移指令JMP(不能實現特權級變化)和段間調用指令CALL所含指針的選擇子指示調用門描述符時(此時指令中的偏移部分被丟棄),可實現通過調用門的轉移。調用門描述符中包含了轉移入口地址的48位全指針。
處理器采用和訪問數據段相同的特權等級規則控制對門描述符的訪問:只有在相同級或者更內層級的程序才能訪問門(source.CPL<=gate.DPL),同時,還必須滿足source.RPL<=gate.DPL。此外,進入門後,還須檢測門內的段選擇子指示的描述符必須為代碼段描述符。在裝載高速緩沖寄存器之前將調整source.RPL = 0,即調用門中源代碼選擇子的RPL被忽略(也就是說,只要通過門檢查進入了門,那麽就認為它具有最高請求級別,source.RPL<=destination.DPL總是滿足)。
在滿足以上條件後(已經進入門),在裝載CS高速緩沖寄存器時(進入目標代碼段前)還要對目標代碼描述符進行保護檢測(以下檢測調用目標代碼描述符中的DPL而不是調用門的DPL):
i)對於用調用門段間JMP指令:與段間直接JMP檢測條件相同,對於一致代碼段,須source.CPL >= destination.DPL(註意,在source.CPL>destination.DPL情況下進入目標代碼以後,destination.CPL的值並不改變,也就是說發生無特權變化轉移);對於非一致代碼段,當source.CPL = destination.DPL時發生無特權變化轉移;其它情況引發異常。
ii)對於用調用門段間CALL指令:對於一致代碼段,在滿足source.CPL>=destination.DPL時發生無特權變化轉移;對於非一致代碼段,當source.CPL = destination.DPL時發生無特權變換轉移,當source.CPL > destination.DPL時,發生向內層特權級變換的轉移,此時CPL將改變為destination.DPL,同時切換到對於的內存堆棧。
表格參見“《天書夜讀:從匯編語言到windows內核編程》十四 CPU權限級與分頁機制”
須註意:CALL指令在無特權變換時,不發生堆棧切換,返回地址保存在原堆棧中;如果特權級變換,那麽返回地址保存在內層堆棧中。
b)堆棧切換
在source.CPL <= gate.DPL且source.RPL <= gate.RPL時段間CALL指令進入調用門,在門內做保護檢測,如果為非一致代碼段,且有source.CPL > destination.DPL,那麽需要往內存切換特權等級,此時堆棧也做切換。堆棧切換的過程為:
i)根據切換後的特權等級使用TSS中相應的堆棧(SS0:ESP0~SS2:ESP2),並建立一個空棧
ii)把外層當前堆棧指針SS:ESP寄存器的值壓入內層堆棧
iii)從外層堆棧復制調用參數到內層堆棧(即主程序通過堆棧給子程序的實參,復制以雙字為單位)
iv)把調用者的返回地址壓入堆棧。
須註意:任何情況下,如果不發生特權等級的變換,則不會進行堆棧切換。
c)向外層返回
與段間調用CALL向內層變換項對應的是使用RET實現段間返回,其步驟為:
i)從堆棧彈出返回地址
ii)如果返回地址選擇子的RPL是當前CPL更外層的級,那麽說明在進入時發生了權限等級的向內切換,此時需要向外層切換返回;否則,沒有進行權限等級的切換,也就沒有棧的切換,直接跳入第5步。
iii)在向外層返回時,跳過進入時壓入的參數堆棧區域,從內存堆棧彈出外層的堆棧指針,裝入SS:ESP,恢復調用前的現場,並調整內存ESP到最空棧位置。
iv)檢查DS、ES、FS和GS,保證在外層可訪問,如果不可訪問則裝入空選擇子。
v)返回外層繼續執行。
d)實例演示參見“《80x86匯編》十四 任務內特權級變換轉移實例 ”
3) 任務切換
段間JMP、段間CALL、任務門、TSS、中斷/異常或IRET都可以切換任務。
a)直接通過TSS進行任務切換
遠JMP與遠CALL段選擇子是一個可用TSS描述符,正常情況下發生任務切換,目標任務入口點由TSS的CS和EIP字段指定而JMP或CALL指令內偏移被丟棄。TSS描述符訪問特權級控制同數據段。
b)通過任務門進行任務切換
任務門內選擇子指示某個任務的TSS描述符,偏移無意義,過程同上。進入任務門以後將對TSS描述符的可用性進行保護檢測,通過則開始任務切換。
c)任務切換過程
i)測試TSS基本格式,TSS界限應不小於103(基本格式有104個字節)。
ii)把寄存器現場保存到當前任務TSS,不保存LDTR與CR3。註意:EIP保存的是返回地址。
iii)把目標任務TSS選擇子裝入TS,TSS描述符裝入TR高速緩沖寄存器,當前任務變原任務,目標任務變當前任務。
iv)基本恢復當前任務寄存器現場(其中段寄存器不裝載高速緩沖寄存器),恢復CR3寄存器
v)進行鏈接處理。嵌套任務時,將原任務TSS選擇子寫入當前任務TSS鏈接字段,當前任務TSS類型改為“忙”,EFLAGS的NT位置1。如果要解鏈,將原任務TSS描述符類型改為“可用”。無鏈接處理時,原任務TSS類型為“可用”,當前任務TSS類型為“忙”(JMP指令引起任務切換不進行鏈處理,CALL、中斷、IRET會進行鏈處理)。
vi)CR0的TS位置1,表示已進行任務切換,目的是使當前使用協處理器發生自陷,完成協處理器相關現場保護和恢復。
vii)把TSS中的CS選擇子RPL作為CPL(也就是說任務切換可以在任何特權等級發生,切換到任何特權等級的另一個任務)。
ix)裝載LDTR寄存器。當任務沒有LDT時,TSS中的LDT選擇子為空,LDT的存在位置為0;否則從GDT讀出LDT描述符,測試後裝入LDTR高速緩沖寄存器。
x)裝載各高速緩沖寄存器。
xi)把調試寄存器DR7中局部啟用位設置為0,清除局部於原任務的各個斷點和方式。
d)任務狀態和嵌套說明
i)段間JMP指令引起任務切換(目標任務可用),不進行鏈接,不導致任務嵌套。原任務“可用”,目標任務“忙”。
ii)段間CALL指令以及中斷/異常引起任務切換時(目標任務可用),導致任務嵌套。原任務“忙”,目標任務“忙”。
iii)IRET指令引起任務切換時(目標任務忙),實施解鏈,原任務“可用”,目標任務“忙”。
e)實例演示參見“《80x86匯編》十五 任務切換實例”
《80X86匯編語言程序設計教程》十二 任務狀態段、控制門和控制轉移