1. 程式人生 > >保護模式程式設計——保護的詳盡意義:通過呼叫門轉移特權級

保護模式程式設計——保護的詳盡意義:通過呼叫門轉移特權級



摘要:在組合語言的程式設計和作業系統的編寫過程中,我們經常能聽說到“保護模式”這個名詞。為什麼要叫“保護模式”呢?保護 二字的含義何在?本文主要探討,“保護模式”下面各種具體的保護機制,這些保護機制產生的原因和具體的影響。閱讀本文之前,讀者需要了解基本的處理器相關知識,知道分段和分頁機制的基本原理,熟悉一些基本的資料結構(段選擇符、描述符、GDT、頁表、CR系列暫存器等),另外也需要懂一些基本的彙編知識。

發明保護模式是為了進行多工設計,避免任務之間的相互干擾。保護模式的實現是通過分段和分頁機制來進行的。通過設定CR0的PE標誌位可以讓處理器工作在保護模式下,PG位可以開啟分頁保護機制。通過分段保護機制,處理器使用段暫存器中選擇符(RPL和CPL)和段描述符中的各個欄位來執行保護驗證。對於分頁機制,主要用頁目錄表和頁表項中的R/W和U/S標誌來實現保護操作。

本文最重要的部分屬於第三部分——通過呼叫門,在不同特權級別的程式碼段之間進行轉移。

1.段級保護


保護模式下,保護機制根據特權級(4個段保護和2個頁保護)提供對段和頁的基本訪問閒置能力。例如,通過設定系統程式碼和資料段比普通應用程式具有較高的特權級,應用程式只能按照受控的方式來訪問作業系統的程式碼和資料。保護機制下執行的檢查可以分為如下類別:段界限檢查、段型別檢查、特權級檢查、可定址範圍檢查、過程入口點限制、指令集限制。

下面,我們逐個分析各類檢查:

1.1段限長檢查


段限長檢查需要依賴三位:顆粒度G、擴充套件方向標誌E和標誌B(預設棧指標大小或者上界)。這裡,我們可以先回顧一下段描述符中,這幾個位的定義和段描述符的結構.


顆粒度G:G=0,limit的範圍是0~0xFFFFF(注意從0開始;段限長的表示佔用20b)。G=1,limit需要乘以4K,同時,段內偏移地址的低12b不會與limit進行對照。例如,G=1,Limit=0,偏移值從0到0xFFF仍然是合法的。

段的拓展方向標誌位E:E=1的時候,段限長具有相同的功能,但是含義不同。對於上擴段,表示從0到limit是合法的;對於下擴段,需要結合預設棧指標大小標誌B的設定,從limit到oxfffff(B標誌=0)或者oxFFFFFFFF。

除了檢查段限長,處理器也會檢查段描述符表的長度。GDTR、IDTR、LDTR暫存器中包含有16b的限長值。選擇符為0的時候,將產生一個一般保護性異常。

1.2段型別檢查


應用程式有資料段和程式碼段,cpu還有系統段和門描述符。他們用來管理任務、異常和中斷。並非所有的描述符都定義一個段,門描述符中存放著一個指向過程入口點的指標。S和Type欄位表明了段的型別資訊。

操作段選擇符和段描述符時,處理器會隨時檢查型別資訊。
(1)載入段選擇符進入段暫存器的時候
CS暫存器只能存放可執行段的選擇符
不可讀可執行段的選擇符不能被載入進入資料段暫存器(因為資料段都是可讀的)
只有可寫資料段選擇符才能載入到SS暫存器(SS暫存器一定是可寫的)
(2)指令訪問一個段,段描述符已經被載入到段暫存器,指令只能用某些預定義的方法來訪問某些段(這個和規則1是互相補充的)
不能寫可執行段(程式碼段不可寫)
不能寫一個可寫位沒有設定的資料段
不能讀可讀位沒有設定的可執行段

1.3特權級

