国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

《Undocumented Windows 2000 Secrets》翻譯 --- 第四章(1)

瀏覽:101日期:2023-08-27 14:18:45

第四章 探索 Windows 2000 的內(nèi)存管理機(jī)制

翻譯: Kendiv( fcczj@263.ne t)

更新: Sunday, February 13, 2005

聲明:轉(zhuǎn)載請(qǐng)注明出處,并保證文章的完整性,本人保留譯文的所有權(quán)利。

內(nèi)存管理對(duì)于操作系統(tǒng)來(lái)說(shuō)是非常重要的。本章將全面的縱覽 Windows 2000 的內(nèi)存管理機(jī)制以及 4GB 線性地址空間的結(jié)構(gòu)。針對(duì)此部分內(nèi)容,將解釋 Intel i386 CPU 家族的虛擬內(nèi)存尋址及其分頁(yè)能力,重點(diǎn)將在于 Windows 2000 的內(nèi)核是如何使用它們的。為了幫助我們對(duì)內(nèi)存的探索,本章提供了一對(duì)程序:一個(gè)內(nèi)核模式的驅(qū)動(dòng)程序,該驅(qū)動(dòng)用來(lái)收集系統(tǒng)相關(guān)的信息,另一個(gè)是用戶模式的應(yīng)用程序,該程序?qū)⑼ㄟ^(guò)設(shè)備 I/O 控制來(lái)查詢來(lái)自驅(qū)動(dòng)程序的數(shù)據(jù),并在控制臺(tái)窗口中進(jìn)行顯示。在剩余的章節(jié)中將重復(fù)使用“ Spy Driver ”模塊來(lái)完成其他幾個(gè)非常有趣的任務(wù)(這些任務(wù)都需要在內(nèi)核模式下執(zhí)行代碼)。請(qǐng)堅(jiān)持閱讀完本章的第一部分,因?yàn)樗鼘⒅苯用鎸?duì) CPU 硬件。不過(guò),我仍然希望你不要跳過(guò)它,因?yàn)樘摂M內(nèi)存管理是一個(gè)非常令人興奮的話題,理解它是如何工作的,將幫助你洞察復(fù)雜操作系統(tǒng)(如 Windows 2000 )采用的機(jī)制。

Intel i386 內(nèi)存管理機(jī)制

Windows 2000 內(nèi)核大量使用 Intel i386 CPU 系列提供的保護(hù)模式下的虛擬內(nèi)存管理機(jī)制。為了更好的理解 Windows 2000 如何管理它的主內(nèi)存,最低限度的熟悉 i386 CPU 的架構(gòu)某些特點(diǎn)就顯得尤為重要。 Windows 2000 是針對(duì) Pentium 以上 CPU 設(shè)計(jì)的。不過(guò),這些新的處理器采用的內(nèi)存管理模型仍源自針對(duì) 80386 CPU 的設(shè)計(jì),不過(guò)當(dāng)然會(huì)加入了一些重要的增強(qiáng)。因此,微軟通常標(biāo)注 Windows NT 和 Windows 2000 的版本為 Intel 處理器“ i386 ”或者“ x86 ”。不要對(duì)這些感到困惑,不管你在本書的什么地方遇到 86 或 386 ,請(qǐng)記住,這只是表示特定的 CPU 架構(gòu),而不是特定的處理器版本。

基本的內(nèi)存布局

Windows 2000 為應(yīng)用程序和系統(tǒng)代碼提供了非常簡(jiǎn)單的內(nèi)存布局。由 32 位的 Intel CPU 提供的 4GB 虛擬內(nèi)存空間被分割為相等的兩部分。低于 0x80000000 的內(nèi)存地址由用戶模式下的模塊使用,這包括 Win32 子系統(tǒng),剩余的 2GB 保留給了系統(tǒng)內(nèi)核。 Windows 2000 Advanced Server 還支持通常稱為 4GT RAM Tuning 的另一種內(nèi)存模型,該模型隨 Windows NT 4.0 Server 的企業(yè)版引入。該模型可提供 3GB 的用戶地址空間,另 1GB 保留給內(nèi)核,通過(guò)在 boot.ini 中添加 /3GB 選項(xiàng)來(lái)啟用該模型。

Windows 2000 Advanced Server 和 DataCenter 支持稱為:物理地址擴(kuò)展( Physical Address Extension, PAE )的內(nèi)存選項(xiàng),通過(guò)在 boot.ini 中加入 /PAE 就可允許這種內(nèi)存方式。該選項(xiàng)采用了某些 Intel CPU 的特性(如, Pentium Pro 處理器)以允許大于 4GB 的物理內(nèi)存映射到 32 位的地址空間上。在本章中,我將忽略這種特殊的設(shè)置。你可閱讀微軟的基本知識(shí)文章 Q171793 (微軟 2000c )、 Intel 的 Pentium 手冊(cè)( Intel 1999a,1999b,1999c )以及 Windows 2000 DDK 文檔(微軟 2000f )來(lái)獲取更多此方面的信息。

內(nèi)存分段和請(qǐng)求式分頁(yè)

