一文讀懂linux缺頁異常處理--內(nèi)核空間(技術(shù)干貨~)
缺頁異常被觸發(fā)通常有兩種情況
程序設(shè)計的不當(dāng)導(dǎo)致訪問了非法的地址
訪問的地址是合法的,但是該地址還未分配物理頁框
下面解釋一下第二種情況,這是虛擬內(nèi)存管理的一個特性。盡管每個進(jìn)程獨立擁有3GB的可訪問地址空間,但是這些資源都是內(nèi)核開出的空頭支票,也就是說進(jìn)程手握著和自己相關(guān)的一個個虛擬內(nèi)存區(qū)域(vma),但是這些虛擬內(nèi)存區(qū)域并不會在創(chuàng)建的時候就和物理頁框掛鉤,由于程序的局部性原理,程序在一定時間內(nèi)所訪問的內(nèi)存往往是有限的,因此內(nèi)核只會在進(jìn)程確確實實需要訪問物理內(nèi)存時才會將相應(yīng)的虛擬內(nèi)存區(qū)域與物理內(nèi)存進(jìn)行關(guān)聯(lián)(為相應(yīng)的地址分配頁表項,并將頁表項映射到物理內(nèi)存),也就是說這種缺頁異常是正常的,而第一種缺頁異常是不正常的,內(nèi)核要采取各種可行的手段將這種異常帶來的破壞減到最小。
缺頁異常的處理函數(shù)為do_page_fault(),該函數(shù)是和體系結(jié)構(gòu)相關(guān)的一個函數(shù),缺頁異常的來源可分為兩種,一種是內(nèi)核空間(訪問了線性地址空間的第4個GB),一種是用戶空間(訪問了線性地址空間的0~3GB),以X86架構(gòu)為例,先來看內(nèi)核空間異常的處理。
該函數(shù)傳遞進(jìn)來的兩個參數(shù)
regs包含了各個寄存器的值
error_code是觸發(fā)異常的錯誤類型,它的含義如下
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ??


首先要檢查該異常的觸發(fā)地址是不是位于內(nèi)核地址空間 也就是address>=TASK_SIZE_MAX,一般為3GB。然后要檢查觸發(fā)異常時是否處于內(nèi)核態(tài),滿足這兩個條件就嘗試通過vmalloc_fault()來解決這個異常。由于使用vmalloc申請內(nèi)存時,內(nèi)核只會更新主內(nèi)核頁表,所以當(dāng)前使用的進(jìn)程頁表就有可能因為未與主內(nèi)核頁表同步導(dǎo)致這次異常的觸發(fā),因此該函數(shù)試圖將address對應(yīng)的頁表項與主內(nèi)核頁表進(jìn)行同步
同步處理:
如果do_page_fault()函數(shù)執(zhí)行到了bad_area_nosemaphore(),那么就表明這次異常是由于對非法的地址訪問造成的。在內(nèi)核中產(chǎn)生這樣的結(jié)果的情況一般有兩種:
內(nèi)核通過用戶空間傳遞的系統(tǒng)調(diào)用參數(shù),訪問了無效的地址
內(nèi)核的程序設(shè)計缺陷
第一種情況內(nèi)核尚且能通過異常修正機(jī)制來進(jìn)行修復(fù),而第二種情況就會導(dǎo)致OOPS錯誤了,內(nèi)核將強(qiáng)制用SIGKILL結(jié)束當(dāng)前進(jìn)程。
內(nèi)核態(tài)的bad_area_nosemaphore()的實際處理函數(shù)為bad_area_nosemaphore()-->__bad_area_nosemaphore()-->no_context()
