01-linux內(nèi)存管理之二在x86上的虛擬內(nèi)存_第1頁
01-linux內(nèi)存管理之二在x86上的虛擬內(nèi)存_第2頁
免費預(yù)覽已結(jié)束,剩余1頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、nLinux 內(nèi)存管理之二:Linux 在 X86 上的虛擬內(nèi)存管理本文檔來自網(wǎng)絡(luò),并稍有改動。前言Linux 支持很多硬件運行,常用的有: el X86,Alpha,Sparc 等。對于不能夠通用的一些功能,Linux 必須依據(jù)硬件的特點來具體實現(xiàn)。本文的目的是簡要探討 Linux在 X86 保護模式上如何實現(xiàn)虛擬內(nèi)存管理功能。為簡化和方便敘述,本如下限定:X86處理器為 80486 和其后的處理器,X86 工作在保護模式,不采用物理內(nèi)存擴展(使用 32bits物理地址),不使用擴展頁(頁大小為 4K)。凡是與限定模式無關(guān)的內(nèi)容,本文都盡量略過。 Linux 的虛擬內(nèi)存管理中與硬件無關(guān)的內(nèi)容

2、在本文中也被略過。本文所援引的 Linux 內(nèi)核源代碼版本為 Linux 2.2.5。X86 的分段和分頁機制I. X86 的分段機制和相應(yīng)系統(tǒng)結(jié)構(gòu)X86 的分段機制就是將X86 的線性地址空間分成許多小空間-段(segment),利用這些(段的作用和)代碼和數(shù)據(jù),通過對段的保護來提供一種對數(shù)據(jù)或代碼的保護。根據(jù)每個內(nèi)容的不同,X86 將段分為三類進程段(代碼段、數(shù)據(jù)段和堆棧段)和兩類系統(tǒng)段:任務(wù)狀態(tài)段(TSS,Task-Se Segment)和 LDT 段(由于 GDT 不是通過段描述符和段選擇符來,所以 X86 沒有認為存在一個 GDT 段;同理,也不存在 IDT 段)。在分段機制,X86

