內核態與用戶態

 

內核態與用戶態是操作系統的兩種運行級別,intel cpu提供Ring0-Ring3三種級別的運行模式。Ring0級別最高,Ring3最低。其中特權級0(Ring0)是留給操作系統代碼,設備驅動程序代碼使用的,它們工作於系統核心態;而特權極3(Ring3)則給普通的用戶程序使用,它們工作在用戶態。運行於處理器核心態的代碼不受任何的限制,可以自由地訪問任何有效地址,進行直接端口訪問。而運行於用戶態的代碼則要受到處理器的諸多檢查,它們只能訪問映射其地址空間的頁表項中規定的在用戶態下可訪問頁面的虛擬地址,且只能對任務狀態段(TSS)中I/O許可位圖(I/O Permission Bitmap)中規定的可訪問端口進行直接訪問(此時處理器狀態和控制標誌寄存器EFLAGS中的IOPL通常爲0,指明當前可以進行直接I/O的最低特權級別是Ring0)。以上的討論只限於保護模式操作系統,象DOS這種模式操作系統則沒有這些概念,其中的所有代碼都可被看作運行在覈心態。
  當一個任務(進程)執行系統調用而陷入內核代碼中執行時,我們就稱進程處於內核運行態(或簡稱爲內核態)。此時處理器處於特權級最高的(0級) 內核代碼中執行。當進程處於內核態時,執行的內核代碼會使用當前進程的內核棧。每個進程都有自己的內核棧。當進程在執行用戶自己的代碼時,則稱其處於用戶運行態(用戶態)。即此時處理器在特權級最低的(3級)用戶代碼中運行。
  在內核態下CPU可執行任何指令,在用戶態下CPU只能執行非特權指令。當CPU處於內核態,可以隨意進入用戶態;而當CPU處於用戶態時,用戶從用戶態切換到內核態只有在系統調用和中斷兩種情況下發生,一般程序一開始都是運行於用戶態,當程序需要使用系統資源時,就必須通過調用軟中斷進入內核態。
  Linux使用了Ring3級別運行用戶態,Ring0作爲內核態,沒有使用Ring1和Ring2。Ring3狀態不能訪問Ring0的地址空間,包括代碼和數據。Linux進程的4GB地址空間,3G-4G部分大家是共享的,是內核態的地址空間,這裏存放在整個內核的代碼和所有的內核模塊,以及內核所維護的數據。用戶運行一個程序,該程序所創建的進程開始是運行在用戶態的,如果要執行文件操作,網絡數據發送等操作,必須通過 write,send等系統調用,這些系統調用會調用內核中的代碼來完成操作,這時,必須切換到Ring0,然後進入3GB-4GB中的內核地址空間去執行這些代碼完成操作,完成後,切換回Ring3,回到用戶態。這樣,用戶態的程序就不能隨意操作內核地址空間,具有一定的安全保護作用。
處理器模式從Ring3向Ring0的切換髮生在控制權轉移時,有以下兩種情況:訪問調用門的長轉移指令CALL,訪問中斷門或陷阱門的INT指令。具體的轉移細節由於涉及複雜的保護檢查和堆棧切換,不再贅述,請參閱相關資料。現代的操作系統通常使用中斷門來提供系統服務,通過執行一條陷入指令來完成模式切換,在INTEL X86上這條指令是INT,如在WIN9X下是INT30(保護模式回調),在LINUX下是INT80,在WINNT/2000下是INT2E。用戶模式的服務程序(如系統DLL)通過執行一個INTXX來請求系統服務,然後處理器模式將切換到核心態,工作於核心態的相應的系統代碼將服務於此次請求並將結果傳給用戶程序。
 
一,中斷處理過程

硬件中斷:來自時鐘,外設

可編程中斷:programmed interrupt,執行引起軟件中斷的指令。

例外中斷:如頁面錯。

都由系統負責處理。當發生一箇中斷時,如果CPU正在比該中斷級低的處理機運行級上運行,它就在解碼下條指令之前,接受該中斷,並提高處理機運行級。內核處理中斷的操作順序如下:

1,對於正在進行的進程,保存其當前寄存器上下文,並創建壓入一個新的上下文層。

2,確定中斷源,識別中斷類型。如是時鐘或磁盤的。

3,查找中斷向量。當系統接受一箇中斷時,它從機器中得到一個數,系統把這個作爲查表的偏移量。這個表通常成爲中斷向量(interrupt vector)。中斷向量的內容包括各種中斷源的中斷處理程序的地址,以及中斷處理程序取得參數的方式。

4,內核調用中斷處理程序。

5,中斷處理程序執行那個返回,恢復(彈出)前一上下文層。

二,軟中斷

軟中斷通知進程發生了異步事件。

系統有個進程表,每個進程在進程表中有有個進程表項,每個進程表項有個軟中斷信號字段,紀錄發向一個進程的所有未處理的軟中斷信號。

當一個進程即將從核心態返回到用戶態時,或它要進入或離開一個適當的低調度優先級時,內核要檢查它是否收到了一個軟中斷信號。

內核僅當一個進程從核心態返回到用戶態時才處理軟中斷信號。

三,系統調用

我們在C程序中調用系統調用好像是個一般的函數調用,當實際上調用系統調用會引起用戶態到核心態的狀態變化,這是怎麼做到的呢?

原來,C編譯程序採用一個預定義的函數庫(C之程序庫),其中的函數具有系統調用的名字,從而解決了在用戶程序中請求系統調用的問題。這些庫函數一般都執行一條指令,該指令將進程的運行方式變爲核心態,然後,使內核開始爲系統調用執行代碼。我們稱這個指令爲操作系統陷入(operating system trap)。

系統調用的接口是一箇中斷處理程序的特例。

在處理操作系統陷入時,

1,內核根據系統調用號查系統調用入口表,找到相應的內核子程序的地址。

2,內核還要確定該系統調用所要求的參數個數。

3,從用戶地址空間拷貝參數到U區(Unix V)。

4,保存當前上下文,執行系統調用代碼。

核心態:當CPU正在運行內核代碼時(內核代碼是共享的)。

用戶態:當CPU正在運行用戶代碼時。

用戶模式:不可以訪問內核空間(>=0x80000000)

內核模式:可以訪問任何有效虛擬地址,包括內核空間。一個線程可以訪問其他任何線程地址空間。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章