任务和特权级保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记27
本文及后面的幾篇文章是原書第14章的讀書筆記。
1.LDT(局部描述符表)
在之前的學(xué)習(xí)中,不管是內(nèi)核程序還是用戶程序,我們都是把段描述符放在GDT中。但是,為了有效實(shí)施任務(wù)間的隔離,處理器建議每個(gè)任務(wù)都應(yīng)該有自己的描述符表,稱為局部描述符表LDT(Local Descriptor Table),并且把專屬于這個(gè)任務(wù)的那些段描述符放到LDT中。
和GDT一樣,LDT也是用來存放段描述符的。不同之處在于,LDT只屬于某個(gè)任務(wù)。或者說,每個(gè)任務(wù)都有自己的LDT,每個(gè)任務(wù)私有的段,都應(yīng)當(dāng)在LDT中進(jìn)行描述。
需要注意的是:LDT的0號(hào)槽位,是有效的,可以使用的。
GDT是全局性的,為所有的任務(wù)服務(wù),是它們所共有的,我們只需要一個(gè)GDT就夠了。為了追蹤GDT,訪問它內(nèi)部的描述符,處理器使用了GDTR寄存器。
和GDT不同,LDT的數(shù)量不止一個(gè),具體有多少,根據(jù)任務(wù)的數(shù)量而定。為了追蹤和訪問這些LDT,處理器使用了LDTR(局部描述符表寄存器)。在一個(gè)多任務(wù)的系統(tǒng)中,會(huì)有很多任務(wù)輪流執(zhí)行,正在執(zhí)行的那個(gè)任務(wù),稱為當(dāng)前任務(wù)(Current Task)。因?yàn)長(zhǎng)DTR只有一個(gè),所以,它只用于指向當(dāng)前任務(wù)的LDT。每當(dāng)發(fā)生任務(wù)切換時(shí),LDTR的內(nèi)容被更新,以指向新任務(wù)的LDT。
當(dāng)向段寄存器加載段選擇子的時(shí)候,段選擇子的TI(Bit2)位是表指示器(Table Indicator)。
TI=0:處理器從GDT中加載描述符
TI=1:處理器從LDT中加載描述符
因?yàn)槊枋龇饕加昧?3個(gè)比特,所以每個(gè)LDT最多能容納的描述符個(gè)數(shù)是8192(2的13次方),也就是說每個(gè)LDT只能定義8192個(gè)段;又因?yàn)槊總€(gè)段描述符占用8個(gè)字節(jié),所以LDT的最大長(zhǎng)度是64KB(2的16次方)。
2.TSS(任務(wù)狀態(tài)段)
在一個(gè)多任務(wù)環(huán)境中,當(dāng)任務(wù)發(fā)生切換時(shí),必須保存現(xiàn)場(chǎng)(比如通用寄存器,段寄存器,棧指針等)。為了保存被切換任務(wù)的狀態(tài),并且在下次執(zhí)行它時(shí)恢復(fù)現(xiàn)場(chǎng),每個(gè)任務(wù)都應(yīng)當(dāng)有一片內(nèi)存區(qū)域,專門用于保存現(xiàn)場(chǎng)信息,這就是任務(wù)狀態(tài)段(Task State Segment)。
TSS的格式如下圖所示:
TSS的最小尺寸是104(0x68=104)字節(jié)。
和LDT類似,處理器用任務(wù)寄存器TR(Task Register)指向當(dāng)前任務(wù)的TSS。和GDTR、LDTR一樣,TR在處理器中也只有一個(gè)。當(dāng)任務(wù)發(fā)生切換的時(shí)候,TR的內(nèi)容會(huì)跟著指向新任務(wù)的TSS。這個(gè)過程是這樣的:首先,處理器將要掛起的任務(wù)的現(xiàn)場(chǎng)信息保存到TR指向的TSS;然后,使TR指向新任務(wù)的TSS,并從這個(gè)TSS中恢復(fù)現(xiàn)場(chǎng)。
下圖是我根據(jù)原書圖14-1繪制而成的,對(duì)我們理解GDTR、TR、LDTR和多任務(wù)的關(guān)系很有幫助。
3.全局空間和局部空間
每個(gè)任務(wù)實(shí)際上包括兩個(gè)部分:全部部分和私有部分。全局部分是所有任務(wù)共有的,含有操作系統(tǒng)的數(shù)據(jù)、庫程序、系統(tǒng)調(diào)用等;私有部分是每個(gè)任務(wù)自己的數(shù)據(jù)和代碼,與任務(wù)要實(shí)現(xiàn)的功能有關(guān),彼此并不相同。
從內(nèi)存的角度來看,所謂的全局部分和私有部分,其實(shí)是地址空間的劃分,即全局地址空間(簡(jiǎn)稱全局空間)和局部地址空間(簡(jiǎn)稱局部空間)。
對(duì)地址空間的訪問離不開分段機(jī)制,全局地址空間用GDT來指定,局部地址空間由每個(gè)任務(wù)私有的LDT來指定。
從程序員的角度看,任務(wù)的全局空間包含了操作系統(tǒng)的段,是由別人編寫的,但是他可以調(diào)用這些段的代碼,或者獲取這些段中的數(shù)據(jù);任務(wù)的局部空間的內(nèi)容是由程序員自己編寫的。通常,任務(wù)在自己的局部空間運(yùn)行,當(dāng)它需要操作系統(tǒng)提供的服務(wù)時(shí),轉(zhuǎn)入全局空間執(zhí)行。
4.特權(quán)級(jí)保護(hù)概述
在分段機(jī)制的基礎(chǔ)上,處理器引入了特權(quán)級(jí)的概念,并由固件負(fù)責(zé)實(shí)施特權(quán)級(jí)保護(hù)。
特權(quán)級(jí)(Privilege Level),是存在于描述符及其選擇子中的一個(gè)數(shù)值。當(dāng)這些描述符或者選擇子所指向的對(duì)象要進(jìn)行某種操作,或者被別的對(duì)象訪問時(shí),該數(shù)值用于控制它們所能進(jìn)行的操作,或者限制它們的可訪問性。
Intel處理器可以識(shí)別4個(gè)特權(quán)級(jí)別,分別是0~3,數(shù)值越小特權(quán)級(jí)越高。
如下圖所示(圖片來自維基百科):這是Intel處理器所提供的4級(jí)環(huán)狀結(jié)構(gòu)。
通過,操作系統(tǒng)是為所有程序服務(wù)的,可靠性最高,而且必須對(duì)軟硬件有完全的控制權(quán),所以它的主體部分必須擁有特權(quán)級(jí)0,處于整個(gè)環(huán)形結(jié)構(gòu)的中心。因此,操作系統(tǒng)的主體部分通常被稱作內(nèi)核(Kernel、Core)。
特權(quán)級(jí)1和2通常賦予那些可靠性不如內(nèi)核的系統(tǒng)服務(wù)程序,比較典型的就是設(shè)備驅(qū)動(dòng)程序。不過,在很多流行的操作系統(tǒng)中,驅(qū)動(dòng)程序也是0特權(quán)級(jí)。
應(yīng)用程序的可靠性被視為是最低的,而且通常不需要直接訪問硬件和一些敏感的系統(tǒng)資源,通過調(diào)用設(shè)備驅(qū)動(dòng)程序和操作系統(tǒng)例程就能完成絕大多數(shù)工作,所以賦予它們最低的特權(quán)級(jí)別3.
5.CPL,DPL,RPL
想搞清楚段級(jí)保護(hù),必須要弄懂這三個(gè)概念。
5.1.CPL
CPL:當(dāng)前特權(quán)級(jí)(Current Privilege Level),存在于CS寄存器的低兩位。
當(dāng)處理器正在一個(gè)代碼段中取指令和執(zhí)行時(shí),這個(gè)代碼段所在的特權(quán)級(jí)叫做當(dāng)前特權(quán)級(jí)。正在執(zhí)行的這個(gè)代碼段,其選擇子位于段寄存器CS中,CS中的低兩位就是當(dāng)前特權(quán)級(jí)的數(shù)值。
一般來說,操作系統(tǒng)的代碼正在執(zhí)行時(shí),CPL就等于0;
相反,普通的應(yīng)用程序則工作在特權(quán)級(jí)3上。應(yīng)用程序的加載和執(zhí)行,是由操作系統(tǒng)主導(dǎo)的,操作系統(tǒng)一定會(huì)將其放在特權(quán)級(jí)3上(具體的做法,我們會(huì)慢慢學(xué)到)。當(dāng)應(yīng)用程序開始執(zhí)行時(shí),CPL自然會(huì)是3.
需要注意的是,不能僵化地看待任務(wù)和任務(wù)的特權(quán)級(jí)別。當(dāng)任務(wù)在自己的局部空間執(zhí)行時(shí),CPL等于3;當(dāng)它通過調(diào)用系統(tǒng)服務(wù),進(jìn)入操作系統(tǒng)內(nèi)核,在全局空間執(zhí)行時(shí),CPL就變成了0.(具體過程我們會(huì)在后面講解。)
5.2.DPL
DPL:描述符特權(quán)級(jí)(Descriptor Privilege Level),存在于段描述符中的DPL字段。
DPL是每個(gè)描述符都有的字段,故又稱描述符特權(quán)級(jí)。描述符總是指向它所描述的目標(biāo)對(duì)象,代表著該對(duì)象。因此,DPL實(shí)際上是目標(biāo)對(duì)象的特權(quán)級(jí)。
如果你忘了描述符的格式,可以看看下圖。
5.3.RPL
RPL:請(qǐng)求特權(quán)級(jí)(Requested Privilege Level),存在于段選擇子的低兩位。
要想將控制從一個(gè)代碼段轉(zhuǎn)移到另一個(gè)代碼段,通常是使用jmp或者call指令,并在指令中提供目標(biāo)代碼段的選擇子和偏移;為了訪問內(nèi)存中的數(shù)據(jù),也必須先將段選擇子加載到段寄存器,比如DS、ES、FS、GS中。不管是實(shí)施控制轉(zhuǎn)移還是訪問數(shù)據(jù)段,這都可以看成是一個(gè)請(qǐng)求,請(qǐng)求者提供一個(gè)段選擇子,請(qǐng)求訪問指定的段。從這個(gè)意義上來說,RPL也就是指請(qǐng)求者的特權(quán)級(jí)別。
也許你會(huì)疑惑:有CPL和DPL進(jìn)行判斷不就可以了嗎?為什么還需要一個(gè)RPL呢?
因?yàn)楫?dāng)?shù)吞貦?quán)級(jí)的應(yīng)用程序使用call far指令通過調(diào)用門將控制轉(zhuǎn)移到較高特權(quán)級(jí)的非一致代碼段(例如操作系統(tǒng)提供的例程,假設(shè)此代碼段的DPL=0)時(shí),會(huì)改變當(dāng)前的特權(quán)級(jí),而在目標(biāo)代碼段的特權(quán)級(jí)上執(zhí)行,對(duì)于本例來說CPL的數(shù)值就會(huì)變成操作系統(tǒng)例程段的DPL的數(shù)值,即0。如果沒有RPL,那么此時(shí)CPL權(quán)限是最高的,也就可以去訪問任何數(shù)據(jù),這就不安全了。所以引入RPL,讓它代表訪問權(quán)限,因此在檢查CPL的同時(shí),也會(huì)檢查RPL.一般來說如果RPL的數(shù)值比CPL大(權(quán)限比CPL的低),那么RPL會(huì)起決定性作用。
6.IO特權(quán)級(jí)
在處理器的標(biāo)志寄存器EFLAGS中,位12、13是IOPL位,也就是輸入/輸出特權(quán)級(jí)(I/O Privilege Level),它代表著當(dāng)前任務(wù)的I/O特權(quán)級(jí)別。
如果CPL在數(shù)值上小于等于IOPL,那么所有的I/O操作都是允許的,針對(duì)任何硬件端口的訪問都可以通過。
相反,如果CPL的數(shù)值大于IOPL,也并不意味著所有的硬件端口都對(duì)當(dāng)前任務(wù)關(guān)上了大門。事實(shí)上,處理器的意思是總體上不允許,但個(gè)別端口除外。至于是哪些個(gè)別端口,要找到當(dāng)前任務(wù)的TSS,并檢索I/O許可位串(具體細(xì)節(jié)我們以后會(huì)說)。
只有當(dāng)CPL=0時(shí),程序才可以使用POPF或IRET指令修改這個(gè)字段。
總結(jié)
以上是生活随笔為你收集整理的任务和特权级保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记27的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 输入两个长度相同的字符串,比较两个数在相
- 下一篇: 代码段间转移控制时的特权级检查(JMP/