深入理解Linux高端內(nèi)存

一汤纸、Linux內(nèi)核地址映射模型

x86 CPU采用了段頁(yè)式地址映射模型胰锌。進(jìn)程代碼中的地址為邏輯地址骗绕,經(jīng)過(guò)段頁(yè)式地址映射后,才真正訪問(wèn)物理內(nèi)存资昧。

段頁(yè)式機(jī)制如下圖:
圖片發(fā)自簡(jiǎn)書App

Linux簡(jiǎn)化了分段機(jī)制酬土,使得虛擬地址與線性地址總是一致,因此格带,Linux的虛擬地址空間也為0~4G撤缴。Linux內(nèi)核將這4G字節(jié)的空間分為兩部分。將最高的1G字節(jié)(從虛擬地址0xC0000000到0xFFFFFFFF)叽唱,供內(nèi)核使用屈呕,稱為“內(nèi)核空間”。而將較低的3G字節(jié)(從虛擬地址0x00000000到0xBFFFFFFF)尔觉,供各個(gè)進(jìn)程使用凉袱,稱為“用戶空間)。因?yàn)槊總€(gè)進(jìn)程可以通過(guò)系統(tǒng)調(diào)用進(jìn)入內(nèi)核侦铜,因此专甩,Linux內(nèi)核由系統(tǒng)內(nèi)的所有進(jìn)程共享。于是钉稍,從具體進(jìn)程的角度來(lái)看涤躲,每個(gè)進(jìn)程可以擁有4G字節(jié)的虛擬空間。

Linux使用兩級(jí)保護(hù)機(jī)制:0級(jí)供內(nèi)核使用贡未,3級(jí)供用戶程序使用种樱。從圖中可以看出(這里無(wú)法表示圖)蒙袍,每個(gè)進(jìn)程有各自的私有用戶空間(0~3G),這個(gè)空間對(duì)系統(tǒng)中的其他進(jìn)程是不可見(jiàn)的嫩挤。最高的1GB字節(jié)虛擬內(nèi)核空間則為所有進(jìn)程以及內(nèi)核所共享害幅。

1.虛擬內(nèi)核空間到物理空間的映射
內(nèi)核空間中存放的是內(nèi)核代碼和數(shù)據(jù),而進(jìn)程的用戶空間中存放的是用戶程序的代碼和數(shù)據(jù)岂昭。不管是內(nèi)核空間還是用戶空間以现,它們都處于虛擬空間中。讀者會(huì)問(wèn)约啊,系統(tǒng)啟動(dòng)時(shí)邑遏,內(nèi)核的代碼和數(shù)據(jù)不是被裝入到物理內(nèi)存嗎?它們?yōu)槭裁匆蔡幱谔摂M內(nèi)存中呢恰矩?這和編譯程序有關(guān)记盒,后面我們通過(guò)具體討論就會(huì)明白這一點(diǎn)。
雖然內(nèi)核空間占據(jù)了每個(gè)虛擬空間中的最高1GB字節(jié)外傅,但映射到物理內(nèi)存卻總是從最低地址(0x00000000)開(kāi)始纪吮。對(duì)內(nèi)核空間來(lái)說(shuō),其地址映射是很簡(jiǎn)單的線性映射栏豺,0xC0000000就是物理地址與線性地址之間的位移量彬碱,在Linux代碼中就叫做PAGE_OFFSET。

我們來(lái)看一下在include/asm/i386/page.h中對(duì)內(nèi)核空間中地址映射的說(shuō)明及定義:
圖片發(fā)自簡(jiǎn)書App

源代碼的注釋中說(shuō)明奥洼,如果你的物理內(nèi)存大于950MB巷疼,那么在編譯內(nèi)核時(shí)就需要加CONFIG_HIGHMEM4G和CONFIG_HIGHMEM64G選項(xiàng)桨螺,這種情況我們暫不考慮晌坤。如果物理內(nèi)存小于950MB,則對(duì)于內(nèi)核空間而言车柠,給定一個(gè)虛地址x瓷患,其物理地址為“x-PAGE_OFFSET”骡尽,給定一個(gè)物理地址x,其虛地址為“x+PAGE_OFFSET”擅编。

