天天看點

使用者态和核心态簡析

當一個任務(程序)執行系統調用而陷入核心代碼中執行時,我們就稱程序處于核心運作态(或簡稱為核心态)。此時處理器處于特權級最高的(0級)核心 代碼中執行。當程序處于核心态時,執行的核心代碼會使用目前程序的核心棧。每個程序都有自己的核心棧。當程序在執行使用者自己的代碼時,則稱其處于使用者運作 态(使用者态)。即此時處理器在特權級最低的(3級)使用者代碼中運作。當正在執行使用者程式而突然被中斷程式中斷時,此時使用者程式也可以象征性地稱為處于程序 的核心态。因為中斷處理程式将使用目前程序的核心棧。這與處于核心态的程序的狀态有些類似。 

核心态與使用者态是作業系統的兩種運作級别, 跟intel cpu沒有必然的聯系, intel cpu提供Ring0-Ring3三種級别的運作模式,Ring0級别最高,Ring3最低。Linux使用了Ring3級别運作使用者态,Ring0作為 核心态,沒有使用Ring1和Ring2。Ring3狀态不能通路Ring0的位址空間,包括代碼和資料。Linux程序的4GB位址空間,3G-4G部 分大家是共享的,是核心态的位址空間,這裡存放在整個核心的代碼和所有的核心子產品,以及核心所維護的資料。使用者運作一個程式,該程式所建立的程序開始是運 行在使用者态的,如果要執行檔案操作,網絡資料發送等操作,必須通過write,send等系統調用,這些系統調用會調用核心中的代碼來完成操作,這時,必 須切換到Ring0,然後進入3GB-4GB中的核心位址空間去執行這些代碼完成操作,完成後,切換回Ring3,回到使用者态。這樣,使用者态的程式就不能 随意操作核心位址空間,具有一定的安全保護作用。

至于說保護模式,是說通過記憶體頁表操作等機制,保證程序間的位址空間不會互相沖突,一個程序的操作不會修改另一個程序的位址空間中的資料。

1. 使用者态和核心态的概念差別

究竟什麼是使用者态,什麼是核心态,這兩個基本概念以前一直了解得不是很清楚,根本原因個人覺得是在于因為大部分時候我們在寫程式時關注的重點和着眼的角度放在了實作的功能和代碼的邏輯性上,先看一個例子:

1)例子

void testfork(){

if(0 = = fork()){

printf(“create new process success!\n”);

}

printf(“testfork ok\n”);

這段代碼很簡單,從功能的角度來看,就是實際執行了一個fork(),生成一個 新的程序,從邏輯的角度看,就是判斷了如果fork()傳回的是0則列印相關語句,然後函數最後再列印一句表示執行完整個testfork()函數。代碼 的執行邏輯和功能上看就是如此簡單,一共四行代碼,從上到下一句一句執行而已,完全看不出來哪裡有展現出使用者态和程序态的概念。

如果說前面兩種是靜态觀察的角度看的話,我們還可以從動态的角度來看這段代碼,即它被轉換成CPU執行的指令後加載執行的過程,這時這段程式就是一個動态執行的指令序列。而究竟加載了哪些代碼,如何加載就是和作業系統密切相關了。

2)特權級

熟悉Unix/Linux系統的人都知道,fork的工作實際上是以系統調用的 方式完成相應功能的,具體的工作是由sys_fork負責實施。其實無論是不是Unix或者Linux,對于任何作業系統來說,建立一個新的程序都是屬于 核心功能,因為它要做很多底層細緻地工作,消耗系統的實體資源,比如配置設定實體記憶體,從父程序拷貝相關資訊,拷貝設定頁目錄頁表等等,這些顯然不能随便讓哪 個程式就能去做,于是就自然引出特權級别的概念,顯然,最關鍵性的權力必須由高特權級的程式來執行,這樣才可以做到集中管理,減少有限資源的通路和使用沖 突。

