1、特權級
Intel x86架構的cpu一共有0~4四個特權級,0級最高,3級最低,硬件上在執行每條指令時都會對指令所具有的特權級做相應的檢查。硬件已經提供了一套特權級使用的相關機制,軟件自然要好好利用,這屬于操作系統要做的事情,對于UNIX/LINUX來說,只使用了0級特權級別和3級特權級。也就是說在UNIX/LINUX系統中,一條工作在0級特權級的指令具有了CPU能提供的最高權力,而一條工作在3級特權的指令具有CPU提供的最低或者說最基本權力
2、用戶態和內核態
內核棧:Linux中每個進程有兩個棧,分別用于用戶態和內核態的進程執行,其中的內核棧就是用于內核態的堆棧,它和進程的task_struct結構,更具體的是thread_info結構一起放在兩個連續的頁框大小的空間內。
現在我們從特權級的調度來理解用戶態和內核態就比較好理解了,當程序運行在3級特權級上時,就可以稱之為運行在用戶態,因為這是最低特權級,是普通的用戶進程運行的特權級,大部分用戶直接面對的程序都是運行在用戶態;反之,當程序運行在0級特權級上時,就可以稱之為運行在內核態。
雖然用戶態下和內核態下工作的程序有很多差別,但最重要的差別就在于特權級的不同,即權力的不同。運行在用戶態的程序不能訪問操作系統內核數據結構合程序。 當我們在系統中執行一個程序時,大部分時間是運行在用戶態下的。在其需要操作系統幫助完成某些它沒有權力和能力完成的工作時就會切換到內核態。
Linux進程的4GB地址空間,3G-4G部分大家是共享的,是內核態的地址空間,這里存放在整個內核的代碼和所有的內核模塊,以及內核所維護的數據。用戶運行一個程序,該程序所創建的進程開始是運行在用戶態的,如果要執行文件操作,網絡數據發送等操作,必須通過write,send等系統調用,這些系統調用會調用內核中的代碼來完成操作,這時,必須切換到Ring0eip系統,然后進入3GB-4GB中的內核地址空間去執行這些代碼完成操作,完成后,切換回Ring3,回到用戶態。這樣,用戶態的程序就不能隨意操作內核地址空間,具有一定的安全保護作用。 保護模式,通過內存頁表操作等機制,保證進程間的地址空間不會互相沖突,一個進程的操作不會修改另一個進程的地址空間中的數據。在內核態下,CPU可執行任何指令,在用戶態下CPU只能執行非特權指令。當CPU處于內核態,可以隨意進入用戶態;而當CPU處于用戶態,只能通過中斷的方式進入內核態。一般程序一開始都是運行于用戶態,當程序需要使用系統資源時,就必須通過調用軟中斷進入內核態.
3、用戶態和內核態的轉換
1)用戶態切換到內核態的3種方式
a. 系統調用
這是用戶態進程主動要求切換到內核態的一種方式,用戶態進程通過系統調用申請使用操作系統提供的服務程序完成工作。而系統調用的機制,其核心還是使用了操作系統為用戶特別開放的一個中斷來實現,例如lx86的int 80h, powerpc的sc
b. 異常
當CPU在執行運行在用戶態下的程序時,發生了某些事先不可知的異常,這時會觸發由當前運行進程切換到處理此異常的內核相關的程序中,也就是轉到了內核態,比如缺頁異常。
c. 外圍設備的中斷
當外圍設備完成用戶請求的操作后,會向CPU發出相應的中斷信號,這時CPU會暫停執行下一條即將要執行的指令轉而去執行與中斷信號對應的處理程序,如果先前執行的指令是用戶態下的程序,那么這個轉換的過程自然也就發生了由用戶態到內核態的切換。比如硬盤讀寫操作的完成,系統會切換到硬盤讀寫的中斷處理程序中執行后續操作等。
這3種方式是系統在運行時由用戶態轉到內核態的最主要方式,其中系統調用可以認為是用戶進程主動發起的,異常和外圍中斷是被動的。
4、具體的切換操作
從觸發方式上看,可以認為純在前述3種不同的類型,但是從最終實際完成由用戶態到內核態的切換操作上來說,涉及的關鍵步驟是完全一致的,沒有任何區別,都相當于執行了一個中斷響應的過程,因為系統調用實際上最終是中斷機制實現的,而異常和中斷的處理機制基本上也是一致的。關于中斷處理機制的細節合步驟這里不做過多分析,涉及到有用戶態切換到內核態的步驟主要包括:
【1】從當前進程的描述符中提取其內核棧的ss0及esp0信息
【2】使用ss0和esp0指向的內核棧將當前進程的cseip系統,eip,eflags,ss,esp信息保存起來,這個過程也完成了由用戶棧到內核棧的切換過程,同時保存了被暫停執行的程序的下一條指令。
【3】將先前又中斷向量檢索得到的中斷處理程序的cs,eip信息裝入相應的寄存器,開始執行中斷處理程序,這時就轉到內核態的程序執行了。