Linux核心缺頁
整個缺頁異常的處理過程非常複雜,我們這裡只簡單介紹一下缺頁涉及到的核心功能。
當CPU產生一個異常時,將會跳轉到異常處理的整個處理流程中。對於缺頁異常,CPU將跳轉到page_fault例外處理常式中,該例外處理常式會調用do_page_fault()函數,該函數通過讀取CR2寄存器獲得引起缺頁的線性地址,通過各種條件判斷以便確定一個合適的方案來處理這個異常。
do_page_fault()該函數通過各種條件來檢測當前發生異常的情況,但至少do_page_fault()會區分出引發缺頁的兩種情況:由編程錯誤引發異常,以及由進程地址空間中還未分配實體記憶體的線性地址引發。對於後一種情況,通常還分為使用者空間所引發的缺頁異常和核心空間引發的缺頁異常。核心引發的異常是由vmalloc()產生的,它只用於核心空間記憶體的分配。我們這裡需要關注的是使用者空間所引發的異常情況。這部分工作從do_page_fault()中的good_area標號處開始執行,主要通過handle_mm_fault()完成。
handle_mm_fault()該函數的主要功能是為引發缺頁的進程分配一個物理頁框,它先確定與引發缺頁的線性地址對應的各級頁目錄項是否存在,如何不存在則分進行分配。具體如何分配這個頁框是通過調用handle_pte_fault()完成的。
handle_pte_fault()該函數根據頁表項pte所描述的物理頁框是否在實體記憶體中,分為兩大類:請求調頁:被訪問的頁框不再主存中,那麼此時必須分配一個頁框。寫時複製:被訪問的頁存在,但是該頁是唯讀,核心需要對該頁進行寫操作,此時核心將這個已存在的唯讀頁中的資料複製到一個新的頁框中。使用者進程訪問由malloc()分配的記憶體空間屬於第一種情況。對於請求調頁,handle_pte_fault()仍然將其細分為三種情況:
1.如果頁表項確實為空白(pte_none(entry)),那麼必須分配頁框。如果當前進程實現了vma操作函數集合中的fault鉤子函數,那麼這種情況屬於基於檔案的記憶體映射,它調用do_linear_fault()進行分配物理頁框。否則,核心將調用針對匿名映射分配物理頁框的函數do_anonymous_page()。
2.如果檢測出該頁表項為非線性映射(pte_file(entry)),則調用do_nonlinear_fault()分配物理頁。
3.如果頁框事先被分配,但是此刻已經由主存換出到了外存,則調用do_swap_page()完成頁框分配。
在以上三個函數中缺頁異常處理函數通過alloc_zeroed_user_highpage_movable()來完成物理頁的分配過程。alloc_zeroed_user_highpage_movable()函數最終調用了alloc_pages()。 經過這樣一個複雜的過程,使用者進程所訪問的線性地址終於對應到了一塊實體記憶體。
參考:
1.《深入理解Linux核心》 PDF 下載
2.《深入Linux核心架構》 PDF 下載見
本文永久更新連結地址: