《一個操作系統的實現》(三):2.保護模式進階

在之前的代碼中,程序從實模式跳到保護模式之後就開始死循環。這節會實現在程序結束時跳回實模式,也會實現對大地址內存的讀寫。

新建的段以5MB爲基址。而且每增加段都要用Descriptor描述它的段基址、段界限、屬性,而且還要加上對應的選擇子,比如如下兩行:

LABEL_DESC_DATA:    Descriptor 0, DataLen-1, DA_DRW    ;Data

SelectorData    equ    LABEL_DESC_DATA - LABEL_GDT

需要注意的是:在程序的整個執行過程中,edi始終指向要顯示的下一個字符的位置。所以如果程序中除顯示字符外還用到edi,需要事先保存它的值,以免在顯示時出現混亂。

保護模式跳回到實模式比實模式跳轉到保護模式複雜一些。在準備結束保護模式回到實模式之前,需要加載一個合適的描述符選擇子到有關段寄存器,以使對應段描述符高速緩衝寄存器中含有合適的段界限和屬性。而且不能從32位代碼段返回實模式,只能從16位代碼段中返回。這是因爲無法實現從32位代碼段返回時cs高速緩衝寄存器中的屬性符合實模式的要求(實模式不能改變段屬性)。

若要跳回到實模式,則段寄存器需要修改指向(將SelectorNormal加載到各段寄存器,然後清cr0的PE位,給跳轉回實模式的指令指定正確的段地址。這樣就可以跳回實模式了。但是還沒有完,程序還需要重新設置各個段寄存器的值,恢復sp的值,關閉A20,打開中斷,然後就OK了。

編譯運行整個程序~

nasm pmtest2.asm -o pmtest2.com

bochs -f bochsrc

然後輸入c跑起來,然後又要開另一個終端了:

sudo mount -o loop pm.img /mnt/floppy

sudo cp pmtest2.com /mnt/floppy/

sudo umount /mnt/floppy

然後到Bochs中執行b:\pmtest2.com,得到了預期結果~


這節還講了一下LDT,與GDT的區別就在於LDT是局部的(Local),而GDT是全局的(Global)。

它們兩個的選擇子一大區別就是TI位置,LDT爲1而GDT爲0。lldt是針對LDT的,lgdt針對GDT,它們均負責加載描述符,操作數是對應描述LDT的描述符的選擇子(這句話有點繞- -)

而且GDT中需要添加描述LDT的描述符。

以後可以在LDT中添加更多段(數據段、堆棧段等),這樣可以把一個單獨的任務所用到的所有東西封裝在一個LDT中

增加一個用LDT描述的簡單任務的步驟:

1.增加一個32位代碼段

2.增加一個段,內容是一個描述符表(LDT),可以只有一個代碼段描述符,也可以添加更多的描述符描述更多的段,涉及的選擇子的TI位應該爲1.

3.在GDT中增加一個描述符,用以描述這個LDT,同時要定義其描述符。

4.增加新添的描述符的初始化代碼主要針對段基址。

5.用新加的LDT描述的局部任務準備完畢。

6.使用前用lldt指令加載ldtr,用jmp指令跳轉等方式運行。


下面對保護模式中的“保護”做更深的瞭解。描述符中段基址和段界限定義了一個段的範圍,對超越段界限之外的地址的訪問是被禁止的;另一方面有點複雜的段屬性作爲對一個段各方面的定義規定和限制了段的行爲和性質,從功能上來講也是一種保護。

關於特權級——

IA32的分段機制中,從高到低有0,1,2,3四個特權級,其中內核爲level0,服務爲level1和2,應用程序爲level3。處理器通過識別CPL、DPL、RPL這三種特權級進行特權級檢驗。

CPL(current)爲當前執行的程序或任務的特權級,存儲在cs和ss的第0位和第1位上,CPL隨着程序轉移到不同特權級代碼段而被處理器改變。但一致代碼段可以被相同或更低特權級的代碼訪問,所以當處理器訪問一個與CPL特權級不同的一致代碼段時,CPL不會被改變。

DPL(descriptor)爲段或門的特權級。對於數據段、調用門、TSS(任務狀態段,task state segment),DPL規定可訪問此段的最低等級;對於不使用調用門情況下的非一致代碼段,DPL規定可訪問此段的特權級(僅一個等級,不存在最低或最高等級);對於一致代碼段和通過調用門訪問的非一致代碼段,DPL規定訪問此段的最高特權級。

RPL(requested)通過段選擇子的第0位和第1位表現出來。處理器通過檢查RPL和CPL確認一個訪問請求是否合法,即RPL和CPL同時都必須有足夠特權級。操作系統過程通常用RPL避免低特權級應用程序訪問高特權級段內的數據。

程序從一個代碼段轉移到另一個代碼段之前,目標代碼段的選擇子會被加載到cs中。作爲加載過程的一部分,處理器會檢查描述符的界限、類型、特權級等內容。如果檢驗成功,cs將被加載,程序控制將轉移到新的代碼段中,從eip指示的位置開始執行。

指令jmp、call、ret、sysenter、sysexit、int n或iret或者中斷和異常機制可引起程序控制轉移發生。

jmp或call指令實現的4種轉移:

1.目標操作數包含目標代碼段的段選擇子(直接轉移,下面三種均爲通過某描述符的間接轉移)

2.目標操作數指向一個包含目標代碼段選擇子的調用門描述符

3.目標操作數指向一個包含目標代碼段選擇子的TSS

4.目標操作數指向一個任務門,這個任務門指向一個包含目標代碼段選擇子的TSS

上面也講到轉移是有限制的,要判斷特權級是否符合。如果要自由在不同特權級之間進行轉移,則要使用門描述符或者TSS

其實門也是一種描述符,定義入口地址的偏移,屬性,選擇子。直觀地看,一個門描述了由一個選擇子和一個偏移所指定的線性地址,程序正是通過這個地址進行轉移的。門描述符共四種:調用門、中斷門、陷阱門、任務門。調用門本質上是一個增加了若干屬性的入口地址。下表爲調用門的特權級規則,其中DPL_G爲調用門的DPL,DPL_B爲轉移目的的DPL:

調用門特權級規則
  call jmp
目標是一致代碼段 CPL≤DPL_G,
RPL≤DPL_G,
DPL_B≤CPL
同call
目標是非一致代碼段 CPL≤DPL_G,
RPL≤DPL_G,
DPL_B≤CPL
CPL≤DPL_G,
RPL≤DPL_G,
DPL_B=CPL
可以總結得出,通過調用門和call指令,可以實現從低特權級到高特權級的轉移,無論目標代碼段是否一致。

特權級變化時堆棧也要變化,這種機制避免了高特權級的過程由於棧空間不足而崩潰,而且如果不同特權級共享同一個堆棧的話,高特權級的程序可能因此受到有意或無意的干擾。

關於jmp和call的段內和段間跳轉:對於jmp,長調用和短調用只是結果不同;而對於call,長調用和短調用對堆棧的影響不同。因爲返回時需要調用者的cs,所以call指令執行時被壓棧的除了eip還應該有cs。

Intel提供複製堆棧內容的機制。由於每一個任務最多都可能在4個特權級間轉移,所以每個任務實際上需要4個堆棧。堆棧切換時,我們可以從TSS中獲得其餘堆棧的ss和esp。書上稱TSS爲Task-State Stack,但是網上TSS的全稱爲Task State Segment,任務狀態段,除了涉及本書的內容之外也沒有“任務狀態棧”這個東西。但是只有在低特權級向高特權級切換時,新堆棧才從TSS中取得。整個的轉移過程CPU所做工作如下:

1.根據目標代碼段的DPL(新的CPL)從TTS中選擇應該切換至哪個ss和esp。

2.從TSS中讀取新的ss和esp。在這過程中如果發現ss、esp或者TSS界限錯誤都會導致無效TSS異常(#TS)。

3.對ss描述符進行檢驗,如果發生錯誤,同樣產生#TS異常。

4.暫時保存當前ss和esp的值。

5.加載新的ss和esp。

6.將剛保存起來的ss和esp的值壓入新棧。

7.從調用者堆棧中將參數複製到被調用者堆棧(新堆棧)中,複製參數的數目由調用門中Param Count一項來決定。如果Param Count是0,則不會複製參數。

8.將當前的cs和eip壓棧。

9.加載調用門中指定的新的cs和eip,開始執行被調用者過程。

如果參數多於Param Count的位數,則可以讓其中的某個參數變成指向一個數據結構的指針,或者通過保存在新堆棧裏的ss和esp來訪問舊堆棧中的參數。

ret基本上是call的反過程,只是帶參數的ret指令會同時釋放事先被壓棧的參數。事實上,ret不僅可以實現短返回和長返回,而且可以實現帶有特權級變換的長返回。通過ret指令可以實現由高特權級到低特權級的轉移。由被調用者到調用者的返回過程中,處理器的工作包含以下步驟:

1.檢查保存的cs中的RPL以判斷返回時是否要變換特權級。

2.加載被調用者堆棧上的cs和eip(此時會進行代碼段描述符和選擇子類型和特權級檢驗)。

3.如果ret指令含有參數,則增加esp的值以跳過參數,然後esp將指向被保存過的調用者ss和esp。注意,ret的參數必須對應調用門中的Param Count的值。

4.加載ss和esp,切換到調用者堆棧,被調用者的ss和esp被丟棄。在這裏將會進行ss描述符、esp以及ss段描述符的檢驗。

5.如果ret指令含有參數,增加esp的值以跳過參數(此時已經在調用者堆棧中)。

6.檢查ds、es、fs、gs的值,如果其中哪一個寄存器指向的段的DPL小於CPL(此規則不適用於一致代碼段),那麼一個空描述符會被加載到該寄存器。


本節到此結束~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章