32位保護模式學習小結(3)---任務切換
兩種基本的任務切換方式
協同式:從一個任務切換到另一個任務,需要當前任務主動地請求暫時放棄執行權,或者在通過呼叫門請求作業系統服務時,由作業系統”趁機”將控制轉移到另一個任務.這種方式依賴於每個任務的”自律”性,當一個任務失控時,其他任務可能得不到執行的機會.
搶佔式:這種方式下,可以安裝一個定時器中斷,並在中斷服務程式中實施任務切換.硬體中斷訊號總會定時出現,不管處理器當時在做什麼,中斷都會適時地發生,而任務切換也就能夠順利進行.在這種情況下,每個任務都能獲得平等的執行機會.而且,即使一個任務失控,也不會導致其他任務沒有機會執行.
任務切換前置
所有任務共享一個全域性空間,這是核心或者作業系統的,包括了系統服務程式和資料;同時,每個任務還有自己的區域性空間,每個人物的功能都不一樣,所以,區域性空間包含的是一個任務區別於其他任務的私有程式碼和資料.如下圖:
在一個任務內,全域性空間和區域性空間具有不同的特區級.使用門,可以在任務內將控制從3特權級別的區域性空間轉移到0特權級的全域性空間,以使用核心或者作業系統提供服務.
任務切換是以任務為單位的,是指離開一個任務,轉到另一個任務中去執行.
要執行任務切換,系統中必須至少有兩個任務,而且已經有一個正在執行中.
任務切換的方法
1.藉助中斷進行中斷
- 這也是現代搶佔式多工的基礎.只要中斷沒有被遮蔽,它就隨時能發生.特別是定時器中斷,能夠以準確的時間間隔發生,可以用來強制實施任務切換.
在保護模式下,中斷向量表不再使用,取而代之的是中斷描述符表.它和GDT, LDT是一樣的,用於儲存描述符.唯一不同的地方是,它儲存的是門描述符,包括中斷門,陷阱門和任務門.當中斷髮生時,處理器用中斷號乘以8(因為每個描述符8位元組),作為索引訪問中斷描述符表,取出門描述符.門描述符中有中斷處理過程的程式碼段選擇子和段內偏移量,這和呼叫門是一樣的.接著,轉移到相應的位置去執行.
回憶一下呼叫門的工作原理,它只是從任務的區域性空間轉移到更高特權級的全域性空間去執行,本質上是一種任務內的控制轉移行為.與此相同,中斷門和陷阱門允許在任務內實施中斷處理,轉到全域性空間去執行一些系統級的管理工作,本質上,也是任務內的控制轉移行為.
在中斷髮生時,如果該中斷對應的門是任務門,那麼,必須進行任務切換.任務門描述符中的主要成分是TSS選擇子.任務門用於在中斷髮生時執行任務的切換,而執行任務切換時必須找到新任務的任務狀態段.所以任務門應當指向任務的TSS.
任務門描述符中P位指示該門是否有效,當P位為0時,不允許通過此門實施任務的切換;DPL是任務門描述符的特權級,但是對因為中斷而發起的任務切換不起作用,處理器不按特權級施加任何保護.
①當中斷髮生時,處理器用中斷號乘以8作為索引訪問中斷描述符表.當它發現這是一個任務門(描述符)時,就知道應當發起任務切換.
②於是,它取出任務門描述符;再從任務門描述符中取出新任務的TSS選擇子;接著,再用TSS選擇子訪問GDT,取出新任務的TSS描述符.
③在轉到新任務執行前,處理器要先把當前任務的狀態儲存起來.當前任務的TSS是由任務暫存器TR的當前內容指向的,所以,處理器把每個暫存器的”快照”儲存到由TR指向的TSS中.
④然後,處理器訪問新任務的TSS,從中恢復各個暫存器的內容.
⑤最終,任務暫存器TR指向新任務的TSS,而處理器隨即開始執行新的任務.一旦新任務開始執行,處理器韌體會自動將其TSS描述符的B位置1,表示該任務的狀態為忙.
中斷髮生時,可以執行常規的中斷處理過程,也可以進行任務切換.儘管性質不同,但它們都要使用iret指令返回.前者是返回到同一任務內的不同程式碼段;後者是返回到被中斷的那個任務.
32位處理器的SFLAGS有NT位(位14),意思是巢狀任務標誌.每個任務的TSS中都有一個任務連結域(指向前一個任務的指標),可以填寫為前一個任務的TSS描述符選擇子.如果當前任務EFLAGS暫存器的NT位是1,則表示當前正在執行的任務巢狀與其他任務內,並且能夠通過TSS任務連結域的指標返回到前一個任務.
對新任務的處理是,要把老任務的TSS選擇子填寫到新任務TSS中的任務連結域,同時,將新任務EFLAGS的NT位置”1”,以允許返回(轉換)到前一個任務(老任務)繼續執行,同時,還要把新任務TSS描述符的B位置”1”.
可以使用iret指令從當前任務返回到前一個任務,前提是EFLAGS的NT位為1.無論任務處理器碰到iret指令,它都要檢查NT位, 如果為0,表示是一般的中斷過程,按一般的中斷返回處理;如果此位為1,則表明當前任務之所以能夠正在執行,是因為中斷了別的任務.因此,應當返回原先被中斷的任務繼續執行.此時,由處理器韌體把當前任務EFLAGS的NT位置0,並把TSS描述符的B位置0(非忙).在儲存了當前任務的狀態之後,接著,用新任務(被中斷的任務)的TSS恢復現場.
2.用CALL或者JMP直接發起任務切換
當處理器執行這兩條指令時,首先用指令中給出的描述符選擇子訪問GDT,分析他的描述符型別,如果是一般的程式碼段描述符,就按普通的段間轉移規則執行;如果是呼叫門,按呼叫門的規則執行;如果是TSS描述符,或者任務門,則執行任務切換.此時指令中給出的32位偏移被忽略,原因是執行任務切換時,所有處理器的狀態都可以從TSS中獲得.注意,任務門描述符可以安裝在中斷描述符表中,也可以安裝在GDT或者LDT中.
如果用於發起任務切換,call指令和jmp指令也有不同之處.使用call發起的任務切換類似於因中斷髮起的任務切換.這就是,由call發起的任務切換是巢狀的,當前任務(舊任務)TSS描述符的B位保持原來的1不變,EFLAGS暫存器的NT位也不發生變化;新任務TSS描述符的B位置1,EFLAGS的NT位也置1,表示此任務巢狀與其他任務中.同時,TSS任務連結域的內容改為舊任務的TSS描述符選擇子.
用CALL指令發起的任務切換,可以通過IRET返回前一個任務.此時,舊任務(當前任務)TSS描述符的B位,以及EFALGS的NT位都被恢復到0,並儲存到它的TSS中.
用JMP指令發起的任務切換,不會形成任務之間的巢狀關係.執行任務切換時,當前任務(舊任務)TSS的B位清0,EFALGS的NT位不變;新任務TSS描述符的B位置1,進入忙的狀態,EFALGS的NT位保持從TSS中載入時的狀態不變.
任務是不可重入的
任務不可重入的本質是,執行任務切換是,新任務的狀態不能為忙.這裡有兩個典型的情形:
執行任務切換時,新任務不能是當前任務自己.試想一下,如果允許這種情況發生,處理器該如何執行現場保護和恢復操作?
如圖不允許使用CALL指令從任務3切換到任務2和任務1上.如果不禁止這種情況的話,任務之間的巢狀關係將會因為TSS任務連結域的破壞而錯亂.
處理器是通過TSS描述符的B位來檢測重入的. 因中斷, IRET, CALL和JMP指令發起任務切換時, 處理器韌體會檢測新任務TSS描述符的B位, 如果為1, 則不允許執行這樣的切換.
處理器在實施任務切換時的操作
處理器用一下4種方法將控制轉移到其他任務:
當前程式,任務或著過程執行一個將控制轉移到GDT內某個TSS描述符的JMP或者CALL指令.
當前程式,任務或者過程執行一個將控制轉移到GDT或者當前LDT內某個任務門描述符的JMP或者CALL指令.
一個異常或者中斷髮生時,中斷號指向中斷描述符表內的任務門.
在EFLAGS暫存器的NT位置位的情況下,當前任務執行了一個IRET指令.
在任務切換是, 處理器執行以下操作:
從JMP或者CALL指令的運算元,任務門或者當前任務的TSS任務連結域取的新任務的TSS描述符選擇子.最後一種方法適用於以IRET發起的任務切換.(簡言之之就是準備命令切換)
檢查是否允許從當前任務(舊任務)切換到新任務.資料訪問的特權級檢查規則適用於JMP和CALL指令,當前任務的CPL和新任務段選擇子的RPL必須在數值上小於或者等於目標TSS或者任務門的DPL.異常,中斷(除了int n指令引發的中斷)和IRET指令引起的任務切換忽略目標任務門或者TSS描述符的DPL.對於以int n指令產生的中斷,要檢查DPL.(簡言之就是檢查特權級)
檢查新任務的TSS描述符是否已經標記為有效(P = 1),並且界限值也有效(大於或者等於0x67,十進位制103).(簡言之就是檢查TSS是否可用)
檢查新任務是否可用,不忙(B = 0,對於以CALL,JMP,異常或者中斷髮起的任務切換),忙(B = 1,對於以iret發起的任務切換).(簡言之就是新任務是否可用)
檢查當前任務(舊任務)和新任務的TSS,以及所有任務切換時用到的段描述符已經安排到系統記憶體中.
如果任務切換是由JMP或者IRET發起的,處理器清除當前(舊)任務的忙(B)標誌;如果是由CALL指令,異常或者中斷髮起的,忙標誌保持原來的置為狀態.
如果任務切換是由IRET指令發起的,處理器建立EFLAGS暫存器的一個臨時副本並清除其NT標誌;如果是由CALL,JMP,異常或者中斷髮起的,副本中的NT標誌不變.
儲存當前(舊)任務的狀態到它的TSS中.處理器從任務暫存器中找到當前TSS的基地址,然後將以下暫存器的狀態複製到它的TSS中:所有通用暫存器,段暫存器中的段選擇子,剛才那個EFLAGS暫存器的副本,以及指令指標暫存器EIP.(簡言之就是儲存現任務狀態)
如果任務切換是由CALL指令,異常或者中斷髮起的,處理器把從新任務載入的EFLAGS的NT標誌置位;如果是由IRET或者JMP指令發起的,NT標誌位的狀態對應著從新任務載入的EFLAGS的NT位.
如果任務切換是由CALL,JMP,異常或者中斷髮起的,處理器將新任務TSS描述符中的B位置位;如果是由IRET指令發起的,B位保持原先的置位狀態不變.
用新任務的TSS選擇子和TSS描述符載入任務暫存器TR.
新任務的TSS狀態資料被載入到處理器.這包括LDTR,PBDR(控制暫存器CR3),EFLAGS,EIP,通過用暫存器,以及段選擇子.載入狀態期間只要發生一個故障,構架狀態就會被破壞(因為有些暫存器的內容已被改變,而且無法撤銷和回退).所謂架構,是指處理器對外公開的那一部分的規格和構造;所謂架構狀態,是指處理器內部的各種構件,在不同的條件下,所建立起來的確定狀態.當處理器處於某種狀態時,再施加另一種確定的條件,可以進入另一種確定的狀態,這應當是嚴格的,眾所周知的,可預見的.否則,就意味著架構狀態遭到破壞.(TSS載入處理器時需要一定的架構不被破壞)
與段選擇子相對應的描述符在經過驗證後也被載入.與載入和驗證新任務環境有關的任何錯誤都將破壞架構狀態.注意,如果所有的檢查和保護工作都已經成功實施,處理器提交任務切換. 如果在第11步的過程中發生了不可恢復性的錯誤,處理器不能完成任務切換,並確保處理器返回到執行發起任務切換的那條指令前的狀態.如果在第12步發生了不可恢復的錯誤,架構狀態被破壞; 如果在提交點(第13步)之後發生了不可恢復性的錯誤,處理器完成任務切換並在開始執行新任務之前產生一個相應的異常.(段選擇子相應描述符的驗證)
開始執行新任務.
任務切換時,當前任務的狀態總要儲存起來,在恢復執行時,處理器從EIP暫存器的儲存值所指向的那條指令開始執行,這個暫存器的值是在當初任務切換被掛起時儲存的.
任務切換時, 新任務的特權級並不是從那個被掛起的任務繼承來的.新任務的特權級別是由其段暫存器CS的低2位決定的.
任務狀態段TSS的任務連結域和EFLAGS的NT位用於返回前一個任務執行,當前EFLAGS暫存器的NT位是1表明當前任務巢狀與其他任務中.無論如何,新任務的TSS描述符的B位都會被置位,舊任務的B位取決於任務切換的方法.
不同任務切換方法對B位,NT位和任務連結域的影響
標誌或TSS任務連結域 | JMP指令的影響 | CALL指令或中斷的影響 | IRET指令的影響 |
---|---|---|---|
新任務的B位 | 置位.原先必需為零 | 置位.原先必需為零 | 不變.原先必須被置位 |
舊任務的B位 | 清零 | 不變.原先必須被置位 | 清零 |
新任務的NT標誌 | 設定為新任務TSS中的對應值 | 置位 | 設定為新任務TSS中的對應值 |
舊任務的NT標誌 | 不變 | 不變 | 清零 |
新任務的任務連結域 | 不變 | 用舊任務的TSS描述符選擇子載入 | 不變 |
舊任務的任務連結域 | 不變 | 不變 | 不變 |