在深入 i386 架構(gòu)的技術(shù)細(xì)節(jié)之前,想讓我們回到 1978 年,那一年 Intel 發(fā)布了 PC 處理器之母: 8086 。我想將討論限制到這個(gè)有重大意義的里程碑上。如果你打算知道更多,閱讀 Robert L. 的 80486 程序員參考( Hummel 1992 )將是一個(gè)很棒的開始。現(xiàn)在看來(lái)這有些過(guò)時(shí)了,因?yàn)樗鼪]有涵蓋 Pentium 處理器家族的新特性;不過(guò),該參考手冊(cè)中仍保留了大量 i386 架構(gòu)的基本信息。盡管 8086 能夠訪問(wèn) 1MB RAM 的地址空間,但應(yīng)用程序還是無(wú)法“看到”整個(gè)的物理地址空間,這是因?yàn)?CPU 寄存器的地址僅有 16 位。這就意味著應(yīng)用程序可訪問(wèn)的連續(xù)線性地址空間僅有 64KB ,但是通過(guò) 16 位段寄存器的幫助,這個(gè) 64KB 大小的內(nèi)存窗口就可以在整個(gè)物理空間中上下移動(dòng), 64KB 邏輯空間中的線性地址作為偏移量和基地址(由 16 位的段寄存器給處)相加,從而構(gòu)成有效的 20 位地址。這種古老的內(nèi)存模型仍然被最新的 Pentium CPU 支持,它被稱為:實(shí)地址模式,通常叫做:實(shí)模式。

80286 CPU 引入了另一種模式,稱為:受保護(hù)的虛擬地址模式,或者簡(jiǎn)單的稱之為:保護(hù)模式。該模式提供的內(nèi)存模型中使用的物理地址不再是簡(jiǎn)單的將線性地址和段基址相加。為了保持與 8086 和 80186 的向后兼容, 80286 仍然使用段寄存器,但是在切換到保護(hù)模式后,它們將不再包含物理段的地址。替代的是,它們提供了一個(gè)選擇器( selector ),該選擇器由一個(gè)描述符表的索引構(gòu)成。描述符表中的每一項(xiàng)都定義了一個(gè) 24 位的物理基址,允許訪問(wèn) 16MB RAM ,在當(dāng)時(shí)這是一個(gè)很不可思議的數(shù)量。不過(guò), 80286 仍然是 16 位 CPU ,因此線性地址空間仍然被限制在 64KB 。

1985 年的 80386 CPU 突破了這一限制。該芯片最終砍斷了 16 位尋址的鎖鏈,將線性地址空間推到了 4GB ,并在引入 32 位線性地址的同時(shí)保留了基本的選擇器 / 描述符架構(gòu)。幸運(yùn)的是, 80286 的描述符結(jié)構(gòu)中還有一些剩余的位可以拿來(lái)使用。從 16 位遷移到 32 位地址后, CPU 的數(shù)據(jù)寄存器的大小也相應(yīng)的增加了兩倍,并同時(shí)增加了一個(gè)新的強(qiáng)大的尋址模型。真正的 32 位的數(shù)據(jù)和地址為程序員帶了實(shí)際的便利。事實(shí)上,在微軟的 Windows 平臺(tái)真正完全支持 32 位模型是在好幾年之后。 Windows NT 的第一個(gè)版本在 1993 年 7 月 26 日發(fā)布,實(shí)現(xiàn)了真正意義上的 Win32 API 。但是 Windows 3.x 程序員仍然要處理由獨(dú)立的代碼和數(shù)據(jù)段構(gòu)成的 64KB 內(nèi)存片, Windows NT 提供了平坦的 4GB 地址空間,在那兒可以使用簡(jiǎn)單的 32 位指針來(lái)尋址所有的代碼和數(shù)據(jù),而不需要分段。在內(nèi)部,當(dāng)然,分段仍然在起作用,就像我在前面提及的那樣。不過(guò)管理段的所有責(zé)任都被移給了操作系統(tǒng)。

80386 的另一個(gè)新特性是在硬件上支持分頁(yè),確切的來(lái)說(shuō)是:請(qǐng)求式分頁(yè)的虛擬內(nèi)存。這種技術(shù)允許一個(gè)不同于 RAM 的存儲(chǔ)介質(zhì) ---- 硬盤來(lái)為內(nèi)存提供支持,例如,在允許分頁(yè)時(shí), CPU 通過(guò)將最近最少訪問(wèn)的內(nèi)存數(shù)據(jù)置換到備份存儲(chǔ)器中,從而為新的數(shù)據(jù)騰出空間,這樣就能訪問(wèn)比可用物理內(nèi)存更大的內(nèi)存空間。理論上來(lái)說(shuō),可以使用此種方式訪問(wèn) 4GB 的連續(xù)線性地址空間,提供的備份介質(zhì)必須足夠的大 --- 即 使只安裝了非常少的物理內(nèi)存。當(dāng)然,分頁(yè)并不是訪問(wèn)內(nèi)存的最快方式,最好還是能提供盡可能多的物理內(nèi)存。但是,這是處理大量數(shù)據(jù)的最好辦法,即使這些數(shù)據(jù) 超過(guò)了可用物理內(nèi)存。例如,圖形和數(shù)據(jù)庫(kù)程序都需要一大塊工作內(nèi)存,如果沒有分頁(yè)機(jī)制的話,其中的某些程序就無(wú)法在低檔的 PC 系統(tǒng)中運(yùn)行。