這里再次說(shuō)明攀细,宏__pa()僅僅把一個(gè)內(nèi)核空間的虛地址映射到物理地址,而決不適用于用戶空間爱态,用戶空間的地址映射要復(fù)雜得多谭贪。

2.內(nèi)核映像
在下面的描述中,我們把內(nèi)核的代碼和數(shù)據(jù)就叫內(nèi)核映像(kernel image)锦担。當(dāng)系統(tǒng)啟動(dòng)時(shí)俭识,Linux內(nèi)核映像被安裝在物理地址0x00100000開(kāi)始的地方,即1MB開(kāi)始的區(qū)間(第1M留作它用)洞渔。然而套媚,在正常運(yùn)行時(shí)缚态,整個(gè)內(nèi)核映像應(yīng)該在虛擬內(nèi)核空間中,因此堤瘤,連接程序在連接內(nèi)核映像時(shí)玫芦,在所有的符號(hào)地址上加一個(gè)偏移量PAGE_OFFSET,這樣宙橱,內(nèi)核映像在內(nèi)核空間的起始地址就為0xC0100000姨俩。

例如,進(jìn)程的頁(yè)目錄PGD(屬于內(nèi)核數(shù)據(jù)結(jié)構(gòu))就處于內(nèi)核空間中师郑。在進(jìn)程切換時(shí),要將寄存器CR3設(shè)置成指向新進(jìn)程的頁(yè)目錄PGD调窍,而該目錄的起始地址在內(nèi)核空間中是虛地址宝冕,但CR3所需要的是物理地址,這時(shí)候就要用__pa()進(jìn)行地址轉(zhuǎn)換邓萨。在mm_context.h中就有這么一行語(yǔ)句:

asm volatile("movl %0,%%cr3": :"r"(__pa(next_pgd;pgd)));

這是一行嵌入式匯編代碼地梨,其含義是將下一個(gè)進(jìn)程的頁(yè)目錄起始地址next_pgd,通過(guò)__pa()轉(zhuǎn)換成物理地址缔恳,存放在某個(gè)寄存器中宝剖,然后用mov指令將其寫入CR3寄存器中。經(jīng)過(guò)這行語(yǔ)句的處理歉甚,CR3就指向新進(jìn)程next的頁(yè)目錄表PGD了万细。

二、Linux內(nèi)核地址空間劃分

通常32位Linux內(nèi)核地址空間劃分0 ~ 3G為用戶空間纸泄,3 ~ 4G為內(nèi)核空間赖钞。注意這里是32位內(nèi)核地址空間劃分,64位內(nèi)核地址空間劃分是不同的聘裁。
圖片發(fā)自簡(jiǎn)書App

三雪营、Linux內(nèi)核高端內(nèi)存的由來(lái)

當(dāng)內(nèi)核模塊代碼或線程訪問(wèn)內(nèi)存時(shí),代碼中的內(nèi)存地址都為邏輯地址衡便,而對(duì)應(yīng)到真正的物理內(nèi)存地址献起,需要地址一對(duì)一的映射,如邏輯地址0xc0000003對(duì)應(yīng)的物理地址為0×3镣陕,0xc0000004對(duì)應(yīng)的物理地址為0×4谴餐,… …,邏輯地址與物理地址對(duì)應(yīng)的關(guān)系為:

物理地址 = 邏輯地址 – 0xC0000000

