x86 保護模式編程

一、保護機制概念

       80x86支持兩類保護機制。

        (1)任務之間的保護機制

       給每個任務不同的虛擬地址(邏輯地址   段地址:偏移地址)空間來完全隔離各個任務。這是通過給每個任務不同的(從邏輯地址到物理地址的)變換映射機制(函數)。

       因此兩個不同任務對相同的邏輯地址(虛擬地址)的引用將變換映射到不同的物理地址。這使得操作系統可以給予每個任務的相同的虛擬地址,但仍然可以隔離每個任務的地址空間。

         (2)特權級保護

   對任務進行操作時需要滿足特權級保護的規則,以保護操作系統內存段(數據段和代碼段等)和處理器特殊寄存器(TR,GDTR,IDTR等)不被應用程序訪問。linux特權級用數字0和3表示,0代表最高特權級(內核態)和3代表最低特權級(用戶態)。每個內存段都和一個特權級相關聯。

二、一致性與非一致性代碼段

  • CPL是當前進程的權限級別(Current Privilege Level),是當前正在執行的代碼所在的段的特權級,存在於cs和ss寄存器的低2位(第0,1位)。CPL表示的是程序或者說任務的當前特權級,它不屬於某個段,當前的程序或任務不可能同時表現出2種特權級,那麼CS和SS的第0位和第1位應該總是相同的。嘗試將RPL異於CPL的數據段選擇子裝入SS會引起異常。它們總是相同的。
  • DPL(Descriptor Priviliege Level):表示段或者門的特權等級。它存儲在段或者門描述符的DPL字段中。當前代碼段試圖訪問一個段或者門時,DPL將會和CPL以及RPL作比 較,根據段或者門類型的不同,DPL將會被區別對待:數據段:DPL規定了可以訪問此段的最低特權等級。非一致代碼段(不使用調用門的情況下):DPL規定了訪問此段的特權級。調用門:與數據段一致。一致代碼段和通過調用門訪問的非一致代碼段:DPL規定了訪問此段的最高特權等級。TSS:與數據段一致。
  • RPL說明的是進程對段訪問的請求權限(Request Privilege Level), 是對於段選擇子而言的,每個段選擇子有自己的RPL,它說明的是進程對段訪問的請求權限,有點像函數參數。而且RPL對每個段來說不是固定的,2次訪問同一段時的RPL可以不同。RPL可能會削弱CPL的作用,例如當前CPL=0的進程要訪問一個數據段,它把段選擇符中的RPL設爲3,這樣它對該段仍然只有特權爲3的訪問權限。處理器通過檢查RPL和CPL來確認一下請求是否合法。即便提出訪問請求的代碼段有足夠的特權級,如果RPL不夠也是不行的。(CPL <= DPL) && (RPL <= DPL)


         對於一致代碼段:也就是共享的段.

        <1>.特權級高的程序不允許訪問特權級低的數據:核心態不允許調用用戶態的數據.

        <2>.特權級低的程序可以訪問到特權級高的數據.但是特權級不會改變:用戶態還是用戶態.

        對於普通代碼段.也就是非一致代碼段:

        <1>.只允許同級間訪問.

        <2>絕對禁止不同級訪問:核心態不使用用戶態.用戶態也不使用核心態.