80386 分頁(yè)的模式是將內(nèi)存劃分為 4KB 或 4MB 大小的頁(yè)。操作系統(tǒng)的設(shè)計(jì)者可以在二者之間自由的選擇,也可混合使用這兩個(gè)大小的頁(yè)面。稍后,我會(huì)介紹 Windows 2000 采用的混合大小方案:由操作系統(tǒng)使用 4MB 的頁(yè)面,而 4KB 頁(yè)面由剩余的代碼和數(shù)據(jù)使用。這些頁(yè)面由分層結(jié)構(gòu)的頁(yè)表樹管理,該頁(yè)表樹記錄當(dāng)前位于物理內(nèi)存中的頁(yè),同時(shí)還記錄了每個(gè)頁(yè)是否實(shí)際的位于物理內(nèi)存中。如果指定頁(yè)已被置換到了硬盤上,而某些模塊觸及了位于這些頁(yè)中的地址, CPU 就會(huì)產(chǎn)生一個(gè)缺頁(yè)中斷(這與外圍硬件產(chǎn)生的中斷類似)。接下來(lái),位于操作系統(tǒng)內(nèi)核中的缺頁(yè)中斷處理例程會(huì)試圖將該頁(yè)再次調(diào)入物理內(nèi)存,這可能需要將另一塊內(nèi)存中的數(shù)據(jù)寫入硬盤以騰出空間。通常,系統(tǒng)采用最近最少( LRU )算法來(lái)確定哪個(gè)頁(yè)可以被置換出去?,F(xiàn)在可以很清楚地看到為什么有時(shí)將這個(gè)過(guò)程稱為 ---- 請(qǐng)求式分頁(yè)( demand paging ):即,由軟件提出請(qǐng)求,然后根據(jù)操作系統(tǒng)和應(yīng)用程序使用的內(nèi)存的統(tǒng)計(jì)數(shù)據(jù),將物理內(nèi)存中的數(shù)據(jù)移動(dòng)到后備存儲(chǔ)設(shè)備中。

由頁(yè)表提供的間接尋址方式蘊(yùn)含著很有趣的兩件事。第一,程序所使用的地址和 CPU 使用的物理地址總線上的地址之間并沒有預(yù)設(shè)的關(guān)系。如果你知道你的程序所使用的數(shù)據(jù)結(jié)構(gòu)位于某一地址,如, 0x00140000 ,你可能仍然不想知道任何有關(guān)這些數(shù)據(jù)的物理地址的信息,除非你要檢查頁(yè)表樹( page-table tree )。 這需要操作系統(tǒng)來(lái)決定這些地址之間的映射關(guān)系。甚至當(dāng)前有效的地址轉(zhuǎn)換都是無(wú)法預(yù)測(cè)的,部分的來(lái)看,這是分頁(yè)機(jī)制所固有的隨機(jī)性導(dǎo)致的。幸運(yùn)的是,在大多 數(shù)應(yīng)用程序中,并不需要有關(guān)物理地址的知識(shí)。不過(guò),對(duì)于開發(fā)硬件驅(qū)動(dòng)程序的人員來(lái)說(shuō)還是需要某些這方面的知識(shí)。分頁(yè)的另一個(gè)隱晦之處是:地址空間并不必須 是連續(xù)的。實(shí)際上,根據(jù)頁(yè)表的內(nèi)容, 4GB 的空間可以包含大量的“空洞”,這些“空洞”既沒有映射到物理內(nèi)存也沒有映射到后備存儲(chǔ)器中。如果一個(gè)應(yīng)用程序試圖讀取或?qū)懭脒@樣的一個(gè)地址,它將立即被系統(tǒng)中止掉。稍后,我會(huì)詳細(xì)的說(shuō)明 Windows 2000 是如何將可用內(nèi)存擴(kuò)展到 4GB 地址空間的。

80486 和 Pentium CPU 使用的分段和分頁(yè)機(jī)制與 80386 很相似,但一些特殊的尋址特性除外,如 Pentium Pro 采用的物理地址擴(kuò)展( Physical Address Extension, PAE )機(jī)制。隨同更高的時(shí)鐘頻率一起, Pentium CPU 的另一特性就是其采用的雙重指令流水線,這一特性允許它在同一時(shí)刻執(zhí)行兩個(gè)操作(只要這兩個(gè)指令不互相依賴)。例如,如果指令 A 修改一個(gè)寄存器的值,而與其相鄰的指令 B 需要這個(gè)修改后的值來(lái)進(jìn)行計(jì)算,在 A 完成之前, B 將無(wú)法執(zhí)行。但是如果指令 B 使用另一個(gè)寄存器, CPU 就可同時(shí)執(zhí)行這兩個(gè)指令。 Pentium 系列 CPU 采用的多種優(yōu)化方式為編譯器的優(yōu)化提供了廣闊的空間。如果你對(duì)這方面的話題很感興趣,請(qǐng)參考 Rick 的《 Inner Loops 》( Booth 1997 )。

