計算機怎麼知道用戶態和內核態?

cpu本身就支持不同特權的指令,我的問題是 如果我懂機器碼 那麼有可能寫出能夠以cpu最高特權執行的代碼嗎? 是否因為引導程序 所引導的程序就是cpu默認賦予以最高特權執行的(操作系統) 其他程序就靠操作系統去管理 (無法直接用特權指令)


保護模式下CS寄存器的低兩位決定了當前CPU的特權等級:

這部分雖然是顯式的寫在CS的值里的,但實際上是隱藏在段寄存器的隱藏部分的。

最開始的時候CS值是引導程序給的,引導程序置上PE位以後,代碼還在16位模式下,CPU會給當前的CS寄存器隱藏部分添加一個RPL,這個RPL是0,之後等跳轉到保護模式以後,由代碼控制自己選擇到那個RPL上跑。

如果自己寫一個引導程序,到保護模式以後,不加準備直接切到R3級別的CS的話,那麼後面的代碼就是R3的許可權了。

你懂機器碼就一定能寫出R0的代碼嗎?不一定。

你的代碼是被OS的載入器載入的,載入的過程中,CS的初始值是確定的,如果操作系統沒給你R0的許可權,你的代碼必然要在R3上執行,在保護模式下,R3狀態下的指令想通過MOV來改變CS是有可能觸發異常的,而OS能決定你的動作是否能觸發異常。

所以如果OS把這些路否封死了,你的代碼只能老老實實的在R3上執行。

我前面說了,引導程序可以在進入保護模式後直接把自己的代碼設置成R3許可權,這是沒問題的,但如果切保護模式之前,沒把該準備的東西準備好,那麼你的代碼可能就一直在R3模式下跑了,想從R3到R0是沒門的。

另外,實模式下操作系統處於R0狀態。

根據評論里的補充,前面有一塊我說的不太正確,RPL雖然是在CS里,但CS只是個index selector,RPL實際保存的地方是段寄存器的隱藏部分,這部分是不可見也不能直接修改的。


瀉藥,我只說x86上的情況吧。

x86是cs段選擇子的rpl就是cpl,四種可能的取值對應ring0到ring3。在x86上面實現操作系統時ring0用來對應內核態,ring3對應用戶態,其他兩種一般不被使用。

可以參考這個CPU Rings, Privilege, and Protection,裡面有圖,可以看到cpl位於16位的選擇子的低0到1位。

這個許可權管理模式背後的原理其實很容易理解。就比如你是國家統治階層,你不讓民眾使用你統治階層的特權,那民眾永遠是民眾沒有機會成為統治階級。


按照傳統BIOS的啟動方式來說一下吧,不討論UEFI了。

開機CPU處於16位的實模式,這個模式沒有許可權的概念,所有東西都是Ring0。

MBR(磁碟引導扇區里的代碼)就是在這個模式下運行的。

MBR的作用是載入PBR(分區的引導扇區的代碼)或BootLoader(比如GRUB)

PBR的作用是載入BootLoader(比如Windows2000/XP/2003的ntldr和Windows Vista/2008/7/2008R2/8/2012/8.1/2012R2/10/2016的bootmgr)

PBR跟MBR一樣,也是在實模式下運行的,那個模式只有RING 0。

BootLoader啟動的時候也是實模式,BootLoader在內存里建立轉換到32位保護模式/64位長模式需要的各種數據結構,然後把CPU轉換到32位/64位模式,並跳轉到BootLoader的32位/64位的部分,跳轉時指定許可權RING 0。

這部分代碼載入各種內核的東西,初始化操作系統內核。

然後內核載入用戶態的東西,調用的時候(怎麼調用的不記得了)指定許可權RING 3(CPU有個標誌位來判斷當前是RING幾),於是被調用的東西只能執行一部分指令。

用戶態的東西要調用系統的東西,通過Fast Fail/Sys Call之類的我記不清了的東西跳轉到一個RING 0的狀態下,然後調用系統的運行在RING 0模式的代碼。

-----

好像傳說中Windows沒有使用RING1和RING2?


