1. 程式人生 > >IA32e下分頁的開啟:概述

IA32e下分頁的開啟:概述

記憶體分佈
IA32e下的地址用64位來表示,但CPU只使用了其中的前52位,即4PB的最大實體記憶體定址空間,而開啟分頁後,CPU只使用其中48位,即256TB的最大虛擬記憶體定址空間,而到了Windows,則更是隻使用了其中44位,即只用16TB的虛擬記憶體定址空間,其中0000000000000000-000007FFFFFFFFFF是使用者層地址空間,而FFFFF80000000000-FFFFFFFFFFFFFFFF則是核心地址空間,前16位會被CPU忽略,而構造的頁表則會忽略44-48位。
下面是Windows在IA32e下的虛擬記憶體分佈圖:
IA32e下Windows虛擬記憶體分佈
頁表構成
和傳統的IA32的兩級頁表以及開啟PAE後三級的三級頁表不同,IA32e的頁表是四級頁表,每級佔9位,共36位,加上頁內偏移12位,正好48位。
第一級頁表叫做PLM4表,每一個表項8位元組,共512項,每一項表示128GB,指向了對應的第二級頁表叫做PDPT,既頁目錄指標表,每一個表項8位元組,共512項,每一項標識1GB的虛擬記憶體空間(這個結構在IA32中也有,但需要開啟PAE並且只有4項),其既可以指向一個1G的大頁面,也可以指向一個第三級頁表(取決於PAT位的狀態)也就是IA32下熟知的PageDirectory,而PDT同樣既可以指向一個2M的大頁面,或者指向一個PageTable。這裡PDPT和PD都可以指向大頁面或者後一級的表,但PML4只能指向表,而PTE則只能指向4K頁面。所有Entry指向的空間(下一級表或者頁面)通過最後一位的P位來標識是否在實體記憶體中,如果不在實體記憶體中則CPU會無視整個頁表項。
IA32e的段管理也有所不同,IA32下,6個段暫存器都會使用,並且會檢查是否越界,而到了IA32e下,ds,es以及ss都被忽視,而cs只有屬性位有效,基址和大小位都無效,並且不檢查越界(因為大小無效,這部分功能完全依賴頁表),在定址時,這幾個段暫存器預設基址為0,大小為整個線性地址空間,gs,fs繼續發揮作用。
這裡寫圖片描述


開啟IA32e分頁需要做如下前置工作:
1. 構造頁表結構,建立pfn資料庫
2. 將載入程式對映到頁表中
3. 將韌體記憶體對映到頁表中
4. 在頁表中預先分配堆疊
5. 構造GDT和IDT並寫入idtr和gdtr
6. 將rsp賦值為堆疊虛擬記憶體地址
7. 將CR3設為PML4的實體地址,置位CR0的PG位, CR4的PAE位以及MSR暫存器IA32_EFER的LME位
8. 利用iretq跳轉到核心
BIOS下開機後會先進入真實模式,需要手工設定CR暫存器進入保護模式,而在UEFI下,預設開機後啟動的是保護模式,IA32下的UEFI只啟用保護模式,而IA32e下UEFI韌體系統會開啟分頁(UEFI Spec 2.3.4),但這個分頁是1:1對映的,即寫一個地址的虛擬記憶體就寫到了對應地址的實體記憶體,這樣通過GetAddressMaps得到的也是真實的實體記憶體分佈,所以IA32e下只需要把PML4賦值給CR3就可以了。
由於在沒有開分頁時CR3的高32位是隻讀的,所以在BIOS下的IA32e的PML4需要在低4G空間,而UEFI下因為已經開啟了分頁,所以就沒有這個限制了,而開啟分頁後則沒有任何限制,64位全都有效。