著手建立核心永久頁表

2021-05-24 02:24:08 字數 4018 閱讀 3031

得到了總的頁面數

max_pfn

和高階頁面數

highmem_pages

之後,來到

setup_arch

的947

行,呼叫

函式來建立系統初始化階段的臨時分頁體系,傳入的引數意義代表從

0~max_low_pfn

對應的32

位實體地址(低

12位全為

0,也就是頁面對齊)

,在函式

函式中先後呼叫下面的幾個函式來設定記憶體相關資料(因為

bootmem

此時沒有初始化):

find_early_table_space()

early_ioremap_page_table_range_init()

load_cr3()

reserve_early()

其中,首先

find_early_table_space

所實現的功能是相當重要的:

32static void __init find_early_table_space(unsigned long end, int use_pse,

33int use_gbpages)

34 else

46pmds = (end + pmd_size - 1) >> pmd_shift;

47 48tables += roundup(pmds * sizeof(pmd_t), page_size);

49 50if (use_pse) else

59ptes = (end + page_size - 1) >> page_shift;

60 61tables += roundup(ptes * sizeof(pte_t), page_size);

62 63#ifdef config_x86_32

64/* for fixmap */

65tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), page_size);

66#endif

67 68/*

69* red-pen putting page tables only on node 0 could

70* cause a hotspot and fill up zone_dma. the page tables

71* need roughly 0.5kb per gb.

72*/

73#ifdef config_x86_32

74start = 0x7000;

75#else

76start = 0x8000;

77#endif

79tables, page_size);

80if (e820_table_start == -1ul)

81panic("cannot find space for the kernel page tables");

82 83e820_table_start >>= page_shift;

84e820_table_end = e820_table_start;

85e820_table_top = e820_table_start + (tables >> page_shift);

86 88end, e820_table_start << page_shift, e820_table_top << page_shift);

89}

我們看到它確定了

pud和

pmd以及

pte、固定記憶體對映等所有的選項所使用的記憶體空間的大小;之後呼叫

find_e820_area

函式從e820.map

陣列中尋找到一塊能夠容納所有頁表項的記憶體段:

743u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align)

744 763return -1ull;

764}

find_e820_area

中檢測e820.map

的每乙個元素,這個元素代表的記憶體區必須是

e820_ram

,然後呼叫

find_early_area

獲得tables

539u64 __init find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,

540u64 size, u64 align)

541

這個find_early_area

函式我們要好好說道說道。早系統初始化時,什麼記憶體管理器、記憶體模型這些東西都沒有建立,那麼獲得記憶體的最低階函式就是這個

find_early_area

函式。它接收

6個引數:

ei_start

和ei_last

表示分配範圍,我們看到這個範圍不能超出某個

e820.map[i]

元素代表的範圍;

start

和end

代表期望分配的範圍;

size

為期望分配大小;

align

表示對齊方式。我們看到,如果

addr >= ei_last

,或者last > ei_last

,或者last > end

都會分配失敗。這個條件看上去很苛刻,不過

e820.map

陣列有那麼多元素,總有乙個元素會滿足的,不然所有的

linux

都無法執行了。

round_up

以及還有乙個雙胞胎弟弟

round_down

的定義如下:

#define __round_mask(x, y) ((__typeof__(x))((y)-1))

#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)

#define round_down(x, y) ((x) & ~__round_mask(x, y))

獲得了獲得頁表

tables

的首位址之後,

find_early_table_space

就用它設定

e820_table_start

、e820_table_end

和e820_table_top

的值。這三個全域性變數相當的重要,分別表示這個將要容納所有核心頁表的空間的起始、結束和頂部頁對齊位址頭

20位(此時

e820_table_start

和e820_table_end

是相等的),在後面的頁表初始化階段將會使用到這三個變數。

看了這麼多**,很多同學可能有些迷糊了。為啥我們在

arch/x86/kernel/head_32.s

中已經初始化了分頁環境,建立了乙個臨時頁表了,為啥這裡還要建乙個呢?其實,這就是

ulk-3

書中提到的核心臨時頁表和最終核心頁表的概念。我在部落格「高階記憶體對映」

中也提到過這一點。

_end

的位置,也就是把解壓縮後的核心**對映出來了。而這裡,是要把所有可用的

ram(注意這裡是包括了已經映**的核心**、頁目錄)以頁為單位分成多個頁,每個頁乙個位元,提供乙個初始階段記憶體的分配和釋放管理平台。

目前我的電腦,在

arch/x86/kernel/head_32.s

裡只是映**大概4m的

vmlinux

**。核心尺寸在

4m左右

(不壓縮

),一般需要連續對映

3個頁面表。現在要把所有

ram對映到核心空間。那麼核心要根據

e820

物理記憶體的布局,也就是

ram的結點布局對多個結點及結點的管理區作初化,最終把除去核心之外所有剩餘的頁交給頁框分配器,同時也完成了頁框分配器的初始化。

核心頁表和程序頁表

初學核心時,經常被 核心頁表 和 程序頁表 搞暈,不知道這到底是個啥東東,跟我們平時理解的頁表有和關係 核心頁表 程序頁表 每個程序自己的頁表,放在程序自身的頁目錄task struct.pgd中。在保護模式下,從硬體角度看,其執行的基本物件為 程序 或執行緒 而定址則依賴於 程序頁表 在程序排程而...

Linux核心頁表

一 linux位址空間 arm的32位系統共支援4g的記憶體空間,其中0 3g為使用者空間,3g 4g是核心空間,arm採用2級頁表,32位位址空間address分別為 pgd pte 12bits,在核心 中分別為pgd 11位,pte 9 位,頁內位址12位 但是在mmu系統中對於arm的二級分...

關於使用者程序頁表和核心頁表

普通使用者程序的頁表也是存在核心空間的。這很容易理解,畢竟頁表沒有vma來對應。在應用程序建立的時候,task struct m struct描述記憶體資訊,mm gpd指定頁表基位址。頁表的分配是通過呼叫核心夥伴演算法介面分配到物理記憶體,核心在啟動階段已經建立了核心頁表,使用者程序的頁表可以分為...