1.利用中斷引發任務切換:
1.1中斷描述符表IDT:
在保護模式下,實模式下中斷向量表不再使用,取而代之的是中斷描述符表IDT。IDT與GDT,LDT一樣,用於保存描述符;但IDT保存的是門描述符:中斷門、陷阱門、任務門;
1.2任務門
中斷髮生時,如果中斷號對應的門是任務門,則必須進行任務切換;
任務門描述符格式:
1.3中斷執行
中斷執行一般執行過程:
中斷髮生==>處理器用中斷號*8(描述符佔8B)作爲索引訪問IDT==>訪問門描述符==>取出代碼段選擇子和段內偏移==>轉去執行;
通過中斷引發任務切換具體過程:
- 中斷髮生==>處理器將中斷號*8==>訪問中斷向量表IDT;
- 看是否爲任務門描述符,是則進行任務切換,否則普通中斷處理;
- 取出任務門描述符==>從描述符中取出新任務TSS選擇子;
- 用TSS選擇子訪問GDT==>取出新任務TSS描述符;
- 將當前任務狀態存到TR指向的TSS(當前)中;
- 訪問新任務TSS,從中恢復恢復各寄存器內容:通用寄存器、標誌寄存器EFLAGS、段寄存器、EIP、ESP、LDTR等;
- TR指向新任務TSS(任務切換完成)
- [1].把舊任務TSS選擇子填寫到新任務TSS的任務鏈接域,固件執行(TSS結構),且舊任務TSS描述符中B位置保持"1"不變;
[2].EFLAGS寄存器中NT位置"1",表示發生嵌套;
(32位處理器的EFLAGS寄存器中NT位(14位),是嵌套任務標誌位,爲"1"則表示當前任務嵌套於其他任務內);
[3].新任務TSS描述符中B位置"1",表示忙;
1.3中斷返回
中斷不論常規中斷處理過程,還是任務切換,返回都需要指令iret
,前者返回同一任務內不同代碼段,後者返回被中斷任務;
處理器通過EFLAGS中NT判斷是哪種情況,因爲若引發任務切換則新任務EFLAGS中NT位爲"1";
中斷返回過程(iret執行):
iret
指令,則檢查NT位:
==>若0(沒嵌套),表明一般中斷過程,一般中斷處理;
==>若1(嵌套),固件將現EFLAGS中NT置"0"(不在嵌套),並將EFLAGS保存在現TSS中,現TSS描述符中B位置"0"(當前沒在執行),從現TSS任務鏈接域中取得原TSS選擇子,所有原始狀態都從原TSS中恢復,包括EIP,回到任務切換出指令繼續執行;
2.利用指令引發任務切換:
利用call
和jmp
指令,操作數爲任務的TSS描述符選擇子/任務門描述符,能夠實現任務切換,描述符可以安在GDT/LDT;如:
call 0x0010:0x000000
jmp 0x0010:0x000000
當執行到這兩條指令時,訪問GDT,若描述符是TSS描述符/任務門描述符==>偏移量忽略並從TSS中獲取,開始任務切換;
3.對比與安全檢查
利用call
和jmp
指令和中斷引發任務切換對比:
JMP/CALL/中斷引發 | 對比 | 返回 | |
---|---|---|---|
CALL/中斷髮起切換 | 引起嵌套; 舊任務:TSS中B保持'1'(忙)不變,EFLAGS中NT保持不變; 新任務:TSS中B置'1'(忙),EFLAGS中NT置'1'(嵌套),新TSS任務鏈接域填舊TSS選擇子(固件執行); | 指令iret/iretd(過程在1.3) | |
JMP | 不會引起嵌套; 舊任務:TSS中B置'0'(非忙),EFLAGS中NT保持不變; 新任務:TSS中B置'1'(忙),EFLAGS中NT保持從TSS中加載時狀態; 新TSS任務鏈接域不變 | JMP回來 |
安全檢查
- 檢查是否允許從舊任務切換到新任務:
JMP/CALL:舊任務CPL、新任務段選擇子RPL<=目標TSS/任務門DPL;
異常、中斷(除in n引發)、iret:忽略目標門/TSS描述符DPL,int n引發中斷檢查DPL; - 檢查新任務TSS是否標記爲有效(P=1),且界限也有效(界限>=103)
- 檢查新任務是否可用:
B=0(CALL、JMP、異常或中斷髮起的任務切換);
B=1(iret發起的任務切換); - 檢查舊任務和新任務TSS,以及所有要用的段描述符是否在內從中;