一步步编写操作系统 55 CPL和DPL入门2
接上節(jié)。
圖中第132行的jmp指令,段選擇子為SELECTOR_CODE,其RPL的值為RPL0,RPL0定義在include/boot.inc中,其值為0。選擇子的索引部分值為1,表示對(duì)應(yīng)GDT中第1個(gè)段描述符,該描述符的DPL為0,(它是用include/boot.inc中的DESC_DPL_0定義的,圖中未展示)。
在跳轉(zhuǎn)之前,CS為0,其低2位RPL部分為0,也就是CPL為0,當(dāng)執(zhí)行跳轉(zhuǎn)指令jmp dword SELECTOR_CODE:p_mode_start時(shí),目標(biāo)代碼段(即第1個(gè)段描述符)的DPL為0,與當(dāng)前特權(quán)級(jí)一致(處理器會(huì)根據(jù)CPL、RPL、DPL做特權(quán)級(jí)檢查,此檢查過程咱們?cè)诮榻B完RPL時(shí)再討論),處理器允許轉(zhuǎn)移,所以新的特權(quán)級(jí)依然是0,該值保存在段寄存器CS的低2位,這就是特級(jí)級(jí)轉(zhuǎn)移的粗略過程,也是進(jìn)入保護(hù)模式后特權(quán)為0的來龍去脈。
說完了CPL,咱們?cè)倏纯?#xff0c;受訪者的特權(quán)標(biāo)簽在哪里。
在段描述符中有一個(gè)屬性還為該內(nèi)存標(biāo)明了特權(quán)等級(jí),這就是段描述符中的DPL字段的作用,它就是受訪者的特權(quán)標(biāo)簽。話說,不僅只有段描述符中有DPL字段,以后所介紹的所有描述符都有DPL。
DPL,即Descriptor Privilege Level,描述符特權(quán)級(jí),這下您清楚為什么DPL字段在段描述符中占2位的原因了吧,兩位能表示4個(gè)組合,00b、01b、10b、11b,所有特權(quán)級(jí)都齊了。
計(jì)算機(jī)是人發(fā)明的,用人的思想來理解計(jì)算機(jī)原理是再合適不過的。拿校園生活舉例,班長(zhǎng)權(quán)限比班主任低,班長(zhǎng)有權(quán)限安排學(xué)生打掃衛(wèi)生,班主任有權(quán)限查看學(xué)生成績(jī)。班長(zhǎng)沒權(quán)限查看學(xué)生成績(jī),但班主任有權(quán)限安排學(xué)生打掃衛(wèi)生。這就是擁有高特權(quán)級(jí)的事物可以訪問同級(jí)或更低特權(quán)級(jí)資源,而低特權(quán)級(jí)的事物無法訪問高特權(quán)級(jí)資源的典型例子。
在計(jì)算機(jī)中也一樣,DPL是段描述符所代表的內(nèi)存區(qū)域的“門檻”權(quán)限,訪問者能否邁過此門檻訪問到本描述符所代表的資源,其特權(quán)級(jí)至少要等于這個(gè)門檻,訪問者特權(quán)能否大于該門檻?這要看受訪資源是代碼還是數(shù)據(jù)啦。不難想像,只有具備“能動(dòng)”行為的訪問者才具備訪問的能力,在計(jì)算機(jī)中真正的訪問者是硬件cpu,而指揮cpu行為(訪問誰及如何訪問)的是具有可執(zhí)行能力的指令代碼,數(shù)據(jù)是不能訪問別人的,所以我們?cè)購?qiáng)調(diào)一下訪問者就是代碼段中的指令,這對(duì)理解當(dāng)前特權(quán)級(jí)非常重要。
訪問者任何時(shí)候都不允許訪問比自己特權(quán)更高的資源,無論受訪資源是數(shù)據(jù)還是代碼。在不涉及RPL的前提下,下面咱們要分情況討論啦。
對(duì)于受訪者為數(shù)據(jù)段(段描述符中type字段中未有X可執(zhí)行屬性)來說:
只有訪問者的權(quán)限大于等于該DPL表示的最低權(quán)限才能夠繼續(xù)訪問,否則連這個(gè)門檻都邁不過去。比如,DPL為1的段描述符,只有特權(quán)級(jí)為0、1的訪問者才有資格訪問它所代表的資源,特權(quán)為2、3的訪問者會(huì)被cpu拒之門外。
對(duì)于受訪者為代碼段(段描述符中type字段中含有X可執(zhí)行屬性)來說:
只有訪問者的權(quán)限等于該DPL表示的最低權(quán)限才能夠繼續(xù)訪問,即只能平級(jí)訪問。任何權(quán)限大于或小于它的訪問者都將被cpu拒之門外。這是為什么呢?自問自答之前先明確一個(gè)概念,對(duì)于受訪者為代碼段一這說法,實(shí)際上是指處理器從當(dāng)前運(yùn)行的代碼段上轉(zhuǎn)移到受訪者這個(gè)目標(biāo)代碼段上去執(zhí)行,并不是說把該目標(biāo)代碼段當(dāng)數(shù)據(jù)一樣訪問,在真實(shí)物理機(jī)器上,代碼段通常情況下不被當(dāng)成數(shù)據(jù)來處理的,但確實(shí)可以這么做(話說虛擬機(jī)中會(huì)把代碼當(dāng)成數(shù)據(jù)來處理)。
咱們先說為什么比它特權(quán)級(jí)更高的代碼也無法“訪問”它(即轉(zhuǎn)移到它上面運(yùn)行)。
代碼指令代表cpu的行為,低特權(quán)級(jí)的代碼能做的事,高特權(quán)級(jí)代碼也能做,換句話說高特權(quán)的代碼不需要低特權(quán)代碼的幫助,正常情況下cpu沒有理由先自降等級(jí)后再去做某事。代碼段是cpu執(zhí)行的指令,不是數(shù)據(jù),這里所說的“受訪者為代碼段”其實(shí)就是指cpu從訪問者所在的段轉(zhuǎn)移到該代碼段上去執(zhí)行。舉個(gè)例子,cpu若相當(dāng)于汽車,代碼則相當(dāng)于司機(jī),它指揮cpu前進(jìn)的方向。段的變換相當(dāng)于換了司機(jī),特權(quán)級(jí)較高的代碼段相當(dāng)于技術(shù)水平較高的F1車手,特權(quán)級(jí)較低的代碼段相當(dāng)于技術(shù)水平較低的普通司機(jī),這輛車為了充分展示性能、活得更加精彩,它始終希望它的搭檔是駕駛技術(shù)高超的F1車手,要是把搭檔降級(jí)為普通司機(jī),它可萬萬不能答應(yīng)啊。
不過,凡事都有例外的時(shí)候,這是唯一一種處理器會(huì)從高特權(quán)降到低特權(quán)運(yùn)行的情況:處理器從中斷處理程序中返回到用戶態(tài)的時(shí)候。
中斷處理都是在0特權(quán)級(jí)下進(jìn)行的,因?yàn)橹袛嗟陌l(fā)生多半是外部硬件發(fā)生了某種狀況或發(fā)生了某種不可抗力事件而必須要通cpu導(dǎo)致的,所以,在中斷的處理過程中需要具備訪問硬件的能力,在大多數(shù)情況下只有cpu處于0特權(quán)級(jí)才能訪問硬件,這是因?yàn)閑flags寄存器中的IOPL位的值通常被設(shè)置為0(該位的作用就是限制訪問IO端口的最低特權(quán)級(jí)),并且TSS中不存在 IO位圖,有關(guān)這部分后面馬上會(huì)講到。再者,有些中斷處理中需要的指令只能在0特權(quán)級(jí)下使用,這部分指令稱為特權(quán)指令,所以中斷發(fā)生后其處理的過程必須在0特權(quán)級(jí)下進(jìn)行。用戶進(jìn)程是在3特權(quán)級(jí),在運(yùn)行用戶程序時(shí)若發(fā)生了中斷,cpu會(huì)暫停用戶程序的執(zhí)行,隨后cpu就會(huì)自動(dòng)由3特權(quán)級(jí)進(jìn)入到0特權(quán)級(jí),在0特權(quán)級(jí)下將執(zhí)行用戶程序時(shí)的現(xiàn)場(chǎng)環(huán)境(也就是著名的概念:上下文)保存起來(這個(gè)保存上下文的動(dòng)作可以由cpu通過TSS完成,這是cpu在硬件上提供的功能,但其效率并不高,所以大多數(shù)操作系統(tǒng)都是自己寫代碼手動(dòng)保存上下文環(huán)境),待中斷處理完成后,cpu會(huì)恢復(fù)用戶程序的執(zhí)行,也就是說會(huì)回到3特權(quán)級(jí)。以后在講了中斷和用戶進(jìn)程時(shí)大伙兒會(huì)更清楚這一點(diǎn)。
現(xiàn)在大家知道了,除了從中斷處理過程返回外,任何時(shí)候cpu都不允許從高特權(quán)級(jí)轉(zhuǎn)移到低特權(quán)級(jí)。再結(jié)合之前咱們所說的大前提,訪問者任何時(shí)候都不允許訪問比自己特權(quán)更高的資源,代碼段也是資源,只不過可以讓cpu轉(zhuǎn)移過去執(zhí)行而已,所以,比目標(biāo)代碼段特權(quán)級(jí)低的訪問者也會(huì)被拒絕訪問目標(biāo)代碼段。綜上所述,對(duì)于受訪問者為代碼段的情況,只能是平級(jí)訪問。也就是說,假如當(dāng)前特權(quán)級(jí)為2,只能轉(zhuǎn)移到DPL為2特權(quán)級(jí)的代碼段上運(yùn)行,轉(zhuǎn)移到0、1、3特權(quán)級(jí)都會(huì)被處理器拒絕。
不過本質(zhì)上來說,代碼能否運(yùn)行與代碼本身的特權(quán)等級(jí)并無關(guān)系,不同等級(jí)下的代碼段中的機(jī)器碼都是一樣的,特權(quán)級(jí)只是寫在描述符的DPL中,并沒有寫在機(jī)器碼中,所以高特權(quán)級(jí)的代碼并不比低特權(quán)級(jí)的代碼顯得“高大上”,目標(biāo)段(代碼段或數(shù)據(jù)段)的特權(quán)級(jí)僅僅是在被訪問時(shí)由處理器檢查一次,之后再無用途,所以特權(quán)級(jí)并不影響處理器執(zhí)行指令。把計(jì)算機(jī)資源劃分成不等級(jí),只是讓處理器知道自己正在處理的資源的“份量”有多重,必須用同樣的身份來執(zhí)行,不能兒戲。
如果處理器僅能平移代碼段的話,另外三個(gè)特權(quán)級(jí)的代碼將沒有機(jī)會(huì)運(yùn)行啦。如何穿過特權(quán)屏障呢?處理器又提供了多種方式用于從低特權(quán)的代碼轉(zhuǎn)移到高特權(quán)代碼。
處理器的特權(quán)級(jí)升高之后,程序想干什么就干什么,多少都覺得有點(diǎn)恐怖,有沒有一種好辦法,即執(zhí)行高特權(quán)級(jí)代碼段上的指令,又不提升特權(quán)級(jí)?一種方式是利用一致性代碼段。
什么是一致性代碼段?早在當(dāng)初介紹段描述符結(jié)構(gòu)時(shí)就已經(jīng)提過它了,不過確實(shí)只是提了一下而已以至于您可能完全沒有印象^_^。在段描述符中,如果該段為非系統(tǒng)段(段描述符的S字段為0),可以用type字段中的C位來表示該段是否為一致性代碼段。C為1時(shí)則表示該段是一致性代碼段,C為0時(shí)則表示該段為非一致性代碼段。上面所提到的代碼段是非一致性代碼段,所以只能平級(jí)轉(zhuǎn)移。
一致性代碼段也稱為依從代碼段,Conforming,用來實(shí)現(xiàn)從低特權(quán)級(jí)的代碼向高特權(quán)級(jí)的代碼轉(zhuǎn)移。一致性代碼段是指,如果自己是轉(zhuǎn)移后的目標(biāo)段,自己的特權(quán)級(jí)(DPL)一定要大于等于轉(zhuǎn)移前的CPL,即數(shù)值上CPL>=DPL,也就是一致性代碼段的DPL是權(quán)限的上限,任何在此權(quán)限之下的特權(quán)級(jí)都可以轉(zhuǎn)到此代碼段上執(zhí)行。這是似乎很奇怪但卻意料之中,奇怪的是,低特權(quán)級(jí)訪問高特權(quán)級(jí)居然是可以的,而意料之中的是,這才能實(shí)現(xiàn)了代碼轉(zhuǎn)移。該關(guān)系用公式表示如下:
在數(shù)值上,CPL >=一致性代碼段的DPL。
一致性代碼段的一大特點(diǎn)是,轉(zhuǎn)移后的特權(quán)級(jí)不與自己的特權(quán)級(jí)(DPL)為主,而是與轉(zhuǎn)移前的低特權(quán)級(jí)一致,聽從、依從轉(zhuǎn)移前的低特權(quán)級(jí),這就是它稱為“依從、一致”的原因。也就是說,處理器遇到目標(biāo)段為一致性代碼段時(shí),并不會(huì)將CPL用該目標(biāo)段的DPL替換。
大家注意啦,既然是轉(zhuǎn)移到特權(quán)級(jí)更高的一致性代碼段后CPL不變,這說明這種轉(zhuǎn)移本身并沒有提升特權(quán)級(jí),只是可以跑到特權(quán)級(jí)更高的代碼段中去執(zhí)行指令,對(duì)計(jì)算機(jī)而言并未造成因特權(quán)級(jí)升高而產(chǎn)生潛在危險(xiǎn),所以在特權(quán)級(jí)檢查過程中,請(qǐng)求者的RPL并不參與。
特權(quán)級(jí)檢查是發(fā)生在訪問者訪問受訪者的一瞬間,只檢查一次,在檢查過后,在該段上以后的執(zhí)行過程中也不會(huì)再被檢查,處理器也并不會(huì)因?yàn)閳?zhí)行了高特權(quán)級(jí)的代碼而覺得自己了不起,在它眼里任何級(jí)別的指令都是一樣的。特權(quán)級(jí)就是一個(gè)個(gè)的關(guān)卡,僅僅是進(jìn)門時(shí)的檢測(cè)而已,與關(guān)卡后面的代碼和數(shù)據(jù)無關(guān)。這種情況類似必須要刷工卡才能進(jìn)公司一樣,即使不刷工卡,您的工位還是那個(gè)工位,電腦還是那個(gè)電腦,您照樣還是可以使用它們,這些資源并不會(huì)有什么改變,它們與咱們是否刷工卡是無關(guān)的。所以,盡管轉(zhuǎn)移到一致性代碼段后CPL還保持為原來的低特權(quán)級(jí)并未提升,但也沒什么好奇怪的,畢竟目的是運(yùn)行目標(biāo)代碼段上的指令,達(dá)到目的就行了,何必在意身份呢,人家西游記里的孫悟空當(dāng)初只是弼馬溫的時(shí)候,由于其身份卑微是無法參加王母娘娘蟠桃大會(huì)的,最后還不是一樣把蟠桃吃個(gè)夠,碉堡了^_^。
順便說一句,代碼段可以有一致性和非一致性之分,但所有的數(shù)據(jù)段總是非一致的,即,數(shù)據(jù)段不允許被比本數(shù)據(jù)段特權(quán)級(jí)更低的代碼段訪問。
按理說,把代碼劃分為不同等級(jí)就是為了等級(jí)變換,如果還以卑微的身份去運(yùn)行高特權(quán)級(jí)的代碼,似乎不夠體面,人家孫悟空為了面子還號(hào)稱為齊天大圣呢,其實(shí)cpu中實(shí)現(xiàn)特權(quán)級(jí)變換的“門路”多著呢,還有4個(gè)“門”。
總結(jié)
以上是生活随笔為你收集整理的一步步编写操作系统 55 CPL和DPL入门2的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一次办信用卡哪个银行额度高
- 下一篇: java lambda 循环list_J