任务切换的方法——《x86汇编语言:从实模式到保护模式》读书笔记37
任務(wù)切換的方法——《x86匯編語言:從實模式到保護模式》讀書筆記37
1. 中斷門和陷阱門
在實模式下,內(nèi)存最低端的1M是中斷向量表,保存著256個中斷處理過程的段地址和偏移。當(dāng)中斷發(fā)生時,處理器把中斷號乘以4,作為索引訪問中斷向量表,從相應(yīng)的位置取出中斷處理過程的段地址和偏移地址,并轉(zhuǎn)移到哪里執(zhí)行。具體過程可以參考我的博文
8086中斷系統(tǒng)——《x86匯編語言:從實模式到保護模式》讀書筆記04
在保護模式下,中斷向量表不再使用,取而代之的是中斷描述符表(Interrupt Descriptor Table,IDT)。不要害怕,它和GDT、LDT是一樣的,用于保存描述符。唯一不同的地方是,它保存的是門描述符,包括中斷門、陷阱門和任務(wù)門。
中斷門和陷阱門的格式如下圖:
當(dāng)中斷發(fā)生時,處理器用中斷號乘以8(因為每個描述符占8個字節(jié)),作為索引訪問IDT,找到某個門描述符。如果是中斷門或陷阱門,那么就取出門描述符中的段選擇子和段內(nèi)偏移量,然后轉(zhuǎn)移到相應(yīng)的位置去執(zhí)行。這個過程可以用下圖說明:
中斷門和陷阱門允許在任務(wù)內(nèi)實施中斷處理,轉(zhuǎn)到全局空間執(zhí)行一些系統(tǒng)級的管理工作。本質(zhì)上,是任務(wù)內(nèi)的控制轉(zhuǎn)移行為。
2. 通過中斷執(zhí)行任務(wù)切換
但是,如果訪問IDT時遇到的是任務(wù)門,那么就會引發(fā)任務(wù)切換。即,要中斷當(dāng)前任務(wù)的執(zhí)行并保護現(xiàn)場,然后后切換到另一個任務(wù)去執(zhí)行。
任務(wù)門的格式如下圖:
注意:任務(wù)門描述符可以安裝在IDT、GDT和LDT中。
通過中斷執(zhí)行任務(wù)切換的過程,可以參考《Intel Architecture Software Developer’s Manual Volume 3:System Programming》的TASK SWITCHING這一節(jié)。
我把其中的關(guān)鍵點總結(jié)如下(序號不代表發(fā)生的先后順序):
1. 保存當(dāng)前任務(wù)狀態(tài)到它的TSS(由TR寄存器指向)中;
2. 處理器訪問新任務(wù)的TSS,從中恢復(fù)現(xiàn)場;
3. TR寄存器指向新任務(wù)的TSS;
4. 把舊任務(wù)的TSS選擇子填寫到新任務(wù)TSS中的“任務(wù)鏈接域”,將新任務(wù)EFLAGS寄存器的NT位置1,同時還要把新任務(wù)TSS描述符的B位置1,表示該任務(wù)狀態(tài)為忙。(舊任務(wù)的TSS的B位不變,仍然為1.)
3. iret指令
當(dāng)中斷發(fā)生時,可以執(zhí)行常規(guī)的中斷處理過程,也可以執(zhí)行任務(wù)切換。盡管性質(zhì)不同,但是它們都要使用iret指令返回。前者是返回到同一任務(wù)內(nèi)的斷點處;后者是返回到上一層任務(wù)。你也許會問:處理器如何區(qū)分這兩種截然不同的返回類型呢?
如下圖所示,32位的EFLAGS寄存器有一個NT位(bit14)—— 嵌套任務(wù)標志(Nested Task Flag).
每個任務(wù)的TSS中都有一個任務(wù)鏈接域,其內(nèi)容可以是前一個任務(wù)的TSS描述符的選擇子。如果當(dāng)前任務(wù)EFLAGS寄存器的NT位是1,則表示當(dāng)前正在執(zhí)行的任務(wù)嵌套于其他任務(wù)內(nèi),并且能夠通過TSS任務(wù)鏈接域的指針返回到前一個任務(wù)。
可以使用iret指令從當(dāng)前任務(wù)返回(切換)到前一個任務(wù),前提是當(dāng)前任務(wù)的NT位必須是1.無論何時處理器遇到iret指令,它都要檢查NT位,如果是0,表明是一般中斷過程,則按照一般的中斷返回處理;如果是1,則表明當(dāng)前任務(wù)之所以能夠執(zhí)行,是因為它打斷了別的任務(wù)。因此,應(yīng)當(dāng)返回到原先被中斷的任務(wù)繼續(xù)執(zhí)行,并且由處理器固件把當(dāng)前任務(wù)EFLAGS的NT位改成0,并把TSS描述符的B位改成0.在保存了當(dāng)前任務(wù)的狀態(tài)后,接著用被中斷的任務(wù)的TSS恢復(fù)現(xiàn)場。
4. 通過call或者jmp指令發(fā)起任務(wù)切換
在這兩種情況下,call指令或者jmp指令的操作數(shù)是任務(wù)的TSS描述符選擇子或者任務(wù)門。例如:
call 0x10:0x00000000jmp 0x10:0x00000000當(dāng)處理器執(zhí)行這兩條指令時,首先用選擇子索引GDT(對于本例,是GDT),分析得到的描述符類型
1. 對于代碼段描述符,就按照普通的段間轉(zhuǎn)移執(zhí)行;
2. 對于調(diào)用門,按照調(diào)用門的規(guī)則執(zhí)行;
3. 對于TSS描述符或者任務(wù)門(下圖中粉色部分),則執(zhí)行任務(wù)切換。此時,指令中給出的32位偏移量被忽略,因為在執(zhí)行任務(wù)切換時,所有處理器的狀態(tài)都可以從TSS中獲得。
使用CALL指令發(fā)起的任務(wù)切換類似于因中斷發(fā)起的任務(wù)切換。也就是說,由CALL指令發(fā)起的任務(wù)切換是“嵌套”的。如下圖所示:
5. 任務(wù)是不可重入的
執(zhí)行任務(wù)切換時,新任務(wù)的狀態(tài)不能為忙。處理器是通過TSS描述符的B位來檢測是否重入的。由中斷、iret、call和jmp指令發(fā)起任務(wù)切換時,處理器固件會檢測新任務(wù)TSS描述符的B位,如果為1,則不允許執(zhí)行這樣的切換。
6. 總結(jié)
處理器可以通過以下四種方法實施任務(wù)切換:
1. call指令或者jmp指令的操作數(shù)是GDT內(nèi)的某個TSS描述符;
2. call指令或者jmp指令的操作數(shù)是GDT或者LDT內(nèi)某個任務(wù)門描述符;
3. 一個異常或者中斷發(fā)生時,中斷號指向IDT內(nèi)的某個任務(wù)門;
4. 在EFLAGS寄存器的NT位置位的情況下,當(dāng)前任務(wù)執(zhí)行了一個iret指令。
最后,把書上表格15-1再繪制一下,加深印象。
總結(jié)
以上是生活随笔為你收集整理的任务切换的方法——《x86汇编语言:从实模式到保护模式》读书笔记37的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 异常分类_Python异常
- 下一篇: 适合程序员的四大字体