Inter的CPU將等級分為四個級別:Ring0、Ring1、Ring2、Ring3。Windows只是用其中的兩個級別Ring0和Ring3,Ring0只給操作系統使用,Ring3誰都能用。如果普通應用程序企圖執行Ring0指令,則windows會顯示“非法指令”錯誤信息。
Ring0是指CPU的運行級別,Ring0是最高級別,Ring1次之,拿Linux來說,內核的代碼運行在最高級別的ring0上,可以使用特權指令,控制中斷,修改頁表,訪問設備等等。應用程序的代碼運行在最低級別的ring3上,不能做受控操作,如果要做,比如訪問磁盤,寫文件,那就要通過執行系統調用(函數),執行系統調用的時候,CPU的運行級別會發生從ring3到ring0的切換,並跳轉到系統調用對應的內核代碼位置執行,這樣內核就為你完成了設備訪問,完成之后再從ring0返回ring3。這個過程也成為用戶態和內核態的切換。
那么ring1 和 ring2是什么?
ring1與ring2主要是訪問驅動程序
用戶態到內核態切換的條件:
系統調用:這是用戶態進程主動要求切換到內核態的一種方式(系統調用是操作系統的最小功能單位),用戶態進程通過系統調用申請使用操作系統提供的服務程序完成工作,比如fork()實際上就是執行了一個創建新進程的系統調用。而系統調用的機制其核心還是使用了操作系統為用戶特別開放的一個中斷來實現,例如linux的int 80h中斷
異常:當CPU在執行運行用戶態下的程序時,發生了某些事先不可知的異常,這時會觸發由當前運行進程切換到處理此異常的內核相關程序中,也就轉到了內核態,比如缺頁異常。
外圍設備中斷:當外圍設備完成用戶請求的操作后,會向CPU發出相應的中斷信號,這時CPU會暫停執行下一條即將要執行的指令轉而去執行與中斷信號對應的處理程序,如果先前執行的指令是用戶態下的程序,那么這個轉換的過程自然也就發生了由用戶態到內核態的切換,比如硬盤讀寫操作完成,系統會切換到硬盤讀寫的中斷處理程序中執行后續操作等。
這三種方式是系統在運行時由用戶態轉到內核態的最主要方式,其中系統調用可以認為是用戶進程主動發起的,異常和外圍設備中斷則是被動的。
為什么用戶態與內核態切換有開銷?
當程序中有系統調用語句,程序執行到系統調用時,首先使用類似int 80H
的軟中斷指令,保存現場,去的系統調用號,在內核態執行,然后恢復現場,每個進程都會有兩個棧,一個內核態棧和一個用戶態棧。當執行int中斷執行時就會由用戶態,棧轉向內核棧。系統調用時需要進行棧的切換。而且內核代碼對用戶不信任,需要進行額外的檢查。系統調用的返回過程有很多額外工作,比如檢查是否需要調度等。
那為什么要有內核態之分呢?