linux用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換
當一個進程執(zhí)行系統(tǒng)調(diào)用而執(zhí)行內(nèi)核代碼時皆怕,稱進程處于內(nèi)核 內(nèi)核態(tài)毅舆,此時處理器處于特權(quán)級最高的(0級)內(nèi)核代碼中執(zhí)行,當進程處于內(nèi)核態(tài)時愈腾,執(zhí)行的內(nèi)核代碼會使用當前進程的內(nèi)核棧,每個進程都有自己的內(nèi)核棧憋活。
當進程執(zhí)行用戶代碼時,稱其處于 用戶態(tài)虱黄,此時處理器在特權(quán)級最低的(3級)用戶代碼中運行悦即。
當正在執(zhí)行用戶程序而突然被中斷程序中斷時,此時用戶程序也可以象征性地稱為處于進程的內(nèi)核態(tài),因為中斷處理程序?qū)⑹褂卯斍斑M程的內(nèi)核棧橱乱。這與處于內(nèi)核態(tài)的進程的狀態(tài)有些類似盐欺。內(nèi)核態(tài) 與 用戶態(tài) 是操作系統(tǒng)的兩種運行級別,跟intel cpu沒有必然的聯(lián)系,intel cpu提供Ring0-Ring3三種級別的運行模式仅醇,Ring0級別最高,Ring3最低魔种。
Linux使用了Ring3級別運行用戶態(tài)析二,Ring0作為內(nèi)核態(tài),沒有使用Ring1和Ring2节预。Ring3狀態(tài)不能訪問Ring0的地址空間叶摄,包括代碼和數(shù)據(jù)。Linux進程的4GB地址空間安拟,3G-4G 部分大家是共享的蛤吓,是內(nèi)核態(tài)的地址空間,這里存放在整個內(nèi)核的代碼和所有的內(nèi)核模塊糠赦,以及內(nèi)核所維護的數(shù)據(jù)会傲。用戶運行一個程序锅棕,該程序所創(chuàng)建的進程開始是運行在用戶態(tài)的,如果要執(zhí)行文件操作淌山,網(wǎng)絡(luò)數(shù)據(jù)發(fā)送等操作裸燎,必須通過write,send等系統(tǒng)調(diào)用泼疑,這些系統(tǒng)調(diào)用會調(diào)用內(nèi)核中的代碼來完成操作德绿,這時,必須切換到Ring0退渗,然后進入3GB-4GB中的內(nèi)核地址空間去執(zhí)行這些代碼完成操作移稳,完成后,切換回Ring3会油,回到用戶態(tài)个粱。這樣,用戶態(tài)的程序就不能隨意操作內(nèi)核地址空間钞啸,具有一定的安全保護作用几蜻。
保護模式,通過內(nèi)存頁表操作等機制体斩,保證進程間的地址空間不會互相沖突梭稚,一個進程的操作不會修改另一個進程的地址空間中的數(shù)據(jù)。在內(nèi)核態(tài)下絮吵,CPU可執(zhí)行任何指令弧烤,在用戶態(tài)下CPU只能執(zhí)行非特權(quán)指令。當CPU處于內(nèi)核態(tài)蹬敲,可以隨意進入用戶態(tài)暇昂;而當CPU處于用戶態(tài),只能通過中斷的方式進入內(nèi)核態(tài)伴嗡。一般程序一開始都是運行于用戶態(tài)急波,當程序需要使用系統(tǒng)資源時,就必須通過調(diào)用軟中斷進入內(nèi)核態(tài).
使用nm查看用戶態(tài)程序的符號表內(nèi)容
使用System.map(內(nèi)核符號表)查看內(nèi)核符號表內(nèi)容
- 測試程序中打印用戶態(tài)函數(shù)地址瘪校,并調(diào)用系統(tǒng)調(diào)用(在內(nèi)核中打印系統(tǒng)調(diào)用函數(shù)地址)澄暮,用"用戶態(tài)符號表"和"內(nèi)核態(tài)符號表"示例說明內(nèi)核態(tài)和用戶態(tài)地址空間的差異
- 說明內(nèi)核態(tài)地址映射ioremap();用戶態(tài)地址映射mmap()
用戶態(tài)切換到內(nèi)核態(tài)的3種方式
系統(tǒng)調(diào)用
這是用戶態(tài)進程主動要求切換到內(nèi)核態(tài)的一種方式阱扬,用戶態(tài)進程通過系統(tǒng)調(diào)用申請使用操作系統(tǒng)提供的服務程序完成工作泣懊,比如前例中fork()實際上就是執(zhí)行了一個創(chuàng)建新進程的系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的機制其核心還是使用了操作系統(tǒng)為用戶特別開放的一個中斷來實現(xiàn)麻惶,例如Linux的INT 80H中斷馍刮。
系統(tǒng)調(diào)用實質(zhì)上是一個中斷,而匯編指令int 就可以實現(xiàn)用戶態(tài)向內(nèi)核態(tài)切換窃蹋,iret實現(xiàn)內(nèi)核態(tài)向用戶態(tài)切換
異常
當CPU在執(zhí)行運行在用戶態(tài)下的程序時卡啰,發(fā)生了某些事先不可知的異常静稻,這時會觸發(fā)由當前運行進程切換到處理此異常的內(nèi)核相關(guān)程序中,也就轉(zhuǎn)到了內(nèi)核態(tài)碎乃,比如缺頁異常姊扔。
外圍設(shè)備的中斷
當外圍設(shè)備完成用戶請求的操作后,會向CPU發(fā)出相應的中斷信號梅誓,這時CPU會暫停執(zhí)行下一條即將要執(zhí)行的指令轉(zhuǎn)而去執(zhí)行與中斷信號對應的處理程序恰梢,如果先前執(zhí)行的指令是用戶態(tài)下的程序,那么這個轉(zhuǎn)換的過程自然也就發(fā)生了由用戶態(tài)到內(nèi)核態(tài)的切換梗掰。比如硬盤讀寫操作完成嵌言,系統(tǒng)會切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等。
這3種方式是系統(tǒng)在運行時由用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài)的最主要方式及穗,其中系統(tǒng)調(diào)用可以認為是用戶進程主動發(fā)起的摧茴,異常和外圍設(shè)備中斷則是被動的。
具體的切換操作
從觸發(fā)方式上看埂陆,可以認為存在前述3種不同的類型苛白,但是從最終實際完成由用戶態(tài)到內(nèi)核態(tài)的切換操作上來說,涉及的關(guān)鍵步驟是完全一致的焚虱,沒有任何區(qū)別购裙,都相當于執(zhí)行了一個中斷響應的過程,因為系統(tǒng)調(diào)用實際上最終是中斷機制實現(xiàn)的鹃栽,而異常和中斷的處理機制基本上也是一致的躏率,關(guān)于它們的具體區(qū)別這里不再贅述。關(guān)于中斷處理機制的細節(jié)和步驟這里也不做過多分析民鼓,涉及到由用戶態(tài)切換到內(nèi)核態(tài)的步驟主要包括:
[1] 從當前進程的描述符中提取其內(nèi)核棧的ss0及esp0信息薇芝。
[2] 使用ss0和esp0指向的內(nèi)核棧將當前進程的cs,eip,eflags,ss,esp信息保存起來,這個過程也完成了由用戶棧到內(nèi)核棧的切換過程丰嘉,同時保存了被暫停執(zhí)行的程序的下一條指令夯到。
[3] 將先前由中斷向量檢索得到的中斷處理程序的cs,eip信息裝入相應的寄存器,開始執(zhí)行中斷處理程序饮亏,這時就轉(zhuǎn)到了內(nèi)核態(tài)的程序執(zhí)行了耍贾。