LINUX2.6中進(jìn)程的內(nèi)核空間共享作者:waitquiet 2009-06-02 16:26 星期二 晴
在2.6內(nèi)核中,所有進(jìn)程的內(nèi)核空間(3G-4G)都是共享的。
LINUX內(nèi)核在初始化過程中,內(nèi)核頁(yè)表的初始化在保護(hù)模式下,但是此時(shí)尚未開啟分頁(yè)機(jī)制。內(nèi)核填充PGD表(靜態(tài)數(shù)組),使得(3G-4G)的虛擬地址映射到物理地址(0-1G),確切的講,是(3G -3G+896M)的虛擬地址映射到物理地址(0-896M),因?yàn)槭O碌?3G+896M--4G)虛擬空間可以用來映射物理存儲(chǔ)器的高端地址(大于896M)。然后內(nèi)核將PGD基地址加載到CR3中,將CR0的PG位置1,正式開啟分頁(yè)機(jī)制。此時(shí),(3G-3G+896M)的虛擬地址正式映射到物理地址(0-896M)。 內(nèi)核頁(yè)表PGD將作為進(jìn)程SWAPPER(PID=0)的頁(yè)表,SWAPPER是系統(tǒng)中的第一個(gè)進(jìn)程,除了SWAPPER,內(nèi)核還創(chuàng)建INIT進(jìn)程。 INIT進(jìn)程的頁(yè)表跟內(nèi)核頁(yè)表是一致的,系統(tǒng)中的其它所有用戶進(jìn)程都是INIT進(jìn)程的兒子或后代。 而在LINUX中,用戶進(jìn)程的創(chuàng)建都是父進(jìn)程通過FORK()函數(shù)實(shí)現(xiàn),創(chuàng)建的子進(jìn)程有兩種情形:1)子進(jìn)程與父進(jìn)程完全共享地址空間,此時(shí)它們共享PGD以及PTE;2)子進(jìn)程不與父進(jìn)程共享地址空間,此時(shí)它們有各自的PGD與PTE,但是(在創(chuàng)建之初)子進(jìn)程的PGD與PTE是父進(jìn)程的拷貝。 在各個(gè)進(jìn)程的運(yùn)行過程中,他們的頁(yè)表可能會(huì)發(fā)生變化,比如發(fā)生缺頁(yè)異常,或者執(zhí)行EXEC()系列函數(shù),但是所有這些頁(yè)表項(xiàng)的變化都屬于用戶空間(0--3G)。內(nèi)核空間的頁(yè)表幾乎不變,確切的講,(3G-3G+896M)之間的頁(yè)表項(xiàng)不變(也就是說,所有進(jìn)程的3G--3G+896M的虛擬地址都映射到物理地址0--896M)。相反,(3G+896M--4G)之間的頁(yè)表可能會(huì)變,比如內(nèi)核執(zhí)行VMALLOC()函數(shù),可能就會(huì)修改(3G+896M--4G)之間的頁(yè)表,為了使所有進(jìn)程的內(nèi)核空間(3G--4G)都保持一致,原則上必須修改每個(gè)進(jìn)程的(3G+896M--4G)之間的頁(yè)表,這樣做的效率比較低下。LINUX內(nèi)核通過PAGE FAULT機(jī)制保持所有進(jìn)程的(3G+896M--4G)之間的頁(yè)表一致。 比如在vmalloc分配了一塊內(nèi)存,如何通知所有的進(jìn)程修改其頁(yè)表呢?遍歷修改?vmalloc先在kernel virtual space找出一段空間,分配出物理頁(yè),然后更新到init_mm.pgd所指的page table中。但是當(dāng)前進(jìn)程的page table中kernel virtual space那段還是要通過page fault來更新。當(dāng)發(fā)生page fault時(shí),內(nèi)核通過讀取cr2來判斷異常的類型,異常發(fā)生時(shí)cpu會(huì)將3位的error_code壓入到棧中。如果發(fā)生了由于內(nèi)核訪問不存在的頁(yè)框引起的異常,就跳轉(zhuǎn)去執(zhí)行vmalloc_fault標(biāo)記處的代碼。這部分代碼負(fù)責(zé)從主內(nèi)核頁(yè)表中取出相應(yīng)信息并更新當(dāng)前進(jìn)程的頁(yè)表。 |
|
|