x86來說引導程序是實模式,是16位的8086代碼。引導程序並不做特權處理,而是載入硬碟上的操作系統引導程序。操作系統引導程序入口為16的8086代碼,在實模式下執行。實模式可以進入特權模式,進入特權模式之後就只有特權代碼才能執行,操作系統內核,或者硬體驅動程序等,是特權模式。普通用戶也能執行特權指令,這個時候就觸發異常。操作系統內核可以模擬特權指令執行的效果,這個時候執行特權指令,相當於系統調用一樣。當然操作系統也可以直接拋出異常。虛擬機技術,就是這樣實現的。當然這種方式性能比較低,於是intel又出了vmm模式,在原有的特權模式上,又加了一層,這樣客戶機操作系統執行特權指令,大部分不需要宿主操作系統來模擬,只有少數一些指令需要陷入異常來處理。cpu是如何知道特權指令該不該執行的,這個內部有標誌位,來標誌當前是啥模式,不同模式下特權指令有不同的處理方式。


對於題主……我發現我最近看到了本書挺適合解決問題的……

30天自製操作系統。

以下引用(手機編輯可能有錯誤)

在段定義的地方,如果將訪問許可權加上0x60的話,就可以將段設置為應用程序用。當CS中的段地址為應用程序用段地址時,CPU會認為「當前正在運行應用程序」,這時如果存入操作系統用的段地址就會產生異常。(P435)

如果將應用程序設置在LDT中,其他的任務由於無法使用該LDT,也就不用擔心它們來搞破壞了。(P580)

以上兩段闡述了如何阻止正在運行的程序對操作系統和其他程序的破壞。簡單說就是你程序運行的內存是操作系統分配給你的,正常情況下處於應用程序模式,既無法運行cpu某些指令(比如jmp),也無法單憑應用程序更改許可權

(以上為正常運行狀態,以下為系統啟動狀態,以傳統模式為例)

當計算機通電時,BIOS處於16位實模式,然後BIOS自檢讀取啟動盤,找到啟動扇區。此時CPU處於最高許可權(應該是叫ring0),此時啟動扇區相關代碼將命令計算機載入操作系統核心部分(好像就是內核),載入完成後,通常情況下會切換到CPU操作系統保護模式(注意這是代碼寫的,不是強制),然後才開始載入其他各種各樣的東西並啟動系統。

所以總的來說,計算機知道「用戶態」和「內核態」可以說完全是由計算機剛啟動時引導扇區寫的。哪怕題主你懂得機器語言(彙編嗎?),由於對指令限制是直接寫在了內存段上,因此只要你的程序是被操作系統啟動的,那麼就無法對操作系統產生破壞。(未驗證,純猜測:雖然無法對操作系統產生破壞,但是不代表不可以對硬體產生破壞)

同時,根據《30》的說法,如果應用程序需要調用操作系統的相關指令,只能通過api調用。(然後這段我忘了QAQ,我猜測應該可以通過產生一個中斷然後退回去值就好)


你寫個linux核心驅動程序就是在最高級別運行了嘛。哥當年寫一個小驅動,循環語句寫錯成死循環,然後機器就死在那裡了,死死的[二哈]


x86下通過cs上的特權級


可以去看下保護模式編程,看個大概後找於淵的書看看


這個問題挺有意思,已經有大神說過了兩種狀態的區別了,我就補充一點自己的理解,關於用戶態向內核態的切換。

用戶準備好參數,通過觸發軟中斷,CPU進入內核態,執行操作系統準備好的中斷處理程序。由於用戶只能改變參數,而不能改變處理程序本身,內核保護自身不被破壞。


x86架構下,你的cs,ss,gs,es寄存器里存的是段選擇子,根據這個判斷~

x86_64裡面似乎沒有分段了,直接就是分頁,而且特權級只有0和3,1和2都直接沒了~


推薦閱讀:

Win 向Mac遷移的用戶,那些建議可以幫助新用戶更好地適應OS X?
在 Windows 普遍的大學 Mac 各種不方便要怎麼破?
操作系統多進程多線程的相關問題?
在可見的將來,我們能看到國產操作系統崛起嗎?
在內存讀寫速度可以達到20~30GB/S的現在(DDR3末期,DDR4早期),為什麼PC或MAC的內存測試依然需要動輒數小時?

TAG:操作系統 | 操作系統內核 |