假設(shè)按照上述簡(jiǎn)單的地址映射關(guān)系茁彭,那么內(nèi)核邏輯地址空間訪問(wèn)為0xc0000000 ~ 0xffffffff总寒,那么對(duì)應(yīng)的物理內(nèi)存范圍就為0×0 ~ 0×40000000,即只能訪問(wèn)1G物理內(nèi)存理肺。若機(jī)器中安裝8G物理內(nèi)存摄闸,那么內(nèi)核就只能訪問(wèn)前1G物理內(nèi)存善镰,后面7G物理內(nèi)存將會(huì)無(wú)法訪問(wèn),因?yàn)閮?nèi)核 的地址空間已經(jīng)全部映射到物理內(nèi)存地址范圍0×0 ~ 0×40000000年枕。即使安裝了8G物理內(nèi)存炫欺,那么物理地址為0×40000001的內(nèi)存,內(nèi)核該怎么去訪問(wèn)呢熏兄?代碼中必須要有內(nèi)存邏輯地址 的品洛,0xc0000000 ~ 0xffffffff的地址空間已經(jīng)被用完了,所以無(wú)法訪問(wèn)物理地址0×40000000以后的內(nèi)存摩桶。

顯然不能將內(nèi)核地址空間0xc0000000 ~ 0xfffffff全部用來(lái)簡(jiǎn)單的地址映射桥状。因此x86架構(gòu)中將內(nèi)核地址空間劃分三部分:ZONE_DMA, ZONE_NORMAL和 ZONE_HIGHMEM。ZONE_HIGHMEM即為高端內(nèi)存硝清,這就是內(nèi)存高端內(nèi)存概念的由來(lái)辅斟。

在x86結(jié)構(gòu)中,三種類型的區(qū)域如下:

名稱 范圍
ZONE_DMA 內(nèi)存開(kāi)始的16MB
ZONE_NORMAL 16MB~896MB
ZONE_HIGHMEM 896MB ~ 結(jié)束
圖片發(fā)自簡(jiǎn)書App

四芦拿、Linux內(nèi)核高端內(nèi)存的理解

高端內(nèi)存HIGH_MEM地址空間范圍為0xF8000000~0xFFFFFFFF(896MB~1024MB)士飒。那么如內(nèi)核是如何借助128MB高端內(nèi)存地址空間是如何實(shí)現(xiàn)訪問(wèn)可以所有物理內(nèi)存?

Linux將內(nèi)核地址空間劃分為三部分:

  • ZONE_DMA蔗崎、
  • ZONE_NORMAL
  • ZONE_HIGHMEM

前面我們解釋了高端內(nèi)存的由來(lái)酵幕。當(dāng)內(nèi)核想訪問(wèn)高于896MB物理地址內(nèi)存時(shí),從0xF8000000 ~ 0xFFFFFFFF地址空間范圍內(nèi)找一段相應(yīng)大小空閑的邏輯地址空間缓苛,借用一會(huì)芳撒。借用這段邏輯地址空間,建立映射到想訪問(wèn)的那段物理內(nèi)存(即填充內(nèi)核PTE頁(yè)面表)他嫡,臨時(shí)用一會(huì)番官,用完后歸還。這樣別人也可以借用這段地址空間訪問(wèn)其他物理內(nèi)存钢属,實(shí)現(xiàn)了使用有限的地址空間徘熔,訪問(wèn)所有所有物理內(nèi)存。如下圖淆党。


圖片發(fā)自簡(jiǎn)書App

例如內(nèi)核想訪問(wèn)2G開(kāi)始的一段大小為1MB的物理內(nèi)存酷师,即物理地址范圍為0×80000000 ~ 0x800FFFFF。訪問(wèn)之前先找到一段1MB大小的空閑地址空間染乌,假設(shè)找到的空閑地址空間為0xF8700000 ~ 0xF87FFFFF山孔,用這1MB的邏輯地址空間映射到物理地址空間0×80000000 ~ 0x800FFFFF的內(nèi)存。映射關(guān)系如下:

邏輯地址 物理地址
0xF8700000 0x80000000
0xF8700001 0x80000001
0xF87FFFFF 0x800FFFFF