在 i386 的內(nèi)存管理中,有三類地址非常有名,它們的術(shù)語(yǔ) --- 邏輯、線性和物理地址出現(xiàn)在 Intel 的系統(tǒng)編程手冊(cè)( Intel 1999c )。

1. 邏輯地址 :這是內(nèi)存地址的精確描述,通常表示為 16 進(jìn)制: xxxx:YYYYYYYY ,這里 xxxx 為 selector ,而 YYYYYYYY 是針對(duì) selector 所選擇的段地址的線性偏移量。除了指定 xxxx 的具體數(shù)值外,還可使用具體的段寄存器的名字來(lái)替代之,如 CS (代碼段), DS (數(shù)據(jù)段), ES (擴(kuò)展段), FS (附加數(shù)據(jù)段 #1 ), GS (附加數(shù)據(jù)段 #2 )和 SS (堆棧段)。這些符號(hào)都來(lái)自舊的“段 : 偏移量”風(fēng)格,在 8086 實(shí)模式下使用此種方式來(lái)指定“ far pointers ”(遠(yuǎn)指針)。

2. 線性地址 :大多數(shù)應(yīng)用程序和內(nèi)核驅(qū)動(dòng)程序都忽略虛擬地址。它們只對(duì)虛擬地址的偏移量部分感興趣,而這一部分通常稱為線性地址。此種類型的地址假定了一種默認(rèn)的分段模型,這種模型由 CPU 的當(dāng)前段寄存器確定。 Windows 2000 使用 flat segmentation (平滑段),此時(shí) CS 、 DS 、 ES 和 SS 寄存器都指向相同的線性地址空間;因此,程序可以認(rèn)為所有的代碼、數(shù)據(jù)和堆棧指針都可安全的相互轉(zhuǎn)化。例如,在任何時(shí)候,堆棧中的一個(gè)地址都可以轉(zhuǎn)化為一個(gè)數(shù)據(jù)指針,而不需要關(guān)心相應(yīng)段寄存器的值。

3. 物理地址 :僅當(dāng) CPU 工作于分頁(yè)模式時(shí),此種類型的地址才會(huì)變得非常“有趣”。本質(zhì)上,一個(gè)物理地址是 CPU 插腳上可測(cè)量的電壓。操作系統(tǒng)通過(guò)設(shè)立頁(yè)表將線性地址映射為物理地址。 Windows 2000 所用頁(yè)表的布局的某些屬性,對(duì)于調(diào)試軟件開發(fā)人員非常有用,本章稍后將討論之。

虛擬地址和線性地址的差別多少有些人為的痕跡,在一些文檔中會(huì)交替的使用這兩個(gè)詞。我會(huì)盡力保證使用這一術(shù)語(yǔ)的一致性。特別需要注意的是, Windows 2000 假定物理地址有 64 位寬。而 Intel i386 系統(tǒng)通常只有一個(gè) 32 位的地址總線。不過(guò),某些 Pentium 系統(tǒng)支持大于 4GB 的物理內(nèi)存。例如,使用 PAE 模式的 Pentium Pro CPU ,這種 CPU 可以將物理地址擴(kuò)展到 36 位,這樣就可訪問(wèn)多大 64GB 的物理內(nèi)存( Intel 1999c )。因此, Windows 2000 的 API 函數(shù)通常使用數(shù)據(jù)類型 PHYSICAL_ADDRESS 來(lái)表示物理地址, PHYSICAL_ADDRESS 實(shí)際是 LARGE_INTEGER 結(jié)構(gòu)的別名,如 列表 4-1 所示。這兩種類型都定義在 DDK 頭文件 ntdef.h 中。 LARGE_INTEGER 實(shí)際上是 64 位有符號(hào)整數(shù)的結(jié)構(gòu)化表示,它可以被解釋為一對(duì) 32 位數(shù)( LowPart 和 HighPart )或一個(gè)完整的 64 位數(shù)( QuadPart )。 LONGLONG 類型等價(jià)于 Visual C/C++ 的原生類型 __int64 ,該類型的無(wú)符號(hào)表示叫做 ULONGLONG 或 DWordLONG ,它們都依賴基本的無(wú)符號(hào)類型 __int64 。

圖 4-1 給出了 i386 內(nèi)存的分段模型,同時(shí)說(shuō)明了邏輯地址和線性地址的關(guān)系。為了更清晰些,我將描述符表( descriptor table )和段( segment )畫的比較小。實(shí)際上, 32 位的操作系統(tǒng)通常采用 4-2 所示的分段方案,這就是所謂的平滑內(nèi)存模型( flat memory model ),它采用一個(gè) 4GB 大小的段。這種方案的不足是,描述符表變成了段的一部分,從而可以被有足夠權(quán)限的代碼訪問(wèn)到。

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

typedef union _LARGE_INTEGER

{

struct

{

ULONG LowPart;

LONG HighPart;

};

LONGLONG QuadPart;

} LARGE_INTEGER, *PLARGE_INTEGER;

列表 4-1. PHYSICAL_ADDRESS 和 LARGE_INTEGER 結(jié)構(gòu)的定義

圖 4-1. i386 的內(nèi)存分段

圖 4-2 給出的內(nèi)存模型被 Windows 2000 作為標(biāo)準(zhǔn)的代碼、數(shù)據(jù)和堆棧段,這意味著,所有的邏輯地址將包括 CS 、 DS 、 ES 和 SS 段寄存器。 FS 和 GS 的處理方式有所不同。 Windows 2000 并不使用 GS 寄存器,而 FS 寄存器被專門用來(lái)保存位于線性地址空間中的系統(tǒng)數(shù)據(jù)區(qū)域的基地址。因此, FS 的基地址遠(yuǎn)大于 0 ,其大小不會(huì)超過(guò) 4GB 。有趣的是, Windows 2000 為用戶模式和內(nèi)核模式分別維護(hù)兩個(gè)不同的 FS 段。稍后我們將詳細(xì)討論這一問(wèn)題。

圖 4-2. 平滑的 4GB 內(nèi)存段

4-1 4-2 中,邏輯地址的 selector 指向描述符表,該描述符表由名為 GDTR 的寄存器指定。這是 CPU 的全局描述符表寄存器,該寄存器可由操作系統(tǒng)設(shè)置為任何適當(dāng)?shù)木€性地址。 GDT (全局描述符表)的第一項(xiàng)是保留的,該項(xiàng)對(duì)應(yīng)的 selector 叫做“ null segment selector ”。 Windows 2000 將其 GDT 保存在 0x80036000 。 GDT 可容納多達(dá) 8,19264 位的條目,即其最大值為 64KB 。 Windows 2000 僅使用開始的 128 個(gè)項(xiàng),并將 GDT 的大小限制為 1,024 字節(jié)。隨 GDT 一起, i386 CPU 還提供了一個(gè)本地描述符表( Local Descriptor Table , LDT )和一個(gè)中斷描述符表( Interrupt Descriptor Table , IDT ),這兩個(gè)表的起始地址分別保存在 LDTR 和 IDTR 這兩個(gè)寄存器中。 GDTR 和 IDTR 的值是唯一的, CPU 執(zhí)行的每個(gè)任務(wù)都采用相同的值,而 LDTR 的值則是任務(wù)相關(guān)的, LDTR 可容納一個(gè) 16 位的 selector 。