3、 使用了如下幾種主要數(shù)據(jù)結(jié)構(gòu):全局描述符表(GDT,Global Describtor Table):存放系統(tǒng)用的段描述符和各項任務(wù)共用的段描述符,可以是上述的任何一類段的段描述符,最大表長 64KB;局部描述符表(LDT,Local Describtor Table):存放某個任務(wù)的各段的段描述符,只能是三類進程段的段描述符和調(diào)用門描述符,最大表長 4GB; 段描述符(Segment Describtor):64bits,地址),該段的類型,對該段操作的限制;一個段的址(該地址是線性 門描述符(Gate Describtor):64bits,一種特殊的描述符,為處于不同級的系統(tǒng)調(diào)用或程序的調(diào)

4、用或提供保護;分為四類:調(diào)用門描述符(Call Gate Describtor)、中斷門描述符( errupt Gate Describtor)、陷阱門描述符(Trap Gate Describtor)、任務(wù)門描述符(Task Gate Describtor);段選擇符(Segment Selector):16bits,用于在 GDT 或 LDT 中索引相應(yīng)的段描述符;中斷描述表(IDT, errupt Describer Table):存放門描述符,只能是中斷門描述符,陷阱門描述符和任務(wù)門描述符,最大表長 64KB;同時,X86 提供了如下幾個用于支持分段機制的寄存器: 全局描述符表寄存器(

5、GDTR,GDT Register):48bits,32bits 為 GDT 的址(線性地址),16bits 為 GDT 的表長;GDTR 的初始值為:址 0,表長 0 xF; 局部描述符表寄存器(LDTR,LDT Register):80bits,16bits 為 LDT 段選擇符,64bits為該 LDT 段的段描述符; 中斷描述符表寄存器(IDTR,IDT Register):48bits,32bits 為 IDT 的址(線性地址),16bits 為 IDT 的表長;IDTR 的初始值為:址 0,表長 0 xF;任務(wù)寄存器(TR,Task Register):80bits,16bits

6、為任務(wù)狀態(tài)段選擇符,64bits 為該任務(wù)狀態(tài)段的段描述符;六個段寄存器(Segment Register):分為可見部分和隱藏部分,可見部分為段選擇符,隱藏部分為段描述符;六個段寄存器分別為 CS、SS、DS、ES、FS、GS;關(guān)于這些段寄存器的作用參見1中 3.4.2 Segment Register;86 工作在保護模式時,進程使用的 48bits 邏輯地址(Logical address)。邏輯地址的高16bits 為段選擇符,低 32bits 是段內(nèi)的偏移量。通過段選擇符在 GDT 或 LDT 中索引相應(yīng)的段描述符(得到該段的址),再加上偏移量得到邏輯地址對應(yīng)的線性地址( Linea

7、rAddress)。如果沒有采用分葉管理,線性地址是直接物理地址(Physical Address),于是可以直接用線性地址理地址。內(nèi)存;否則,還要通過 X86 的分頁轉(zhuǎn)換,將線性地址轉(zhuǎn)換為物以上是對 X86 分段相關(guān)內(nèi)容的簡要描述,對于各數(shù)據(jù)結(jié)構(gòu)、寄存器的細節(jié)和邏輯地址轉(zhuǎn)換為線性地址的細節(jié),請查閱 1。II. X86 的分頁機制和相應(yīng)系統(tǒng)結(jié)構(gòu)32bits 的線性地址空間可以直接到物理地址空間,也可以間接到許多小塊的物空間)上。這種間接方式就是分頁機制。X86 可用頁大小為 4KB、理空間(磁盤2MB 和 4MB(2MB 和 4MB 只能在 Pentium 和 Pentium Pro 處理器中

8、使用,本文中限定采用4KB 頁)。在分頁機制,X86 使用了四種數(shù)據(jù)結(jié)構(gòu): 頁目錄項(PDE,Page Directory Entry):32bits 結(jié)構(gòu),高 20bits 為頁表址(物理地址),以 4KB 為遞增,低 12bits 為頁表屬性,具體換算參見后面初始化部分; 頁目錄(Page directory):頁目錄項,位于一頁中,總共可容納 1024 個頁目錄項; 頁表項(PTE,Page Table Entry):32bits 結(jié)構(gòu),高 20bits 為頁低 12bits 為頁屬性;址(物理地址), 頁表(Page table):頁表項,位于一頁中,總共可容納 1024 個頁表項;頁

9、(Page):4KB 的連續(xù)地址空間;為了實現(xiàn)分頁機制和提高地址轉(zhuǎn)換的效率,X86 提供和使用了如下的硬件結(jié)構(gòu):頁標志位(PG,Page):該標志位為 1,說明采用頁機制;實際就是控制寄存器 CR0的第 31bit; 頁緩存/快表(TLBs,Translation Lookaside Buffers):以提高地址轉(zhuǎn)換的效率;最近使用的 PDE 和 PTE, 頁目錄址寄存器(PDBR,Page Directory Base Register):用于頁目錄的基地址(物理地址),實際就是控制寄存器 CR3;為了實現(xiàn)將線性地址到物理地址,X86 將 32bits 線性地址解釋為三部分:第 31bit到

10、第 22bit 為頁目錄中的偏移,用于索引頁目錄項(得到對應(yīng)頁表的址);第 21bit 到第12bit 為頁表中的偏移,用于索引頁表項(得到對應(yīng)頁的址);第 11bit 到第 0bit 為頁中的偏移。這樣,通過兩級索引和頁中的偏移量,最后能正確得到線性地址對應(yīng)的物理地址。關(guān)于分頁機制的詳細描述和作用,請查閱參考文檔1。LINUX 的分段策略Linux 在 X86 上采用最低限度的分段機制,其目的是為了避開復(fù)雜的分段機制,提高Linux 在其他不支持分段機制的硬件的可移植性,同時又充分利用 X86 的分段機制來隔離用戶代碼和內(nèi)核代碼。因此,在 Linux 上,邏輯地址和線性地址具有相同的值。由于

11、 X86 的 GDT 最大表長為 64KB,每個段描述符為 8B,所以 GDT 最多能夠容納 8192個段描述符。每產(chǎn)生一個進程,Linux 為該進程在 GDT 中創(chuàng)建兩個描述符:LDT 段描述符和 TSS 描述符,除去 Linux 在 GDT 中保留的前 12 項,GDT 實際最多能容納 4090 個進程。Linux 的內(nèi)核自身有獨立的代碼段和數(shù)據(jù)段,其對應(yīng)的段描述符分別在 GDT 中的第 2項和第 3 項。每個進程也有獨立的代碼段和數(shù)據(jù)段,對應(yīng)的段描述符中。有關(guān) LinuxGDT 表項和 DLT 表項分布情況參見附表 1,附表 2 所示。在它自己的 LDT在 Linux 中,每個用戶進程都

12、可以4GB 的線性地址空間。其中 0 x00 xBF的 3GB 空間為用戶態(tài)空間,用戶態(tài)進程可以直接。從 0 xC00000000 x3F 的 1GB。當用戶進程通級 3 切換到空間為內(nèi)核態(tài)空間,存放內(nèi)核的代碼和數(shù)據(jù),用戶態(tài)進程不能直接過中斷或系統(tǒng)調(diào)用內(nèi)核態(tài)空間時,會觸發(fā) X86 的級 0),即從用戶態(tài)切換到內(nèi)核態(tài)。級轉(zhuǎn)換(從LINUX 的分頁策略標準 Linux 的分頁是三級頁表結(jié)構(gòu),除了 X86 支持的頁目錄和頁,還有一級被稱為中間頁目錄。因此,線性地址在轉(zhuǎn)換為物理地址的過程中,線性地址就被解釋為四個部分(不是 X86 所認識的三個部分),增加了頁中間目錄中的索引。當運行在 X86上時,L

13、inux通過將中間頁目錄最大的頁目錄項個數(shù)定義為 1,并提供一組相關(guān)的宏(這些宏將中間頁目錄用頁目錄來替換)將三級頁面結(jié)構(gòu)分解過程完美的轉(zhuǎn)換為 X86 使用的二級頁面分解。這樣,無需改動內(nèi)核中頁面解釋的主要代碼(這些代碼都是認為線性地址由四個部分組成)。關(guān)于這些宏定義參見Linux 源碼/include/asm/pgtable.h,/include/asm/page.h。內(nèi)核態(tài)虛擬空間從 3GB 到 3GB+4MB 的一段(對應(yīng)進程頁目錄第 768 項指引的頁表),被到物理地址 0 x00 x3FF(4MB)。因此,進程處于內(nèi)核態(tài)時,只要通過3GB到 3GB+4MB 就可物理內(nèi)存的低 4MB

14、空間。所有進程從 3GB 到 4GB 的線性空間都是一樣的,由同樣的頁目錄項,同樣的頁表,到相同的物理內(nèi)存段。Linux 以這種方式讓內(nèi)核態(tài)進程共享代碼和數(shù)據(jù)。Linux 分段分頁初始化無論 Linux 系統(tǒng)如何被引導(dǎo),經(jīng)過 zImage(參見 arch/i386/boot/bootsect.s)或經(jīng)過 LILO,最后都會跳轉(zhuǎn)執(zhí)行arch/i386/boot/setup.s(被裝載到 SETUPSEG,物理地址 0 x90200),setup.s從 BIOS 中獲取計算機系統(tǒng)的硬件參數(shù)(如硬盤參數(shù)),放到內(nèi)存參數(shù)區(qū)(臨時寄放),同時做一些初步的狀態(tài)檢查,為進入保護模式做準備。關(guān)于引導(dǎo)過程和 s

15、etup.s 的具體執(zhí)行參見 2。保護模式下的內(nèi)核初始化模塊從物理地址 0 x100000 開始執(zhí)行,該地址開始的代碼和數(shù)據(jù)結(jié)構(gòu)都對應(yīng)在 arch/i386/kernel/head.s 中,參見附表 3。初始化模塊主要功能是對相關(guān)寄存器 IDT,GDT,頁目錄及頁表等進行初始化。下面,忽略 head.s 執(zhí)行流程的細節(jié),概要闡述 head.s 主要的初始化功能。1. 部分寄存器的初始化:將段寄存器 DS、ES、GS 和 FS 用 KERNEL_DS(0 x18, include/asm-i386/segment.h)來初始化(通過前面對段寄存器的描述和段選擇符的介紹可知道,其作用是將定位到 G

16、DT 中的第三項(內(nèi)核數(shù)據(jù)段),并設(shè)置對該段的操作特限級為 0);置位 CR0 的 PG 位,并根據(jù) CPU 的型號選擇置位 AM, WP, NE 和 MP;用 0 x101000 初始化 CR3(頁目錄 swapper_pg_dir 的地址);置 ESP 高 32bits 為 KERNEL_DS(0 x18),低32bits 為 init_user_stack;LDTR 初始化為 0。2. 有關(guān) IDT 的初始化:這只是臨時初始化 IDT,進一步的操作在 start_kernel 中進行;用于表示 IDT 的變量(idt_table )在 arch/i386/kenel/traps.c 中定

17、義,變量類型(desc_struct)定義在 include/asm-i386/desc.h。IDT 共有 IDT_ENTRIES(256)個中斷描述符,屬性字均為0 x8E00,每個中斷描述符都指向同一個中斷服務(wù)程序 ignore_init。Ignore_的功能僅僅是輸出消息_msg(unknownerrupt)。而 IDTR 的值為通過命令 lidt idt_descr 實現(xiàn)。通過在 head.s 中查看 idt_descr 的值可以計算得知,IDT 的IDT_ENTRIES*8-1(0 x7FF)。址為 idt_table 的地址,表長3. 有關(guān) GDT 的初始化:GDT 共有 GDT_

18、ENTRIES 個段描述符。GDT_ENTRIES 的計算公式為:12+2*NR_TASKS。其中 12 表示前面提到的 Linux 在 GDT 中保留的 12 項, NR_TASKS(512)指系統(tǒng)設(shè)定容納的進程數(shù),定義在 include/linux/tasks.h。GDT 在 head.s直接分配單元(標號為 gdt_table)。初始化后的 GDT 如附表 1 所示。GDTR 的值通過命令 lgdt gdt_descr 實現(xiàn)。通過在 head.s 中查看 gdt_descr 的值可以計算得知,GDT 的gdt_table 的地址,表長 GDT_ENTRIES*8-1(0 x205F)。址

19、為4. 頁目錄的初始化:頁目錄由變量 swapper_pg_dir 表示,共有 1024 個頁目錄項。其第0 項和第 768指向 pg0(第 0 頁),初始化值為 0 x00102007(根據(jù)其高 20bits 的值 0 x102換算:0 x102*4KB=0 x102000,第 0 頁緊跟頁目錄后,物理地址為 0 x102000),由此可知,Linux 4GB 空間中的虛擬地址 0 x0 和 0 xBF(3GB)均由 pg0(物理地址0 x00 x3FF(4MB);其他頁目錄項初始值為 0 x0;5. pg0 的初始化:第 n 項對應(yīng)第 n 頁,屬性為 0 x007;即第 n 項的初始化值的

20、高 20bits值為 n,底 12bits 值為 0 x007;由此可見 pg0了物理空間的低 4MB 空間;6. 初始化 empty_zero_page:該頁的前 2KB 空間用來來自 BIOS 的系統(tǒng)硬件參數(shù);后 2KB 空間作為命令行緩沖區(qū);setup.s 保存在內(nèi)存參數(shù)區(qū)的head.s 進行完初始化后調(diào)用 start_kernel(init/main.c)繼續(xù)各方面的初始化,主要是調(diào)用各方面函數(shù)初始化內(nèi)核的數(shù)據(jù)結(jié)構(gòu),下面對與 X86 系統(tǒng)相關(guān)的調(diào)用函數(shù)簡述其(與本文相關(guān)的)功能。1. setup_arch() (arch/i386/kernel/setup.c) ; 設(shè) 置 內(nèi) 核 可

21、 用 物 理 地 址 范 圍( memory_startmemory_end ); 設(shè) 置 init_task.mm 的 范 圍 ; 調(diào) 用 request_region(kernel/resource.c)申請 I/O 空間,參見附表 4。2. paging_init() (arch/i386/mm/init.c);取消虛擬地址 0 x0 對物理地址的;根據(jù)物理地址的實際大小初始化所有的頁表。4MB 空間的3. trap_init() (arch/i386/kernel/traps.c);在 IDT 中設(shè)置各種地址,如異常事件處理程序,系統(tǒng)調(diào)用,調(diào)用門等。其中,trap0trap17 為各種

22、錯誤(溢出,0 除,頁錯誤等,錯誤處理函數(shù)定義在 arch/i386/kernel/entry.s);trap18trap47 保留;設(shè)置系統(tǒng)調(diào)用(0 x80)的為 system_call(arch/i386/kernel/entry.s);在 GDT 中設(shè)置 0 號進程的 TSS段描述符和LDT 段描述符。4. init_IRQ() (arch/i386/kernel/irq.c);初始化 IDT 中 0 x200 xff 項。5. time_init() (arch/i386/kernel/time.c);實時時間,重新設(shè)置時鐘中斷 irq0 的中斷服務(wù)程序。6. mem_init() (

23、arch/i386/mm/init.c);初始化 empty_zero_page;標記已被占用的頁。Linux 進程和分段分頁每當啟動一個新的進程, Linux 都為其創(chuàng)建一個進程控制塊( task_struct ,include/linux/sched.h)。task_struct 中最重要的與有關(guān)的成員為 mm(mm_struct* mm,include/linux/sched.h)和 tss(thread_struct tss,include/asm-i386/pro系統(tǒng)所涉及的(與分段分頁相關(guān))功能包括:sor.h)。在創(chuàng)建過程中,1. 每個進程(根據(jù)需要)建立新頁目錄(mm 成員 pgd_t * pgd),并將其地址置入寄存器 CR3 中;相關(guān)代碼:new_page_tables(mm/memo

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論