特權級顯然是非常有效的管理和控制程式執行的手段,是以在硬體上對特權級做了很 多支援,就Intel x86架構的CPU來說一共有0~3四個特權級,0級最高,3級最低,硬體上在執行每條指令時都會對指令所具有的特權級做相應的檢查,相關的概念有 CPL、DPL和RPL,這裡不再過多闡述。硬體已經提供了一套特權級使用的相關機制,軟體自然就是好好利用的問題,這屬于作業系統要做的事情,對于 Unix/Linux來說,隻使用了0級特權級和3級特權級。也就是說在Unix/Linux系統中,一條工作在0級特權級的指令具有了CPU能提供的最 高權力,而一條工作在3級特權級的指令具有CPU提供的最低或者說最基本權力。

3)使用者态和核心态

現在我們從特權級的排程來了解使用者态和核心态就比較好了解了,當程式運作在3級 特權級上時,就可以稱之為運作在使用者态,因為這是最低特權級,是普通的使用者程序運作的特權級,大部分使用者直接面對的程式都是運作在使用者态;反之,當程式運 行在0級特權級上時,就可以稱之為運作在核心态。

雖然使用者态下和核心态下工作的程式有很多差别,但最重要的差别就在于特權級的不 同,即權力的不同。運作在使用者态下的程式不能直接通路作業系統核心資料結構和程式,比如上面例子中的testfork()就不能直接調用 sys_fork(),因為前者是工作在使用者态,屬于使用者态程式,而sys_fork()是工作在核心态,屬于核心态程式。

當我們在系統中執行一個程式時,大部分時間是運作在使用者态下的,在其需要操作系 統幫助完成某些它沒有權力和能力完成的工作時就會切換到核心态,比如testfork()最初運作在使用者态程序下,當它調用fork()最終觸發 sys_fork()的執行時,就切換到了核心态。

2. 使用者态和核心态的轉換

1)使用者态切換到核心态的3種方式

a. 系統調用

這是使用者态程序主動要求切換到核心态的一種方式,使用者态程序通過系統調用申請使 用作業系統提供的服務程式完成工作,比如前例中fork()實際上就是執行了一個建立新程序的系統調用。而系統調用的機制其核心還是使用了作業系統為使用者 特别開放的一個中斷來實作,例如Linux的int 80h中斷。

b. 異常

當CPU在執行運作在使用者态下的程式時,發生了某些事先不可知的異常,這時會觸發由目前運作程序切換到處理此異常的核心相關程式中,也就轉到了核心态,比如缺頁異常。

c. 外圍裝置的中斷

當外圍裝置完成使用者請求的操作後,會向CPU發出相應的中斷信号,這時CPU會 暫停執行下一條即将要執行的指令轉而去執行與中斷信号對應的處理程式,如果先前執行的指令是使用者态下的程式,那麼這個轉換的過程自然也就發生了由使用者态到 核心态的切換。比如硬碟讀寫操作完成,系統會切換到硬碟讀寫的中斷處理程式中執行後續操作等。

這3種方式是系統在運作時由使用者态轉到核心态的最主要方式,其中系統調用可以認為是使用者程序主動發起的,異常和外圍裝置中斷則是被動的。

2)具體的切換操作

從觸發方式上看,可以認為存在前述3種不同的類型,但是從最終實際完成由使用者态 到核心态的切換操作上來說,涉及的關鍵步驟是完全一緻的,沒有任何差別,都相當于執行了一個中斷響應的過程,因為系統調用實際上最終是中斷機制實作的,而 異常和中斷的處理機制基本上也是一緻的,關于它們的具體差別這裡不再贅述。關于中斷處理機制的細節和步驟這裡也不做過多分析,涉及到由使用者态切換到核心态 的步驟主要包括:

[1] 從目前程序的描述符中提取其核心棧的ss0及esp0資訊。

[2] 使用ss0和esp0指向的核心棧将目前程序的cs,eip,eflags,ss,esp資訊儲存起來,這個

過程也完成了由使用者棧到核心棧的切換過程,同時儲存了被暫停執行的程式的下一

條指令。

[3] 将先前由中斷向量檢索得到的中斷處理程式的cs,eip資訊裝入相應的寄存器,開始

執行中斷處理程式,這時就轉到了核心态的程式執行了。

轉自:http://www.cnblogs.com/viviwind/archive/2012/09/22/2698450.html

本文轉自 古道卿 51CTO部落格,原文連結:http://blog.51cto.com/gudaoqing/1586027

繼續閱讀