圖 4-3 示范了復(fù)雜的線性地址與物理地址的轉(zhuǎn)換機(jī)制,如果在 4KB 分頁(yè)模式下,并允許請(qǐng)求式分頁(yè), i386 的內(nèi)存管理單元就會(huì)采用此種轉(zhuǎn)換機(jī)制。圖中左上角的頁(yè)目錄基址寄存器( Page-Directory Base Register , PDBR )包含頁(yè)目錄的物理地址。 PDBR 由 i386 的 CR3 寄存器保存。僅用該寄存器的高 20 位來(lái)尋址。因此,頁(yè)目錄也是以頁(yè)為邊界的。 PDBR 的剩余位作為標(biāo)志位或保留以便將來(lái)擴(kuò)展使用。頁(yè)目錄占用一個(gè)完整的 4KB 頁(yè),由包含 1024 個(gè)頁(yè)目錄項(xiàng)( Page-Directory Entry )的數(shù)組構(gòu)成,每個(gè)頁(yè)目錄項(xiàng)均為 32 位。和 PDBR 類似,每個(gè) PDE 被劃分為一個(gè) 20 位的頁(yè)幀計(jì)數(shù)器( Page-Frame Number , PFN )和一個(gè)標(biāo)志數(shù)組。 PFN 用來(lái)尋址頁(yè)表。每個(gè)頁(yè)表都是按頁(yè)對(duì)齊的,包含 1024 個(gè)頁(yè)表項(xiàng)( Page-Table Entry , PTE )。每個(gè) PTE 的高 20 位作為一個(gè)指針指向一個(gè) 4KB 的數(shù)據(jù)頁(yè)。通過(guò)將線性地址分為三段來(lái)實(shí)現(xiàn)地址轉(zhuǎn)換:高 10 位用來(lái)選擇一個(gè) PDE (屬于頁(yè)目錄),接下來(lái)的 10 個(gè)位選擇前面所選的 PDE 中的某個(gè) PTE ,最后剩下的 12 個(gè)位用來(lái)指定在數(shù)據(jù)頁(yè)中的偏移量,該數(shù)據(jù)頁(yè)由前面所選的 PTE 確定。

圖 4-3. 兩層間接模型(采用 4KB 頁(yè))