有四種特權級:0,作業系統核心;1和2,作業系統服務;3應用層。

處理器可以識別以下三種類型的特權級別:

1)當前特權級:當前執行程式或者任務的特權級別,存放在CS和SS和b1和b0,通常,CPL等於當前程式碼段的特權級。一般情況下,訪問不同特權級的程式碼段會改變CPL。但是對於一致性程式碼段,那些特權級高於或者等於一致性程式碼段DPL的任何段都可以訪問(一致性程式碼具有可共享性,所以可以被低特權的程式碼訪問),
此時CPL不會發生修改

2)描述符特權級DPL。DPL是一個段或者門的特權級,存在於段或者門描述符中。訪問段或者門的時候,DPL會和CPL和RPL進行比較,根據被訪問的段或者門的型別不同,DPL的定義也有所ubutong

    @資料段:DPL指出執行訪問本資料段的程式所具有的最大特權級數值(就是最小特權級)。
    @非一致性程式碼段(不使用呼叫門):同資料段。
    @呼叫門:同資料段。
    @一致程式碼段和通過呼叫門訪問的非一致程式碼段:由於這種段的設計目的,是為了被低特權級的段共享,它的規則和資料段正好相反,DPL表示指出執行訪問本資料段的程式所具有的最小特權級數值(就是最大特權級)。
    @任務狀態段TSS:同資料段。

3)請求特權級RPL:是一種賦予段選擇符的超越特權級,存放在段選擇符的b0和b1.最終訪問的時候,取max{CPL,RPL}來與DPL進行檢查,RPL的相關介紹可以參考這篇博文。

當段描述符的段選擇符被載入進入段暫存器的時候會進行特權級檢查操作,但用於資料訪問的檢查方式和用於程式碼段之間進行程式控制轉移的檢查方式不一樣。下面分類說明

2.訪問資料段時候的特權級檢查


資料段的檢查方式在第一部分已經有所介紹,注意的是,載入段選擇符的時候就要進行特權級見擦。我們需要注意以下情況:有時候需要將資料儲存在程式碼段中,這時候,訪問程式碼段中的資料需要遵循如下方法

1)將非一致可讀程式碼段的選擇符載入到一個數據段暫存器
2)將一致性可讀程式碼段的選擇符載入到一個數據段暫存器
3)使用程式碼段覆蓋字首(CS)來讀取一個選擇符已經在CS之中的可讀程式碼段。

當使用堆疊段選擇符載入SS暫存器也會執行特權級檢查。這裡,要求CPL=RPL=DPL。

3.程式碼段之間轉移控制時候的特權級檢查


程式成一個程式碼段轉移到新的程式碼段,需要目的碼段的選擇符被載入到CS之中,這個過程,將要執行各種限長、型別、特權級檢查,通過控制轉移指令JMP、RET、INT、IRET以及異常和中斷來實現。我們在這裡,主要談談前四種轉移方法。jmp和call指令可以用以下四種方法來引用另外一個程式碼段。

    @目標運算元含有目的碼段的段選擇符
    @目標運算元指向一個呼叫門描述符,而該描述符中含有目的碼段的選擇符。
    @~~~~~~~~~TSS,~~~~~~~~~~~~~~~~~~~~~
    @~~~~~~~~~任務門~~~TSS~~~目的碼段選擇符
下面,描述前兩種引用型別:

3.1直接呼叫或者跳轉到程式碼段


JMP、CALL、RET指令的近轉移知識在當前程式碼段中執行程式控制轉移,不執行特權級檢查,遠端跳轉才會執行。當不通過呼叫門跳轉時,處理器會驗證四種特權級檢查(CPL,RPL,DPL)和型別(C——一致性標誌)資訊,如下圖:

注意,訪問非一致性程式碼段的時候,段選擇符被載入進CS時候,CPL不會發生變化(即使RPL不等於CPL)。訪問一致性程式碼(C=1),要求CPL>=DPL,而且處理器忽略對於RPL的檢查。當程式被轉移到一致性程式碼中,CPL並不變(及時目的碼的DPL<轉移之前的CPL),這也是CPL和當前程式碼段DPL不同的唯一情況,因為CPL不變,所以堆疊不會切換。