當(dāng)內(nèi)核訪問(wèn)完0×80000000 ~ 0x800FFFFF物理內(nèi)存后荷憋,就將0xF8700000 ~ 0xF87FFFFF內(nèi)核線性空間釋放台颠。這樣其他進(jìn)程或代碼也可以使用0xF8700000 ~ 0xF87FFFFF這段地址訪問(wèn)其他物理內(nèi)存。

從上面的描述,我們可以知道高端內(nèi)存的最基本思想:借一段地址空間串前,建立臨時(shí)地址映射瘫里,用完后釋放,達(dá)到這段地址空間可以循環(huán)使用荡碾,訪問(wèn)所有物理內(nèi)存谨读。

看到這里,不禁有人會(huì)問(wèn):萬(wàn)一有內(nèi)核進(jìn)程或模塊一直占用某段邏輯地址空間不釋放坛吁,怎么辦劳殖?若真的出現(xiàn)的這種情況,則內(nèi)核的高端內(nèi)存地址空間越來(lái)越緊張拨脉,若都被占用不釋放哆姻,則沒(méi)有建立映射到物理內(nèi)存都無(wú)法訪問(wèn)了。

五女坑、Linux內(nèi)核高端內(nèi)存的劃分

內(nèi)核將高端內(nèi)存劃分為3部分:

  • VMALLOC_START ~ VMALLOC_END
  • KMAP_BASE ~ FIXADDR_START
  • FIXADDR_START ~ 0xFFFFFFFF

對(duì)于高端內(nèi)存填具,可以通過(guò) alloc_page() 或者其它函數(shù)獲得對(duì)應(yīng)的 page,但是要想訪問(wèn)實(shí)際物理內(nèi)存匆骗,還得把 page 轉(zhuǎn)為線性地址才行(為什么?想想 MMU 是如何訪問(wèn)物理內(nèi)存的)誉简,也就是說(shuō)碉就,我們需要為高端內(nèi)存對(duì)應(yīng)的 page 找一個(gè)線性空間,這個(gè)過(guò)程稱為高端內(nèi)存映射闷串。

對(duì)應(yīng)高端內(nèi)存的3部分瓮钥,高端內(nèi)存映射有三種方式:

  1. 映射到”內(nèi)核動(dòng)態(tài)映射空間”(noncontiguous memory allocation)。
    這種方式很簡(jiǎn)單烹吵,因?yàn)橥ㄟ^(guò) vmalloc() 碉熄,在”內(nèi)核動(dòng)態(tài)映射空間”申請(qǐng)內(nèi)存的時(shí)候,就可能從高端內(nèi)存獲得頁(yè)面(參看 vmalloc 的實(shí)現(xiàn))肋拔,因此說(shuō)高端內(nèi)存有可能映射到”內(nèi)核動(dòng)態(tài)映射空間”中锈津。

  2. 持久內(nèi)核映射(permanent kernel mapping)。
    如果是通過(guò) alloc_page() 獲得了高端內(nèi)存對(duì)應(yīng)的 page凉蜂,如何給它找個(gè)線性空間琼梆??jī)?nèi)核專門為此留出一塊線性空間,從 PKMAP_BASE 到 FIXADDR_START 窿吩,用于映射高端內(nèi)存茎杂。在 2.6內(nèi)核上,這個(gè)地址范圍是 4G-8M 到 4G-4M 之間纫雁。這個(gè)空間起叫”內(nèi)核永久映射空間”或者”永久內(nèi)核映射空間”煌往。這個(gè)空間和其它空間使用同樣的頁(yè)目錄表,對(duì)于內(nèi)核來(lái)說(shuō)轧邪,就是 swapper_pg_dir刽脖,對(duì)普通進(jìn)程來(lái)說(shuō)羞海,通過(guò) CR3 寄存器指向。通常情況下曾棕,這個(gè)空間是 4M 大小扣猫,因此僅僅需要一個(gè)頁(yè)表即可,內(nèi)核通過(guò)來(lái) pkmap_page_table 尋找這個(gè)頁(yè)表翘地。通過(guò) kmap()申尤,可以把一個(gè) page 映射到這個(gè)空間來(lái)。由于這個(gè)空間是 4M 大小衙耕,最多能同時(shí)映射 1024 個(gè) page昧穿。因此,對(duì)于不使用的的 page橙喘,及應(yīng)該時(shí)從這個(gè)空間釋放掉(也就是解除映射關(guān)系)时鸵,通過(guò) kunmap() ,可以把一個(gè) page 對(duì)應(yīng)的線性地址從這個(gè)空間釋放出來(lái)厅瞎。

  3. 臨時(shí)映射(temporary kernel mapping)
    內(nèi)核在 FIXADDR_START 到 FIXADDR_TOP 之間保留了一些線性空間用于特殊需求饰潜。這個(gè)空間稱為”固定映射空間”在這個(gè)空間中,有一部分用于高端內(nèi)存的臨時(shí)映射和簸。