在 4MB 分頁(yè)模式下,事情就變得很簡(jiǎn)單了,這是因?yàn)橄艘粋€(gè)間接層,如 4-4 所示。此時(shí), PDBR 仍然指向頁(yè)目錄,但僅使用了每個(gè) PDE 的高 10 位,這是因?yàn)槟繕?biāo)地址采用 4MB 對(duì)齊。因?yàn)闆]有使用頁(yè)表,這個(gè)地址同樣也是 4MB 數(shù)據(jù)頁(yè)的基地址。所以,此時(shí)的線性地址只包含兩個(gè)部分: 10 個(gè)位用來(lái)選擇 PDE ,其余的 22 位作為偏移量。 4MB 內(nèi)存方案的開銷沒有 4KB 那么大,這是因?yàn)閮H頁(yè)目錄需要附加的內(nèi)存。這 1024 個(gè) PDE 中的每個(gè)都可尋址一個(gè) 4MB 頁(yè)。這足夠覆蓋整個(gè) 4GB 地址空間了。所以, 4MB 分頁(yè)的優(yōu)勢(shì)就是可以降低內(nèi)存管理的開銷,但結(jié)果就是尋址粒度較大。

4KB 和 4MB 分頁(yè)模型各有優(yōu)缺點(diǎn)。幸運(yùn)的是,操作系統(tǒng)的設(shè)計(jì)人員不必非要在二者之中選擇一個(gè),可以混合使用這兩種模型。例如, Windows 2000 在內(nèi)存范圍 0x80000000 --- 0x9FFFFFFF 使用 4MB 大小的頁(yè),內(nèi)核模塊 hal.dll 和 ntoskrnl.exe 均被加載到該地址范圍內(nèi)。剩余的線性地址采用 4KB 頁(yè)來(lái)管理。 Intel 大力推薦采用這種混合設(shè)計(jì),以改進(jìn)系統(tǒng)性能,這也因?yàn)?4KB 和 4MB 的頁(yè)項(xiàng)( Page Entry )都會(huì)被高速緩存到不同的轉(zhuǎn)換后備緩沖區(qū)( Translation Lookaside Buffers , TLBs )中,該 TLB 位于 i386 CPU 內(nèi)部( Intel 1999c , pp.3-22f )。操作系統(tǒng)的內(nèi)核通常比較大,而且需要常駐內(nèi)存,因此,如果將它們保存在多個(gè) 4KB 頁(yè)中將會(huì)永久性的耗盡寶貴的 TLB 空間。

圖 4-4. 一層間接模型(采用 4MB 頁(yè))

注意,地址轉(zhuǎn)換的所有步驟都在物理內(nèi)存中進(jìn)行。 PDBR 和所有的 PDE 、 PTE 包含的都是物理地址指針。在 4-3 4-4 中可找到的線性地址位于左下角,該線性地址將轉(zhuǎn)化為物理頁(yè)中的偏移量。另一方面,應(yīng)用程序卻必須使用線性地址,它們對(duì)物理地址一無(wú)所知。不過(guò),通過(guò)將頁(yè)目錄和其下屬的所有頁(yè)表映射到線性地址空間可以填補(bǔ)這一不足。在 Windows 2000 和 Windows NT 4.0 中,在線性地址范圍 0xC0000000----0xC03FFFFF 可訪問(wèn)所有的 PDE 和 PTE ,這是一個(gè)采用 4MB 頁(yè)的線性內(nèi)存區(qū)域??梢院?jiǎn)單的通過(guò)線性地址的高 20 位來(lái)查找與其相關(guān)聯(lián)的 PTE ,這個(gè)高 20 位作為 32 位 PTE 數(shù)組的索引, PTE 數(shù)組起始于 0xC0000000 。例如,地址 0x00000000 表示的 PTE 位于 0xC0000000 。假定有一線性地址 0x80000000 ,通過(guò)將該地址右移 12 位,可得到 0x80000 (即該地址的高 20 位),因?yàn)槊總€(gè) PTE 占用 4 個(gè)字節(jié),所以目標(biāo) PTE 的地址為: 0xC0000000+ ( 4*0x80000 ) =0xC0200000 。這樣的結(jié)果看起來(lái)很有趣,線性地址將 4GB 地址空間劃分為相等的兩部分,又映射為一個(gè) PTE 的地址,從而將 PTE 數(shù)組也劃分為了相等的兩部分。

