1. 程式人生 > >x86 保護模式程式設計

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不發生改變,因此是“一致的”;