Linux把每個物理內(nèi)存劃分成3個管理區(qū)
內(nèi)存區(qū)域 | 說明 |
---|---|
ZONE_DMA | 范圍是0~16M,該區(qū)域的物理頁面專門供I/O設(shè)備的DMA使用 |
ZONE_NORMAL | 范圍是16~896M,該區(qū)域的物理頁面是內(nèi)核能夠直接使用的 |
ZONE_HIGHMEM | 范圍是896~結(jié)束,高端內(nèi)存,內(nèi)核不能直接使用 |
通常32位Linux內(nèi)核地址空間劃分0 ~ 3G為用戶空間,3 ~ 4G為內(nèi)核空間
物理地址 = 邏輯地址 – 0xC0000000
假設(shè)按照上述簡單的地址映射關(guān)系,內(nèi)核只能訪問1G物理內(nèi)存空間
存在這樣一個問題:由于內(nèi)核只能訪問1G物理內(nèi)存空間,如果物理內(nèi)存是2G,那內(nèi)核如何訪問剩余的1G物理內(nèi)存空間呢?
由本文開始我們知道物理內(nèi)存地址被劃分成了3個Zone,其中0~ 896M是內(nèi)核直接可以訪問的,896M ~ 2G這一部分內(nèi)核要如何訪問呢?
實(shí)際上內(nèi)核想訪問高于896M的物理地址時(shí),從0xF8000000~ 0xFFFFFFFF虛擬地址空間中取一部分與想要訪問的物理內(nèi)存建立映射即填充內(nèi)核PTE頁表(內(nèi)核頁表),訪問完成之后內(nèi)核釋放0xF8000000~0xFFFFFFFF中的虛擬地址空間,以便其它進(jìn)程訪問。(采用這128M的虛擬空間,建立臨時(shí)地址映射,完成了對所有高于896M物理內(nèi)存的訪問)
如下圖所示
1G的虛擬內(nèi)核空間如下圖
Linux內(nèi)核可以采用以下機(jī)制將頁框映射到內(nèi)核空間
虛擬內(nèi)存區(qū)域 | 說明 |
---|---|
物理內(nèi)存映射 | 映射物理內(nèi)存空間0~896M部分,這一部分是內(nèi)核可以直接訪問的。 |
vmalloc區(qū) | 用來分配物理地址非連續(xù)的內(nèi)存空間 |
永久內(nèi)核映射 | 允許內(nèi)核建立高端頁框到內(nèi)核虛擬地址空間的長期映射。 |
固定映射的線性地址空間 | 其中的一部分用于建立臨時(shí)內(nèi)核映射 |
線性空間中從3G開始大小為896M的區(qū)間,為直接內(nèi)存映射區(qū)
映射關(guān)系為:物理地址等于虛擬地址減去0xc0000000,即虛擬地址減去3G。
如果是通過 alloc_page() 獲得了高端內(nèi)存對應(yīng)的 page,如何給它找個線性空間?
內(nèi)核專門為此留出一塊線性空間,從 PKMAP_BASE 到 FIXADDR_START ,用于映射高端內(nèi)存。這個空間叫永久內(nèi)核映射空間
這個空間和其它空間使用同樣的頁目錄表,對于內(nèi)核來說,就是 swapper_pg_dir,對普通進(jìn)程來說,通過 CR3 寄存器指向。通常情況下,這個空間是 4M 大小,因此僅僅需要一個頁表即可,在內(nèi)核初始化頁表管理機(jī)制時(shí),專門用pkmap_page_table這個變量保存了PKMAP_BASE對應(yīng)的頁表項(xiàng)的地址,由pkmap_page_table來維護(hù)永久內(nèi)核映射區(qū)的頁表項(xiàng)的映射,頁表項(xiàng)總數(shù)為LAST_PKMAP個。通過 kmap(),可以把一個 page 映射到這個空間來。
由于這個空間是 4M 大小,最多能同時(shí)映射 1024 個 page。因此,對于不使用的的 page,應(yīng)該及時(shí)通過 kunmap()把一個 page 對應(yīng)的線性地址從這個空間釋放掉(也就是解除映射關(guān)系)
這里的永久并不是指調(diào)用kmap()建立的映射關(guān)系會一直持續(xù)下去無法解除,而是指在調(diào)用kunmap()解除映射之間這種映射會一直存在,這是相對于臨時(shí)內(nèi)核映射機(jī)制而言的。
需要注意的是,當(dāng)永久內(nèi)核映射區(qū)沒有空閑的頁表項(xiàng)可供映射時(shí),請求映射的進(jìn)程會被阻塞,因此永久內(nèi)核映射請求不能發(fā)生在中斷和可延遲函數(shù)中。
臨時(shí)內(nèi)核映射和永久內(nèi)核映射相比,其最大的特點(diǎn)就是不會阻塞請求映射頁框的進(jìn)程,因此臨時(shí)內(nèi)核映射請求可以發(fā)生在中斷和可延遲函數(shù)中
這塊空間具有如下特點(diǎn):
(1)每個 CPU 占用一塊空間
(2)在每個CPU 占用的那塊空間中,又分為多個小空間,每個小空間大小是 1 個 page,每個小空間用于一個目的,這些目的定義在 kmap_types.h 中的 km_type 中。
系統(tǒng)中的每個CPU都有自己的13個臨時(shí)內(nèi)核映射窗口,根據(jù)不同的需求(用于內(nèi)核控制路徑),選擇不同的窗口來創(chuàng)建映射。每個CPU的映射窗口集合用 enum km_type 數(shù)據(jù)結(jié)構(gòu)表示,該數(shù)據(jù)結(jié)構(gòu)中的每個符號,如 KM_BOUNCE_READ 、 KM_USER0 或 KM_PTE0 ,標(biāo)識了窗口的線性地址,其實(shí)是一個下標(biāo)。當(dāng)要內(nèi)核建立一個臨時(shí)映射時(shí),通過 cpu_id 和 窗口下標(biāo) 來確定線性地址。通過 kmap_atomic() 可實(shí)現(xiàn)臨時(shí)映射。
臨時(shí)內(nèi)核映射的實(shí)現(xiàn)比永久內(nèi)核映射要簡單,當(dāng)一個進(jìn)程申請?jiān)谀硞€窗口創(chuàng)建映射,即使這個窗口已經(jīng)在之前就建立了映射,新的映射也會建立并且覆蓋之前的映射,所以說這種映射機(jī)制是臨時(shí)的,并且不會阻塞當(dāng)前進(jìn)程。
非連續(xù)內(nèi)存分配是指將物理地址不連續(xù)的頁框映射到線性地址連續(xù)的線性地址空間
主要應(yīng)用于大容量的內(nèi)存分配。
優(yōu)點(diǎn):避免了外部碎片
缺點(diǎn):必須打亂內(nèi)核頁表,而且訪問速度較連續(xù)分配的物理頁框慢
非連續(xù)內(nèi)存分配的線性地址空間是從 VMALLOC_START 到 VMALLOC_END ,每當(dāng)內(nèi)核要用vmalloc類的函數(shù)進(jìn)行非連續(xù)內(nèi)存分配,就會申請一個vm_struct結(jié)構(gòu)來描述對應(yīng)的vmalloc區(qū),兩個vmalloc區(qū)之間的間隔至少為一個頁框的大小,即PAGE_SIZE。
總結(jié)
由于內(nèi)核的線性地址空間有限,因此采取上面介紹的三種方式來映射高端內(nèi)存。但是每種映射的本質(zhì)都是通過頁表來建立線性地址與物理地址之間的聯(lián)系。
永久內(nèi)核映射和臨時(shí)內(nèi)核映射,都由內(nèi)核指定了需要進(jìn)行映射的頁面,也就是說指定了頁描述符(頁描述符和物理頁框之間的關(guān)系是固定不可變的)。
在永久內(nèi)核映射中,內(nèi)核只需要在永久內(nèi)核映射區(qū)找到空閑的,也就是未被映射的線性地址對應(yīng)的頁表項(xiàng),然后將其分配給page即可,若找不到則將阻塞申請建立映射的進(jìn)程。
而臨時(shí)內(nèi)核映射更直接,連進(jìn)行映射的線性地址窗口都是固定的,若是其已經(jīng)分配給了某個頁框,則直接搶過來用,因此之前的映射就被覆蓋了,體現(xiàn)出了臨時(shí)性。
非連續(xù)內(nèi)存分配,內(nèi)核不用指定具體的頁框,只需指定要申請的內(nèi)存大小,內(nèi)核將在非連續(xù)內(nèi)存分配區(qū)找到一塊相應(yīng)大小虛擬地址空間,然后再由伙伴系統(tǒng)分配頁框,還要通過slab分配器為一些數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存,最后再用同樣的方式(設(shè)置PTE表項(xiàng))來建立映射。
原文鏈接:來源網(wǎng)絡(luò),如有侵犯到您的權(quán)益請聯(lián)系zengyin969@gmail.com進(jìn)行下架處理
聯(lián)系客服