現(xiàn)在,讓我們更進(jìn)一步,通過(guò) PTE 自身來(lái)計(jì)算數(shù)據(jù)項(xiàng)在 PTE 數(shù)組中的地址。常規(guī)的映射公式為:(( LinearAddress >> 12 ) *4 ) +0xC0000000 。 LinearAddress 取值范圍為: 0xC0000000----0xC0300000 。位于線性地址 0xC0300000 的數(shù)據(jù)項(xiàng)指向 PTE 數(shù)組在物理內(nèi)存中的起始位置。現(xiàn)在回去看一下 4-3 ,開始于地址 0xC0300000 的 1024 個(gè)數(shù)據(jù)項(xiàng)肯定是頁(yè)目錄!這種特殊的 PDE 、 PTE 排列方式被多個(gè)內(nèi)存管理函數(shù)使用,這些函數(shù)由 ntoskrnl.exe 導(dǎo)出。例如,有文檔記載的 API 函數(shù) MmIsAddressValid() 和 MmGetPhysicalAddress() 使用 32 位的線性地址來(lái)查找其 PDE ,如可用,還會(huì)查找其 PTE ,并會(huì)檢查它們的內(nèi)容。 MmIsAddressValid() 簡(jiǎn)單的檢驗(yàn)?zāi)繕?biāo)頁(yè)是否位于物理內(nèi)存中。如果測(cè)試失敗,就意味著線性地址或者無(wú)效或者該地址引用的頁(yè)已經(jīng)被置換到了后備存儲(chǔ)器(由系統(tǒng)頁(yè)面文件集表示)中。 MmGetPhysicalAddress() 首先從線性地址中提取相應(yīng)的頁(yè)幀計(jì)數(shù)器( PFN ),該 PFN 就是與其相關(guān)的物理內(nèi)存頁(yè)(該頁(yè)將按照頁(yè)大小進(jìn)行劃分)的基地址。接下來(lái),它通過(guò)線性地址中剩余的 12 個(gè)位,來(lái)計(jì)算在物理頁(yè)中的偏移量,最后將 PFN 指出的物理頁(yè)基地址和前面算出的偏移量相加即可得到該線性地址對(duì)應(yīng)的物理地址。

更徹底的檢查 MmGetPhysicalAddress() 的實(shí)現(xiàn)方式,會(huì)發(fā)現(xiàn) Windows 2000 內(nèi)存布局的另一個(gè)有趣的特性。 MmGetPhysicalAddress() 函數(shù)在開始之前,首先測(cè)試線性地址是否位于 0x80000000-----0x9FFFFFFF 。就像前面提到的,這里存放著 hal.dll 和 ntoskrnl.exe ,而且這也是 Windows 2000 使用 4MB 頁(yè)的地址塊。這個(gè)有趣的特性是,如果給定的線性地址位于這一范圍, MmGetPhysicalAddress() 將不會(huì)關(guān)心所有的 PDE 或 PTE 。替代的是,該函數(shù)簡(jiǎn)單的將線性地址的高 3 位設(shè)為零,然后加上字節(jié)偏移量,最后將得到地址作為物理地址返回。這意味著,物理地址范圍: 0x00000000----0x1FFFFFFF 將按照 1 : 1 的比例映射到線性地址 0x80000000----0x9FFFFFFF !要知道 ntoskrnl.exe 總是被加載到線性地址 0x80400000 ,這意味著 Windows 2000 的內(nèi)核總位于物理地址 0x00400000 ,這種情況發(fā)生在第二個(gè) 4MB 頁(yè)的基地址位于物理內(nèi)存中。事實(shí)上,通過(guò)檢查這些內(nèi)存區(qū)域可以證明上面的假定是正確的。本章提供的 Memory SPY 將使你有機(jī)會(huì)看到這一點(diǎn)。

補(bǔ)充:

這部分內(nèi)容選擇自《 Windows 環(huán)境下 32 位匯編語(yǔ)言程序設(shè)計(jì)》

x86 的內(nèi)存分頁(yè)機(jī)制

當(dāng) x86 CPU 工作在保護(hù)模式和虛擬 8086 模式時(shí),可以使用全部 32 根地址線訪問(wèn) 4GB 的內(nèi)存。因?yàn)?80386 的所有通用寄存器都是 32 位的,所以用任何一個(gè)通用寄存器來(lái)間接尋址,不必分段就可以訪問(wèn)到 4GB 的內(nèi)存地址。

但 這并不意味著,此時(shí)段寄存器就不再有用了。實(shí)際上,段寄存器更加有用了,雖然在尋址上沒有分段的限制了,但在保護(hù)模式下,一個(gè)地址空間是否可以被寫入,可 以被多少優(yōu)先級(jí)的代碼寫入,是不是允許執(zhí)行等等涉及保護(hù)的問(wèn)題就出來(lái)了。要解決這些問(wèn)題,必須對(duì)一個(gè)地址空間定義一些安全上的屬性。段寄存器這時(shí)就派上了 用場(chǎng)。但是設(shè)計(jì)屬性和保護(hù)模式下段的其他參數(shù),要表示的信息太多了,要用 64 位長(zhǎng)的數(shù)據(jù)才能表示。我們把這 64 位的屬性數(shù)據(jù)叫做段描述符( Segment Descriptor )。

80386 的段寄存器是 16 位的,無(wú)法放下保護(hù)模式下 64 位的段描述符。如何解決這個(gè)問(wèn)題呢?方法是把所有段的段描述符順序存放在內(nèi)存中的指定位置,組成一個(gè)段描述符表( Descriptor Table );而段寄存器中的 16 位用來(lái)做索引信息,指定這個(gè)段的屬性用段描述符表中的第幾個(gè)描述符來(lái)表示。這時(shí),段寄存器中的信息不再是段地址了,而是段選擇器( Segment Selector )??梢酝ㄟ^(guò)它在段描述符表中“選擇”一個(gè)項(xiàng)目已得到段的全部信息。