這塊空間具有如下特點(diǎn):
(1)每個(gè) CPU 占用一塊空間
(2)在每個(gè) CPU 占用的那塊空間中彭雾,又分為多個(gè)小空間,每個(gè)小空間大小是 1 個(gè) page锁保,每個(gè)小空間用于一個(gè)目的薯酝,這些目的定義在 kmap_types.h 中的 km_type中。當(dāng)要進(jìn)行一次臨時(shí)映射的時(shí)候爽柒,需要指定映射的目的吴菠,根據(jù)映射目的,可以找到對(duì)應(yīng)的小空間浩村,然后把這個(gè)空間的地址作為映射地址做葵。這意味著一次臨時(shí)映射會(huì)導(dǎo)致以前的映射被覆蓋。通過(guò) kmap_atomic() 可實(shí)現(xiàn)臨時(shí)映射穴亏。

六蜂挪、常見(jiàn)問(wèn)題:

  1. 用戶空間(進(jìn)程)是否有高端內(nèi)存概念?
    用戶進(jìn)程沒(méi)有高端內(nèi)存概念嗓化。只有在內(nèi)核空間才存在高端內(nèi)存棠涮。用戶進(jìn)程最多只可以訪問(wèn)3G物理內(nèi)存,而內(nèi)核進(jìn)程可以訪問(wèn)所有物理內(nèi)存刺覆。

  2. 64位內(nèi)核中有高端內(nèi)存嗎严肪?
    目前現(xiàn)實(shí)中,64位Linux內(nèi)核不存在高端內(nèi)存,因?yàn)?4位內(nèi)核可以支持超過(guò)512GB內(nèi)存驳糯。若機(jī)器安裝的物理內(nèi)存超過(guò)內(nèi)核地址空間范圍篇梭,就會(huì)存在高端內(nèi)存。

  3. 用戶進(jìn)程能訪問(wèn)多少物理內(nèi)存酝枢??jī)?nèi)核代碼能訪問(wèn)多少物理內(nèi)存恬偷?
    32位系統(tǒng)用戶進(jìn)程最大可以訪問(wèn)3GB,內(nèi)核代碼可以訪問(wèn)所有物理內(nèi)存帘睦。
    64位系統(tǒng)用戶進(jìn)程最大可以訪問(wèn)超過(guò)512GB袍患,內(nèi)核代碼可以訪問(wèn)所有物理內(nèi)存。

  4. 高端內(nèi)存和物理地址竣付、邏輯地址诡延、線性地址的關(guān)系?
    高端內(nèi)存只和邏輯地址有關(guān)系古胆,和邏輯地址肆良、物理地址沒(méi)有直接關(guān)系。

  5. 為什么不把所有的地址空間都分配給內(nèi)核逸绎?
    若把所有地址空間都給內(nèi)存惹恃,那么用戶進(jìn)程怎么使用內(nèi)存?怎么保證內(nèi)核使用內(nèi)存和用戶進(jìn)程不起沖突棺牧?
    (1)讓我們忽略Linux對(duì)段式內(nèi)存映射的支持座舍。 在保護(hù)模式下,我們知道無(wú)論CPU運(yùn)行于用戶態(tài)還是核心態(tài)陨帆,CPU執(zhí)行程序所訪問(wèn)的地址都是虛擬地址,MMU 必須通過(guò)讀取控制寄存器CR3中的值作為當(dāng)前頁(yè)面目錄的指針采蚀,進(jìn)而根據(jù)分頁(yè)內(nèi)存映射機(jī)制(參看相關(guān)文檔)將該虛擬地址轉(zhuǎn)換為真正的物理地址才能讓CPU真 正的訪問(wèn)到物理地址疲牵。
    (2)對(duì)于32位的Linux,其每一個(gè)進(jìn)程都有4G的尋址空間榆鼠,但當(dāng)一個(gè)進(jìn)程訪問(wèn)其虛擬內(nèi)存空間中的某個(gè)地址時(shí)又是怎樣實(shí)現(xiàn)不與其它進(jìn)程的虛擬空間混淆 的呢纲爸?每個(gè)進(jìn)程都有其自身的頁(yè)面目錄PGD,Linux將該目錄的指針存放在與進(jìn)程對(duì)應(yīng)的內(nèi)存結(jié)構(gòu)task_struct.(struct mm_struct)mm->pgd中妆够。每當(dāng)一個(gè)進(jìn)程被調(diào)度(schedule())即將進(jìn)入運(yùn)行態(tài)時(shí)识啦,Linux內(nèi)核都要用該進(jìn)程的PGD指針設(shè) 置CR3(switch_mm())。
    (3)當(dāng)創(chuàng)建一個(gè)新的進(jìn)程時(shí)神妹,都要為新進(jìn)程創(chuàng)建一個(gè)新的頁(yè)面目錄PGD颓哮,并從內(nèi)核的頁(yè)面目錄swapper_pg_dir中復(fù)制內(nèi)核區(qū)間頁(yè)面目錄項(xiàng)至新建進(jìn)程頁(yè)面目錄PGD的相應(yīng)位置,具體過(guò)程如下:
    do_fork() --> copy_mm() --> mm_init() --> pgd_alloc() --> set_pgd_fast() --> get_pgd_slow() --> memcpy(&PGD + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t))
    這樣一來(lái)鸵荠,每個(gè)進(jìn)程的頁(yè)面目錄就分成了兩部分冕茅,第一部分為“用戶空間”,用來(lái)映射其整個(gè)進(jìn)程空間(0x0000 0000-0xBFFF FFFF)即3G字節(jié)的虛擬地址;第二部分為“系統(tǒng)空間”姨伤,用來(lái)映射(0xC000 0000-0xFFFF FFFF)1G字節(jié)的虛擬地址哨坪。可以看出Linux系統(tǒng)中每個(gè)進(jìn)程的頁(yè)面目錄的第二部分是相同的乍楚,所以從進(jìn)程的角度來(lái)看当编,每個(gè)進(jìn)程有4G字節(jié)的虛擬空間, 較低的3G字節(jié)是自己的用戶空間徒溪,最高的1G字節(jié)則為與所有進(jìn)程以及內(nèi)核共享的系統(tǒng)空間忿偷。
    (4)現(xiàn)在假設(shè)我們有如下一個(gè)情景:
    在進(jìn)程A中通過(guò)系統(tǒng)調(diào)用sethostname(const char *name,seze_t len)設(shè)置計(jì)算機(jī)在網(wǎng)絡(luò)中的“主機(jī)名”。在該情景中我們勢(shì)必涉及到從用戶空間向內(nèi)核空間傳遞數(shù)據(jù)的問(wèn)題词渤,name是用戶空間中的地址牵舱,它要通過(guò)系統(tǒng)調(diào)用設(shè)置到內(nèi)核中的某個(gè)地址中。讓我們看看這個(gè) 過(guò)程中的一些細(xì)節(jié)問(wèn)題:系統(tǒng)調(diào)用的具體實(shí)現(xiàn)是將系統(tǒng)調(diào)用的參數(shù)依次存入寄存器ebx,ecx,edx,esi,edi(最多5個(gè)參數(shù)缺虐,該情景有兩個(gè) name和len)芜壁,接著將系統(tǒng)調(diào)用號(hào)存入寄存器eax,然后通過(guò)中斷指令“int 80”使進(jìn)程A進(jìn)入系統(tǒng)空間高氮。由于進(jìn)程的CPU運(yùn)行級(jí)別小于等于為系統(tǒng)調(diào)用設(shè)置的陷阱門的準(zhǔn)入級(jí)別3慧妄,所以可以暢通無(wú)阻的進(jìn)入系統(tǒng)空間去執(zhí)行為int 80設(shè)置的函數(shù)指針system_call()。由于system_call()屬于內(nèi)核空間剪芍,其運(yùn)行級(jí)別DPL為0塞淹,CPU要將堆棧切換到內(nèi)核堆棧,即 進(jìn)程A的系統(tǒng)空間堆棧罪裹。我們知道內(nèi)核為新建進(jìn)程創(chuàng)建task_struct結(jié)構(gòu)時(shí)饱普,共分配了兩個(gè)連續(xù)的頁(yè)面,即8K的大小状共,并將底部約1k的大小用于 task_struct( 如#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)))套耕,而其余部分內(nèi)存用于系統(tǒng)空間的堆棧空間峡继,即當(dāng)從用戶空間轉(zhuǎn)入系統(tǒng)空間時(shí)冯袍,堆棧指針 esp變成了(alloc_task_struct()+8192),這也是為什么系統(tǒng)空間通常用宏定義current(參看其實(shí)現(xiàn))獲取當(dāng)前進(jìn)程的 task_struct地址的原因碾牌。每次在進(jìn)程從用戶空間進(jìn)入系統(tǒng)空間之初康愤,系統(tǒng)堆棧就已經(jīng)被依次壓入用戶堆棧SS、用戶堆棧指針ESP舶吗、EFLAGS征冷、 用戶空間CS、EIP裤翩,接著system_call()將eax壓入资盅,再接著調(diào)用SAVE_ALL依次壓入ES调榄、DS、EAX呵扛、EBP每庆、EDI、ESI今穿、 EDX缤灵、ECX、EBX蓝晒,然后調(diào)用sys_call_table+4*%EAX腮出,本情景為sys_sethostname()。
    5)在sys_sethostname()中芝薇,經(jīng)過(guò)一些保護(hù)考慮后胚嘲,調(diào)用copy_from_user(to,from,n),其中to指向內(nèi)核空間 system_utsname.nodename洛二,譬如0xE625A000馋劈,from指向用戶空間譬如0x8010FE00。現(xiàn)在進(jìn)程A進(jìn)入了內(nèi)核晾嘶,在 系統(tǒng)空間中運(yùn)行妓雾,MMU根據(jù)其PGD將虛擬地址完成到物理地址的映射,最終完成從用戶空間到系統(tǒng)空間數(shù)據(jù)的復(fù)制垒迂。準(zhǔn)備復(fù)制之前內(nèi)核先要確定用戶空間地址和 長(zhǎng)度的合法性械姻,至于從該用戶空間地址開(kāi)始的某個(gè)長(zhǎng)度的整個(gè)區(qū)間是否已經(jīng)映射并不去檢查,如果區(qū)間內(nèi)某個(gè)地址未映射或讀寫權(quán)限等問(wèn)題出現(xiàn)時(shí)机断,則視為壞地址楷拳, 就產(chǎn)生一個(gè)頁(yè)面異常,讓頁(yè)面異常服務(wù)程序處理吏奸。過(guò)程如 下:copy_from_user()->generic_copy_from_user()->access_ok()+__copy_user_zeroing().