大多數程式碼段都是非一致性程式碼段,所以程式控制只能轉移到相同特權的程式碼中,除非通過呼叫門。這也是和上一段的第一句話結合起來。

3.2門描述符

我們都知道,利用call和jmp進行的直接轉移,無論是一致性程式碼還是非一致性程式碼,CPL是不會改變的。如果想自由地進行不同特權級的切換,需要用到其他幾種方式——門描述符或者TSS。 為了對不同特權級的程式碼段,提供受控的訪問,我們採用門描述符,有四種
    @呼叫門:type=12
    @陷阱門:type=15
    @中斷門:type=14
    @任務門:type=5
這裡,我們僅僅說明呼叫門。

下圖給出了呼叫門描述符的格式,它可以存放在GDT、LDT表中,但是不能放在IDT表中。一個呼叫主要定義了目的碼段的段選擇子、入口地址的偏移+一些屬性,門功能如下:
@指定要訪問的程式碼段
@在指定的程式碼段中定一個過程入口點
@指定訪問過程的呼叫者必須具備的優先順序
@如果發生堆疊切換,制定堆疊之間需要複製的可選引數個數

@指明呼叫門描述符是否有效。


注意,結合上面需求來看描述符格式。linux核心中沒有使用呼叫門,不過它有助於我們理解中斷和異常門。

3.3通過呼叫門來訪問程式碼段


為了訪問呼叫門,我們需要為CALL、JMP指令的運算元提供一個遠指標。該指標中的段選擇符用於指定呼叫門,偏移值雖然需要,但CPU不會使用它,所以可以任意指定(因為真正使用的偏移值是在呼叫門中的)。如下圖

通過呼叫門程序程式的轉移控制的時候,CPU會對CPL、呼叫門選擇符中RPL、呼叫門描述符中的DPL、目的程式碼描述符中的DPL四種不同的特權級進行檢查,如下圖:

另外,目的程式碼的一致性標誌C也將受到檢查。

CALL、JMP指令擁有不同的優先順序檢測規則,見下表。

指令

特權級檢查規則

CALL

CPL<=呼叫門的DPL;RPL<=呼叫門的DPL

對於一致性和非一致性程式碼段都只要求DPL<=CPL

JMP

CPL<=呼叫門的DPL;RPL<=呼叫門的DPL

對於一致性程式碼段要求DPL<=CPL;對於非一致性程式碼段只要求DPL=CPL

解釋一個這個表的內容:檢查分為兩個階段CPL和呼叫門相關特權級進行檢查;CPL和目的程式碼段進行檢查;只有call指令可以將程式碼通過呼叫門轉移到特權級更高的非一致性程式碼之中。


對於非一致性程式碼的成功轉移,CPL被目的程式碼的DPL重新整理,會引起堆疊切換;對於一致性程式碼,不會重新整理,也不會切換。

呼叫門的作用是,讓一個程式碼段中的過程被不同特權級的程式訪問。通常用於低特權級程式碼來訪問高特權級的程式碼段。和jmp和call的直接呼叫相比,這裡共享的只是一個段中的過程,而不是一個完整的段。

3.4堆疊切換


每當呼叫門用於把程式控制轉移到一個更高級別的非一致性程式碼段時,CPU會自動切換到目的程式碼段特權級的堆疊去。每個任務只能定義最多4個棧,分別對應4個特權級。每個棧都位於不同的段中,並且使用段選擇符和段中偏移值指定。

當特權級3的程式在執行時,特權級3的堆疊段選擇符和棧頂指標被分別放在SS和ESP,發生堆疊切換的時候被儲存在被呼叫過程的堆疊上。