那么段描述符表存放在哪里呢? 80386 引入了兩個(gè)新的寄存器來(lái)管理段描述符表。一個(gè)是 48 位的全局描述符表寄存器 GDTR ,一個(gè)是 16 位的局部描述符表寄存器 LDTR 。那么,為什么有兩個(gè)描述符表寄存器呢?

GDTR 指向的描述符表為全局描述符表 GDT ( Global Descriptor Table )。它包含系統(tǒng)中所有任務(wù)都可用的段描述符,通常包含描述操作系統(tǒng)所使用的代碼段、數(shù)據(jù)段和堆棧段的描述符及各任務(wù)的 LDT 段等。全局描述符表只有一個(gè)。

LDTR 指向局部描述符表 LDT ( Local Descriptor Table )。 80386 處理器設(shè)計(jì)成每個(gè)任務(wù)都有一個(gè)獨(dú)立的 LDT 。它包含每個(gè)任務(wù)私有的代碼段、數(shù)據(jù)段和堆棧段的描述符,也包含該任務(wù)所使用的一些門描述符,如任務(wù)門和調(diào)用門描述符等。

不同任務(wù)的局部描述符分別組成不同的內(nèi)存段,描述這些內(nèi)存段的描述符當(dāng)作系統(tǒng)描述符放在全局描述符表中。和 GDTR 直接指向內(nèi)存地址不同, LDTR 和 CS 、 DS 等段選擇器一樣只存放索引值,指向局部描述符內(nèi)存段對(duì)應(yīng)的描述符在全局描述符表中的位置。隨著任務(wù)的切換,只要改變 LDTR 的值,系統(tǒng)當(dāng)前的局部描述符表 LDT 也隨之切換,這樣便于個(gè)任務(wù)之間數(shù)據(jù)的隔離。但 GDT 并不隨著任務(wù)的切換而切換。

16 位的段選擇器如何使用全局描述符表和局部描述符表這兩個(gè)表呢?實(shí)際上,段選擇器中只有高 13 位表示索引值。剩下的 3 個(gè)數(shù)據(jù)位中,第 0 , 1 位表示程序的當(dāng)前優(yōu)先級(jí) RPL ;第 2 位 TI 位用來(lái)表示在段描述符的位置; TI=0 表示在 GDT 中, TI=1 表示在 LDT 中。

80386 處理器把 4KB 大小的一塊內(nèi)存當(dāng)作一“頁(yè)”內(nèi)存,每頁(yè)物理內(nèi)存可以根據(jù)“頁(yè)目錄”和“頁(yè)表”,隨意映射到不同的線性地址上。這樣,就可以將物理地址不連續(xù)的內(nèi)存的映射連到一起,在線性地址上視為連續(xù)。在 80386 處理器中,除了與 CR3 (保存當(dāng)前頁(yè)目錄的地址)相關(guān)的指令使用的是物理地址外,其他所有指令都是使用線性地址尋址的。

是否啟用內(nèi)存分頁(yè)機(jī)制是由 80386 處理器新增的 CR0 寄存器中的位 31 ( PG 位)決定的。如果 PG=0 ,則分頁(yè)機(jī)制不啟用,這時(shí)所有指令尋址的地址(線性地址)就是系統(tǒng)中實(shí)際的物理地址;當(dāng) PG=1 的時(shí)候, 80386 處理器進(jìn)入內(nèi)存分頁(yè)管理模式,所有的線性地址要經(jīng)過(guò)頁(yè)表的映射才得到最后的物理地址。

標(biāo)簽: Windows系統(tǒng)
主站蜘蛛池模板: 本道久久综合88全国最大色 | 亚洲网美女 | 欧美日韩亚洲一区二区三区在线观看 | 成人黄网大全在线观看 | 国产一区二区fc2ppv在线播放 | 99热在线观看 | 99视频国产热精品视频 | 亚州视频一区二区 | 日韩永久在线观看免费视频 | 国产精品久久久久久影院 | 在线播放一区二区三区 | 在线精品国产成人综合第一页 | 国产三级精品最新在线 | 中文字幕在线观看不卡视频 | 国产情侣久久 | 欧美一级毛片不卡免费观看 | 黄色国产网站 | 中文字幕亚洲一区 | 国产一级片观看 | 国产网站在线 | 国产三香港三韩国三级不卡 | 欧美精品18videos性欧美 | 久久精品免费视频观看 | 自拍在线| 日韩日韩日韩手机看片自拍 | 国产成人免费高清激情视频 | 特黄特色一级特色大片中文 | 日韩高清欧美 | 美女综合网 | 欧美一级专区免费大片 | 日韩视频在线观看 | 久久精品亚洲一区二区 | 亚洲黄网址 | 亚洲精品久久九九热 | 亚洲精品国产精品国自产 | 国产福利精品在线观看 | 亚洲第一网站免费视频 | 综合网自拍 | 免费萌白酱国产一区二区三区 | aaa一级毛片 | 女人张开腿给人桶免费视频 |