討論特權級的比較

  1. CPL表示的是程序或者說任務的當前特權級,它不屬於某個段,當前的程序或任務不可能同時表現出2種特權級,那麼CS和SS的第0位和第1位應該總是相同的。嘗試將RPL異於CPL的數據段選擇子裝入SS會引起異常。另外後面在論述跳轉的時候可以看到,它們總是相同的。
  2. DPL表示的是某個段或門的特權級,當程序要訪問段A的時候,會將CPL和段A的DPL作比較,以確定程序是否有權限訪問段A。
  3. RPL表示選擇子是否有權限訪問其所指向的段。選擇子指向一個段描述符,段描述符指向一個段,段的特權級由段描述符中的DPL決定。當程序需要訪問段 A的時候,需要先通過段A的選擇子加載段A的段描述符,然後才能訪問段A,在這個過程中CPU會先將段A選擇子中的RPL和段A描述符中的DPL作比較,確定選擇子是否有權限訪問其所指向的段,成功後纔是CPL和段A的DPL的比較。RPL、 DPL之間的比較規則與CPL、DPL之間的比較規則一致。舉個例子解釋前面這句話的意思:比如當前程序要訪問一個數據段A,那麼CPL不能大於段A的 DPL,否則失敗(後面會講到這一點)。這是CPL和段A的DPL的比較規則,那麼同樣段A的RPL、DPL也遵循這樣的規則,也就是段A的RPL不能大於段A的DPL。RPL和CPL不會進行比較。
  4. 不管什麼情況下,相同特權級之間的訪問總是不會錯的,所以後面的討論中通常會忽略相同特權級之間的比較。
  5. 保護模式下代碼段中可以存放數據,但數據段中不能存放代碼(跳轉不過去)。所以代碼段既可以獲取代碼段中的數據(被讀的代碼段屬性需要可讀,就算是獲取自身段內數據也需要可讀),也可以獲取數據段中的數據(數據段總是可讀的),還可以跳轉到其他代碼段。而數據段除了被讀取,什麼都做不了。
  6. 代碼段分爲一致代碼段和非一致代碼段,這會對特權級比較產生影響,是否一致由段描述符的第42位決定。數據段和代碼不同,它總是非一致的。代碼段只在作爲被訪問一方(或者說目標代碼段)時一致性纔會對特權級比較產生影響,在作爲訪問一方時沒有區別。是否一致代碼段的區別是,在段間跳轉過程中,如果目標代碼段是一個特權級更高的一致代碼段,那麼跳轉成功,並且CPL不會改變(CS和SS都不會變),於是CPL異於目標代碼段的RPL(CPL數值更大,特權級更低);如果目標代碼段是一個特權級更高的非一致代碼段,那麼跳轉是會失敗的,此時需要使用調用門。另外,如果目標代碼段是一個特權級更低的代碼段(不論是否一致),那麼跳轉總是會失敗的,除非使用RETF跳轉。
  7. 如果當前程序要訪問一個數據段A,那麼CPL不能大於段A的DPL,否則失敗。也就是說當前程序不能訪問特權級更高的數據段。CPL可以小於段A的 DPL,也就是說當前程序可以訪問特權級更低的數據段。當前程序對調用門和TSS的訪問規則與此一致。
  8. 特權級的檢查是在選擇子被裝入段寄存器的時候進行的。先看相對簡單一點的數據段A選擇子裝入DS的情況(裝入ES,FS,GS類似,這裏以DS爲例說明):段A的DPL必須大於RPL,同時還必須大於CPL(第7點),否則產生異常,段A的RPL不和CPL進行比較。另外,當程序向低特權級跳轉時,會檢查CPL和DS指向的段的DPL,如果DPL小於CPL,那麼DS會被加載空描述符的選擇子。
  9. 數據段A選擇子裝入SS的情況(只有數據段選擇子才能裝入SS,代碼段選擇子不能裝入SS,不管是否可讀):段A的RPL和DPL都必須和CPL相等,否則失敗。來看下爲什麼會這樣。CPU要保證CS和SS中的第0和第1位(CPL)一致,所以段A的RPL必須等於CPL。CPU還要保證當前程序的特權級和當前使用的堆棧段的特權級一致,所以段A的DPL要等於CPL。
  10. 代碼段A選擇子裝入DS的情況(裝入ES,FS,GS類似,這裏以DS爲例說明):如果段A不可讀,裝入失敗。如果段A是可讀的非一致代碼段,那麼 CPL、段A的RPL都必須等於段A的DPL,否則裝入就會失敗。如果段A是可讀的一致代碼段,那麼CPL、段A的RPL都可以大於段A的DPL,但不能小於段A的DPL。代碼段A用段超越前綴CS讀取自身段內數據的時候,雖然沒有選擇子的裝入過程,但CPU會檢查段A是否可讀,如果不可讀會產生異常。
  11. 最後是代碼段的段間跳轉。段間跳轉可以用JMP、CALL、RETF和調用門。從高特權級到低特權級只能用RETF;從低特權級到高特權級非一致代碼段,只能用調用門,而且還必須是用CALL指令來使用調用門;從低特權級到高特權級一致代碼段JMP、CALL、調用門都可以。
  12. 保護模式下的“一致”與”非一致“,指的是當前特權級CPL和要訪問的目標代碼段的DPL的關係說的。

    對於“non-conforming code segment”來說,當合法訪問到目標代碼段時,當前特權級CPL會隨着跳轉被設定成目標代碼段的DPL,因此是“非一致的”;

    對於"conforming code segment"來說,當合法訪問到目標代碼段時,CPL不發生改變,因此是“一致的”;


發佈了59 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章