小結(jié)

  • 進(jìn)程尋址空間0~4G 唯竹。
  • 進(jìn)程在用戶態(tài)只能訪問(wèn)03G,只有進(jìn)入內(nèi)核態(tài)才能訪問(wèn)3G4G 苦丁。
  • 進(jìn)程通過(guò)系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài)。
  • 每個(gè)進(jìn)程虛擬空間的3G~4G部分是相同的物臂。
  • 進(jìn)程從用戶態(tài)進(jìn)入內(nèi)核態(tài)不會(huì)引起CR3的改變但會(huì)引起堆棧的改變旺拉。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市棵磷,隨后出現(xiàn)的幾起案子蛾狗,更是在濱河造成了極大的恐慌,老刑警劉巖仪媒,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沉桌,死亡現(xiàn)場(chǎng)離奇詭異谢鹊,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)留凭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門佃扼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蔼夜,你說(shuō)我怎么就攤上這事兼耀。” “怎么了求冷?”我有些...
    開(kāi)封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵瘤运,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我匠题,道長(zhǎng)拯坟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任韭山,我火速辦了婚禮郁季,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掠哥。我一直安慰自己巩踏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布续搀。 她就那樣靜靜地躺著塞琼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪禁舷。 梳的紋絲不亂的頭發(fā)上彪杉,一...
    開(kāi)封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音牵咙,去河邊找鬼派近。 笑死,一個(gè)胖子當(dāng)著我的面吹牛洁桌,可吹牛的內(nèi)容都是我干的渴丸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼另凌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼谱轨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起吠谢,我...
    開(kāi)封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤土童,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后工坊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體献汗,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敢订,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了罢吃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楚午。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刃麸,靈堂內(nèi)的尸體忽然破棺而出醒叁,到底是詐尸還是另有隱情,我是刑警寧澤泊业,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布把沼,位于F島的核電站,受9級(jí)特大地震影響吁伺,放射性物質(zhì)發(fā)生泄漏饮睬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一篮奄、第九天 我趴在偏房一處隱蔽的房頂上張望捆愁。 院中可真熱鬧,春花似錦窟却、人聲如沸昼丑。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菩帝。三九已至,卻和暖如春茬腿,著一層夾襖步出監(jiān)牢的瞬間呼奢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工切平, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留握础,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓悴品,卻偏偏與公主長(zhǎng)得像禀综,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苔严,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 內(nèi)存管理一向是所有操作系統(tǒng)書籍不惜筆墨重點(diǎn)討論的內(nèi)容菇存,無(wú)論市面上或是網(wǎng)上都充斥著大量涉及內(nèi)存管理的教材和資料...
    木有sky閱讀 907評(píng)論 0 1
  • 操作系統(tǒng)對(duì)內(nèi)存的管理 沒(méi)有內(nèi)存抽象的年代 在早些的操作系統(tǒng)中,并沒(méi)有引入內(nèi)存抽象的概念邦蜜。程序直接訪問(wèn)和操作的都是物...
    Mr槑閱讀 16,701評(píng)論 3 24
  • 1 內(nèi)存尋址 1.1 物理地址、虛擬地址以及線性地址 物理地址: 物理內(nèi)存的內(nèi)存單元地址 虛擬地址: 程序員看到的...
    瘋狂小王子閱讀 2,816評(píng)論 3 21
  • 進(jìn)程 創(chuàng)建 創(chuàng)建進(jìn)程用fork()函數(shù)亥至。fork()為子進(jìn)程創(chuàng)建新的地址空間并且拷貝頁(yè)表悼沈。子進(jìn)程的虛擬地址空間...
    梅花怒閱讀 1,908評(píng)論 0 7
  • 今天臺(tái)風(fēng)在上海登陸贱迟,所以接到體育局的通知,所以我們能休息一天絮供,睡了一天的覺(jué)衣吠。估計(jì)晚上又睡不著了晚安吧。
    吳三石石石石ah閱讀 76評(píng)論 0 0