特權級0~2的堆疊的初始指標都存放在當前執行任務的TSS段中。TSS段中,這些指標都是隻讀的,任務執行時候,CPU不會修改它們。當呼叫更高級別的程式時,CPU才會用他們來建立新堆疊。當從呼叫過程返回時候,相應堆疊就不存在了。

作業系統負責為所有用到的特權級建立堆疊和堆疊描述符,並且在任務的TSS中初始化指標。每個堆疊必須可讀可寫,並且有足夠的空間,放置如下資訊:
@呼叫過程的SS、ESP、CS、IP
@被呼叫過程的引數和臨時變數所需要使用的空間
@當隱含呼叫一個異常或者中斷過程時,EFLAGS和出錯碼使用的空間
由於一個過程可呼叫其他過程,因此每個棧需要足夠空間容納多套上述資訊。

當通過呼叫門執行一個過程呼叫而改變特權級的時候,CPU會執行以下步驟切換堆疊,並開始在新特權級上執行被呼叫過程,如下圖所示。

1)使用目的程式碼段的DPL從TSS中選擇新棧的指標。從當前TSS讀取新棧的段選擇符和棧指標(為什麼從TSS中讀取?How)
2)檢查段描述符特權級和型別是否有效
3)臨時儲存SS和ESP暫存器的當前值,將新棧段選擇符和棧指標載入到SS和ESP,然後將臨時儲存的SS和ESP壓入堆疊。
4)複製引數
5)把返回指令指標(當前的CS和EIP,此時是指令切換之前)壓入新棧,將新程式碼段選擇符加入CS,同時把呼叫門中的偏移值載入到EIP。最後開始執行被呼叫過程。

3.5從被呼叫過程中返回

RET可以執行近返回,相同/不同特權級之間的遠端返回。
@近返回,僅僅檢查界限
@同特權級遠端返回,彈出EIP和CS,同時執行特權級檢查,防止當前過程可能修改指標值EIP

@會發生特權級別改變的遠端返回僅僅允許返回到低特權級別程式中(例如,通過retf從ring0進入ring3),即返回目的程式碼段的DPL>返回前CPL(注意,此處沒有等於)。CPU會使用selector暫存器中的RPL欄位確定是否要求返回到低特權級。如果RPL>CPL,執行特權級之間的返回操作。當執行遠返回到一個呼叫過程,CPU將執行以下操作:

1)檢查儲存的CS暫存器的RPL欄位(注意,是儲存的CS的RPL,而不是當前的RPL),確定在返回的時候特權級別是否需要改變

2)彈出並使用儲存的CS和EIP
3)如果RET指令包含一個引數個數運算元,並且返回會改變特權級,將把引數個數值加到(注意,是相加,不是載入)ESP暫存器中,以跳過(無用,所以丟棄)被呼叫者堆疊上的引數。此時,ESP暫存器指向原來儲存的呼叫者堆疊的指標SS和ESP
4)將儲存的SS和ESP,載入到對應暫存器,從而切換回堆疊。
5)檢查暫存器DS~GS的內容,如果其中有指向DPL小於新CPL的段(一致性程式碼段除外),那麼CPU就會用NULL選擇符載入這個暫存器

4.頁級保護


分頁機制僅僅識別兩級許可權,特權級0~2是超級使用者,3屬於普通使用者。普通用於的頁面可以設定屬性,超級使用者的頁面對超級使用者總是可讀/可寫/可執行的,但普通使用者不能訪問。及時使用者標註為可讀/可執行的頁面,超級使用者也是可讀/可寫/可執行。

另外,分段與分頁構成一種序列保護機制。

CPU並不維護TLB和頁表的相關性,而是作業系統來維護。通過簡單的重置CR3暫存器,可以重新整理TLB。
特殊情況下,修改頁表項不需要重新整理TLB。當不存在的頁表項被修改,不許要重新整理TLB,因為無效的頁表項不會被存入TLB。







相關推薦

保護模式程式設計——保護詳盡意義通過呼叫轉移特權

