時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(0)
高端內(nèi)存是指物理地址大于 896M 的內(nèi)存。
對于這樣的內(nèi)存,無法在"內(nèi)核直接映射空間"進行映射。
為什么?
因為"內(nèi)核直接映射空間"最多只能從 3G 到 4G,只能直接映射 1G 物理內(nèi)存,對于大于 1G 的物理內(nèi)存,無能為力。
實際上,"內(nèi)核直接映射空間"也達不到 1G, 還得留點線性空間給"內(nèi)核動態(tài)映射空間" 呢。
因此,Linux 規(guī)定"內(nèi)核直接映射空間" 最多映射 896M 物理內(nèi)存。
對 于高端內(nèi)存,可以通過 alloc_page() 或者其它函數(shù)獲得對應(yīng)的 page,但是要想訪問實際物理內(nèi)存,還得把 page 轉(zhuǎn)為線性地址才行(為什么?想想 MMU 是如何訪問物理內(nèi)存的),也就是說,我們需要為高端內(nèi)存對應(yīng)的 page 找一個線性空間,這個過程稱為高端內(nèi)存映射。
高端內(nèi)存映射有三種方式:
1、映射到"內(nèi)核動態(tài)映射空間"
這種方式很簡單,因為通過 vmalloc() ,在"內(nèi)核動態(tài)映射空間"申請內(nèi)存的時候,就可能從高端內(nèi)存獲得頁面(參看 vmalloc 的實現(xiàn)),因此說高端內(nèi)存有可能映射到"內(nèi)核動態(tài)映射空間" 中。
2、永久內(nèi)核映射
如果是通過 alloc_page() 獲得了高端內(nèi)存對應(yīng)的 page,如何給它找個線性空間?
內(nèi)核專門為此留出一塊線性空間,從 PKMAP_BASE 到 FIXADDR_START ,用于映射高端內(nèi)存。在 2.4 內(nèi)核上,這個地址范圍是 4G-8M 到 4G-4M 之間。這個空間起叫"內(nèi)核永久映射空間"或者"永久內(nèi)核映射空間"
這個空間和其它空間使用同樣的頁目錄表,對于內(nèi)核來說,就是 swapper_pg_dir,對普通進程來說,通過 CR3 寄存器指向。
通常情況下,這個空間是 4M 大小,因此僅僅需要一個頁表即可,內(nèi)核通過來 pkmap_page_table 尋找這個頁表。
通過 kmap(), 可以把一個 page 映射到這個空間來
由于這個空間是 4M 大小,最多能同時映射 1024 個 page。因此,對于不使用的的 page,及應(yīng)該時從這個空間釋放掉(也就是解除映射關(guān)系),通過 kunmap() ,可以把一個 page 對應(yīng)的線性地址從這個空間釋放出來。
3、臨時映射
內(nèi)核在 FIXADDR_START 到 FIXADDR_TOP 之間保留了一些線性空間用于特殊需求。這個空間稱為"固定映射空間"
在這個空間中,有一部分用于高端內(nèi)存的臨時映射。
這塊空間具有如下特點:
1、 每個 CPU 占用一塊空間
2、 在每個 CPU 占用的那塊空間中,又分為多個小空間,每個小空間大小是 1 個 page,每個小空間用于一個目的,這些目的定義在 kmap_types.h 中的 km_type中。
當要進行一次臨時映射的時候,需要指定映射的目的,根據(jù)映射目的,可以找到對應(yīng)的小空間,然后把這個空間的地址作為映射地址。這意味著一次臨時映射會導致以前的映射被覆蓋。
通過 kmap_atomic() 可實現(xiàn)臨時映射。
下圖簡單簡單表達如何對高端內(nèi)存進行映射
?。?/p>
高端內(nèi)存含義為:線性地址空間 PAGE_OFFSET + 896M 至4G的最后128M線性地址 <==映射==> 896M以上的物理頁框,非直接映射。有3種方法:非連續(xù)內(nèi)存區(qū)映射,永久內(nèi)核映射,臨時內(nèi)核映射(固定映射)
從 PAGE_OFFSET開始的線性地址區(qū)域為:
PAGE_OFFSET(3G)|物理內(nèi)存映射 --8M-- vmalloc區(qū) --4K-- vmalloc區(qū) --8K-- 永久內(nèi)核映射--臨時內(nèi)核映射(固定映射)|4G
1. 非連續(xù)區(qū)映射
1.1 每個非連續(xù)內(nèi)存區(qū)都對應(yīng)一個類型為 vm_struct的描述符,通過next字段,這些描述符被插入到一個vmlist鏈表中。
1.2 三種非連續(xù)區(qū)的類型:
VM_ALLOC?? -- 物理內(nèi)存(調(diào)用alloc_page)和線性地址同時申請,物理內(nèi)存是 __GFP_HIGHMEM類型(分配順序是HIGH, NORMAL, DMA )(可見vmalloc不僅僅可以映射__GFP_HIGHMEM頁框,它的主要目的是為了將零散的,不連續(xù)的頁框拼湊成連續(xù)的內(nèi)核邏輯地址空間...)
VM_MAP???? -- 僅申請線性區(qū),物理內(nèi)存另外申請,是VM_ALLOC的簡化版
VM_IOREMAP -- 僅申請線性區(qū),物理內(nèi)存另外申請(這里的物理內(nèi)存一般都是高端內(nèi)存,大于896M的內(nèi)存)
2. 永久內(nèi)核映射
2.1 永久內(nèi)存映射允許建立長期映射。使用主內(nèi)核頁表中swapper_pg_dir的一個專門頁表。
pkmap_page_table: 專門的頁表。頁表表項數(shù)由LAST_PKMAP(512或1024)產(chǎn)生。
page_address_htable: 存放地址的
pkmap_count: 包含LAST_PKMAP個計數(shù)器的數(shù)組。
PKMAP_BASE: 頁表線性地址從PKMAP_BASE開始。
2.2 如果LAST_PKMAP個項都用完,則把當前進程置為 TASK_UNINTERRUPTIBLE,并調(diào)用schedule()
3. 臨時內(nèi)存映射
3.1 可以用在中斷處理函數(shù)和可延遲函數(shù)的內(nèi)部,從不阻塞。因為臨時內(nèi)存映射是固定內(nèi)存映射的一部分,一個地址固定給一個內(nèi)核成分使用。
3.2 每個CPU都有自己的一個13個窗口(一個線性地址及頁表項)的集合。
enum km_type {
KM_BOUNCE_READ,
KM_SKB_SUNRPC_DATA,
KM_SKB_DATA_SOFTIRQ,
KM_USER0,
KM_USER1,
KM_BIO_SRC_IRQ,
KM_BIO_DST_IRQ,
KM_PTE0,
KM_PTE1,
KM_IRQ0,
KM_IRQ1,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_TYPE_NR
};
所有固定映射的固定線性地址
enum fixed_addresses {
FIX_HOLE,
FIX_VSYSCALL,
....
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN,??? /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
.......
__end_of_permanent_fixed_addresses,
/* temporary boot-time mappings, used before ioremap() is functional */
#define NR_FIX_BTMAPS??? 16
FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
FIX_WP_TEST,
__end_of_fixed_addresses
};
3.3 注意 fixed_addresses 的地址從上至下是倒著的,F(xiàn)IX_HOLE的地址等于 0xfffff000,是一個洞
#define __fix_to_virt(x)??? (FIXADDR_TOP - ((x) << PAGE_SHIFT))
#define __FIXADDR_TOP??? 0xfffff000
?。?/p>
VMALLOC_RESERVE和896M
LINUX 內(nèi)核虛擬地址空間到物理地址空間一般是固定連續(xù)影射的。
假定機器內(nèi)存為512M,
從 3G開始,到3G + 512M 為連續(xù)固定影射區(qū)。zone_dma, zone_normal為這個區(qū)域的。固定影射的VADDR可以直接使用(get a free page, then use pfn_to_virt()等宏定義轉(zhuǎn)換得到vaddr)或用kmalloc等分配. 這樣的vaddr的物理頁是連續(xù)的。得到的地址也一定在固定影射區(qū)域內(nèi)。
如果內(nèi)存緊張,連續(xù)區(qū)域無法滿足,調(diào)用vmalloc分配是必須的,因為它可以將物理不連續(xù)的空間組合后分配,所以更能滿足分配要求。vmalloc可以映射高端頁框,也可以映射底端頁框。vmalloc的作用只是為了提供邏輯上連續(xù)的地址。。。
但 vmalloc分配的vaddr一定不能與固定影射區(qū)域的vaddr重合。因為vaddr到物理頁的影射同時只能唯一。所以vmalloc得到的 vaddr要在3G + 512m 以上才可以。也就是從VMALLOC_START開始分配。 VMALLOC_START比連續(xù)固定影射區(qū)大最大vaddr地址還多8-16M(2*VMALLOC_OFFSET)--有個鬼公式在
#define VMALLOC_OFFSET?? 8*1024
#define VMALLOC_START?? (high_memory - 2*VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)
high_memory 就是固定影射區(qū)域最高處。
空開8-16M做什么? 為了捕獲越界的mm_fault.
同樣,vmalloc每次得到的VADDR空間中間要留一個PAGE的空(空洞),目的和上面的空開一樣。你vmalloc(100)2次,得到的2個地址中間相距8K。
如果連續(xù)分配無空洞,那么比如
p1=vmalloc(4096);
p2=vmalloc(4096);
如果p1使用越界到p2中了,也不會mm_falut. 那不容易debug.
下面說明VMALLOC_RESERVE和896M的問題。
上面假設(shè)機器物理512M的case. 如果機器有1G物理內(nèi)存如何是好?那vmalloc()的vaddr是不是要在3G + 1G + 8M 空洞以上分配?超過尋址空間了嗎。
這時,4G 下面保留的VMALLOC_RESERVE 128m 就派上用場了。
也就是說如果物理內(nèi)存超過896M, high_memory也只能在3G + 896地方??蓪ぶ房臻g最高處要保留VMALLOC_RESREVE 128M給vmalloc用。
所以這128M的VADDR空間是為了vmalloc在物理超過了896M時候使用。如果物理僅僅有512M, 一般使用不到。因為VMALLOC_START很低了。如果vmalloc太多了才會用到。
high_memory在arch/i386/kernel, mm的初始化中設(shè)置。根據(jù)物理內(nèi)存大小和VMALLOC_RESERVE得到數(shù)值.
所以說那128M的內(nèi)核線性地址僅僅是為了影
關(guān)鍵詞標簽:Linux
相關(guān)閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址 dmidecode命令查看內(nèi)存型號 linux tc實現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負載