摘要:在組合語言的程式設計和作業系統的編寫過程中,我們經常能聽說到“保護模式”這個名詞。為什麼要叫“保護模式”呢?保護 二字的含義何在?本文主要探討,“保護模式”下面各種具體的保護機制,這些保護機制產生的原因和具體的影響。閱讀本文之前,讀者需要了解基本的處理器相關知識,知

3.保護模式7-特權轉移(通過呼叫轉移目標段-無特權轉換)

在上次的程式碼基礎上,新增一個程式碼段作為通過呼叫門轉移的目標段。瞭解一下呼叫的工作方法,程式碼分析如下: <<紅色標識部分為新增程式碼>> ; ========================================== ; pmtest4.asm ; 編譯方法:na

3.保護模式7-特權轉移(通過呼叫轉移目標段-有特權轉換-進入ring3-b)

我們在進入ring3後,實現了高特權級到低特權級的轉移,我們在原有程式碼上稍作修改,實現低特權級到高特權級的轉移: 修改的程式碼如下: 1.修改呼叫門描述符和選擇的特權級 ; 門                               目標選擇子,偏移,DCount, 屬性 LABEL_CALL_G

通過retf和呼叫實現特權轉換

不打算按別人的思路來,因為在我學的過程中上網查,發現網上的部落格都是互相抄的,最終還是抄書的。 Intel 64 和 IA-32架構處理器在進入保護模式之後,就會有一些列保護機制。其中出現了三個特別重要的東西:CPL、DPL、RPL。 CPL表示當前

x86 保護模式程式設計

一、保護機制概念        80x86支援兩類保護機制。         (1)任務之間的保護機制        給每個任務不同的虛擬地址(邏輯地址   段地址:偏移地址)空間來完全隔離各個任務。這是通過給每個任務不同的(從邏輯地址到實體地址的)變換對映機制(函式)。

《x86匯編語言從實模式保護模式》檢測點和習題答案

style 出現 x86匯編 內存操作 3.1 fff 地址 blog strong 檢測點1.1:按順序分別為:13 15 78 255 128 56091 檢測點1.2:按順序分別為:1000 1010 1100 1111 11001 1000000

【OS學習筆記】十四 保護模式段描述符

上一篇文章初步進入保護模式的學習。首先學習了全域性描述符表GDT。點選連結檢視上一篇文章:全域性描述符表 本篇文章繼續學習,GDT中存放的條目:描述符,確切的說是段描述符。學習段描述符的作用以及段描述符的格式。 1、段描述符的格式 真實模式和保護模式,在記憶體訪問上是由區別的

【OS學習筆記】十三 保護模式全域性描述符表(GDT)

上一篇文章,我們大致領略了現代處理器的結構和特點。點解連結檢視上一篇文章:現代處理器的結構和特點 本篇文章開始,學習保護模式下的的各種機制。什麼是保護模式呢? 一般來說,作業系統負責整個計算機軟硬體的的管理,它做任何事情都是可以的。但是使用者程式就應當有所限制,使用者程式它只能訪

TSS詳解 ——《x86組合語言從真實模式保護模式》讀書筆記33

TSS(Task State Segment,任務狀態段)詳解 1. TSS描述符 和LDT一樣,必須為每個TSS在GDT中建立對應的描述符。TSS描述符的格式如下圖: B位是“忙”位(Busy)。在任務剛剛建立的時候,它應該為0,表明任務不忙。當

已解決客戶端無法登入Redis伺服器報錯,解除保護模式

一:問題如下 在192.168.56.57客戶端登入192.168.56.56的redis伺服器時,報錯如下: [[email protected] src]# ./redis-cli

保護模式及其程式設計——中斷和異常處理

摘要:為了提高CPU的利用效率,我們採用了中斷策略來處理某些外部事件。同時,軟體也需要觸發某些中斷和異常,例如除零中斷/page Fault異常等。和子程式呼叫相比,中斷和異常的發生往往是不可預料的,中斷/異常和輪詢相比,能夠顯著提高CPU的工作效率。中斷髮生在任何時刻,相

進入保護模式(二)——《x86組合語言從真實模式保護模式》讀書筆記14

首先來段題外話:之前我發現我貼出的程式碼都沒有行號,給講解帶來不便。所以從現在起,我要給程式碼加上行號。我寫部落格用的這個插入程式碼的外掛,確實不支援自動插入行號。我真的沒有找到什麼好方法,無奈之下,只能按照網友的說法,在VIM中給每行程式碼加上行號,然後再貼出來。 在VI

linux核心 80x86保護模式及其程式設計

這一章涉及intel8086系列cpu的保護模式程式設計,應該是學習核心程式設計,驅動程式設計及嵌入式程式設計一些基礎知識。不過對於沒接觸過底層程式設計的我來說,感覺還是好複雜。   不過裡面也有許多以前彙編學過的東西,大部分還是能看懂的。我覺得圖表就能說明大部分內容了,細

x86分頁機制——《x86組合語言從真實模式保護模式》讀書筆記42

1. 為什麼會有分頁機制? 有些資料說是為了實現“虛擬記憶體”,真的是這樣嗎?如果沒有分頁機制,能否實現“虛擬記憶體”?答案是肯定的。 當同時執行的任務很多時,記憶體可能就不夠用。這時候作業系統就該大展身手了。每個段描述符都有A位,每當訪問一個段時,處理器都

保護模式及其程式設計——真實模式保護模式的切換

機器上電,CPU進入真實模式,從實體地址0xFFFFFFFF0處開始執行初始化程式碼,設定基本系統功能操作必要的資料結構資訊,例如處理中斷和異常的IDT表。接下來,如果繼續在保護模式工作,需要載入作業系統模組;如果要進入真實模式,那麼需要進行模式切換。 1.進入保護模式時的初始化操作 處理器能夠進入到保護模

視訊記憶體文字模式詳解 ———《x86組合語言從真實模式保護模式》讀書筆記補遺02

文章修改記錄 修改日期 修改內容 2018-2-4 修改了一處錯別字;增加了表格的使用方法 今天我們討論如何程式設計以在螢幕上顯示出彩色的文字。 為了顯示文字,通常需要兩種硬體——顯示器和顯示卡。 顯示卡的作用是為顯示器

任務和特權保護(一)——《x86組合語言從真實模式保護模式》讀書筆記27

本文及後面的幾篇文章是原書第14章的讀書筆記。 1.LDT(區域性描述符表) 在之前的學習中,不管是核心程式還是使用者程式,我們都是把段描述符放在GDT中。但是,為了有效實施任務間的隔離,處理器建議每個任務都應該有自己的描述符表,稱為區域性描述符表LDT

儲存器的保護(三)——《x86組合語言從真實模式保護模式》讀書筆記20

儲存器的保護(三) 修改本章程式碼清單,使之可以檢測1MB以上的記憶體空間(從地址0x0010_0000開始,不考慮快取記憶體的影響)。要求:對記憶體的讀寫按雙字的長度進行,並在檢測的同時顯示已檢測的記憶體數量。建議對每個雙字單元用兩個花碼0x55AA5

程式的載入和執行(三)——《x86組合語言從真實模式保護模式》讀書筆記23

程式的載入和執行(三)——讀書筆記23 接著上次的內容說。 關於過程load_relocate_program的講解還沒有完,還差建立棧段描述符和重定位符號表。 1.分配棧空間與建立棧段描述符 462 ;建立程式堆疊段描述符 463

x86 組合語言從真實模式保護模式

1.邏輯地址的作用:程式在記憶體中載入的位置變了,仍然可以執行。 為了在硬體一級提供對“段地址:偏移地址”記憶體訪問模式的支援,處理器至少要提供兩個段暫存器,分別是程式碼段(Code Segment,CS)暫存器和資料段(Data Segment,DS)暫存器