80386的分段机制、分页机制和物理地址的形成
MOVE REG,ADDR ;
它把地址為ADDR(假設(shè)為10000)的內(nèi)存單元的內(nèi)容復(fù)制到REG 中
在8086 的實(shí)模式下,把某一段寄存器(段基址)左移4 位,然后與地址ADDR 相加后被直接送到內(nèi)
存總線上,這個(gè)相加后的地址(20位)就是內(nèi)存單元的物理地址,而程序中的這個(gè)地址ADDR就叫邏輯地址
(或叫虛地址)。
在80386 的段機(jī)制中,邏輯地址由兩部分組成,即
段部分(選擇符)
及偏移部分。
段是形成邏輯地址到線性地址轉(zhuǎn)換的基礎(chǔ)。如果我們把段看成一個(gè)對(duì)象的話,那么對(duì)它
的描述如下。
(1)段的基地址(Base Address):在線性地址空間中段的起始地址。
(2)段的界限(Limit):表示在邏輯地址中,段內(nèi)可以使用的最大偏移量。
(3)段的屬性(Attribute): 表示段的特性。例如,該段是否可被讀出或?qū)懭耄蛘?br /> 該段是否作為一個(gè)程序來(lái)執(zhí)行,以及段的特權(quán)級(jí)等。
1、邏輯地址、線性地址和物理地址
所謂
描述符(Descriptor)
,就是描述段的屬性的一個(gè)8 字節(jié)存儲(chǔ)單元。
2、用戶段描述符(Descriptor)
一個(gè)段描述符指出了段的32 位基地址和20 位段界限(即段大小)。
第6 個(gè)字節(jié)的G 位是粒度位,當(dāng)G=0 時(shí),段長(zhǎng)表示段格式的字節(jié)長(zhǎng)度,即一個(gè)段最長(zhǎng)可
達(dá)1M 字節(jié)。當(dāng)G=1 時(shí),段長(zhǎng)表示段的以4K 字節(jié)為一頁(yè)的頁(yè)的數(shù)目,即一個(gè)段最長(zhǎng)可達(dá)
1M×4K=4G 字節(jié)。D 位表示缺省操作數(shù)的大小,如果D=0,操作數(shù)為16 位,如果D=1,操作數(shù)
為32 位。
第7 位P 位(Present) 是存在位,表示段描述符描述的這個(gè)段是否在內(nèi)存中,如果在
內(nèi)存中。P=1;如果不在內(nèi)存中,P=0。
DPL(Descriptor Privilege Level)
,就是描述符特權(quán)級(jí),它占兩位,其值為0~3,
用來(lái)確定這個(gè)段的特權(quán)級(jí)即保護(hù)等級(jí)。0為內(nèi)核級(jí)別,3為用戶級(jí)別。
S 位(System)表示這個(gè)段是系統(tǒng)段還是用戶段。如果S=0,則為系統(tǒng)段,如果S=1,則
為用戶程序的代碼段、數(shù)據(jù)段或堆棧段。
類型占3 位,第3 位為E 位,表示段是否可執(zhí)行。當(dāng)E=0 時(shí),為數(shù)據(jù)段描述符,這時(shí)的
第2 位ED 表示地址增長(zhǎng)方向。
第1 位(W)是可寫(xiě)位
。
當(dāng)段為代碼段時(shí),第3 位E=1,這時(shí)第2 位為一致位(C)。當(dāng)C=1 時(shí),如果當(dāng)前特權(quán)級(jí)
低于描述符特權(quán)級(jí),并且當(dāng)前特權(quán)級(jí)保持不變,那么代碼段只能執(zhí)行。所謂當(dāng)前特權(quán)級(jí)
CPL
(Current Privilege Level)
,就是當(dāng)前正在執(zhí)行的任務(wù)的特權(quán)級(jí)。第1 位為可讀位R
。
存取權(quán)字節(jié)的第0 位A 位是訪問(wèn)位,用于請(qǐng)求分段不分頁(yè)的系統(tǒng)中,每當(dāng)該段被訪問(wèn)時(shí),
將A 置1。對(duì)于分頁(yè)系統(tǒng),則A 被忽略未用。
3、系統(tǒng)段描述符
系統(tǒng)段描述符的第5 個(gè)字節(jié)的第4 位為0,說(shuō)明它是系統(tǒng)段描述符,類型占
4 位,沒(méi)有A 位。第6 個(gè)字節(jié)的第6 位為0,說(shuō)明系統(tǒng)段的長(zhǎng)度是字節(jié)粒度,所以,一個(gè)系統(tǒng)
段的最大長(zhǎng)度為1M 字節(jié)。
系統(tǒng)段的類型為16 種,如圖2.15 所示。
在這16 種類型中,保留類型和有關(guān)286 的類型不予考慮。
門也是一種描述符,有調(diào)用門、任務(wù)門、中斷門和陷阱門4 種門描述符
。
4、選擇符、描述符表和描述符表寄存器
描述符表(即段表)定義了386 系統(tǒng)的所有段的情況。所有的描述符表本身都占據(jù)一個(gè)
字節(jié)為8 的倍數(shù)的存儲(chǔ)器空間,空間大小在8 個(gè)字節(jié)(至少含一個(gè)描述符)到64K 字節(jié)(至
多含8K=8192)個(gè)描述符之間。
1.全局描述符表(GDT)
全局描述符表GDT(Global Descriptor Table),除了任務(wù)門,中斷門和陷阱門描述符
外,包含著系統(tǒng)中所有任務(wù)都共用的那些段的描述符。它的第一個(gè)8 字節(jié)位置沒(méi)有使用。
2.中斷描述符表(IDT)
中斷描述符表IDT(Interrupt Descriptor Table),包含256 個(gè)門描述符。IDT 中只
能包含任務(wù)門、中斷門和陷阱門描述符,雖然IDT 表最長(zhǎng)也可以為64K 字節(jié),但只能存取2K
字節(jié)以內(nèi)的描述符,即256 個(gè)描述符,這個(gè)數(shù)字是為了和8086 保持兼容。
3.局部描述符表(LDT)
局部描述符表LDT(Local Descriptor Table),包含了與一個(gè)給定任務(wù)有關(guān)的描述符,
每個(gè)任務(wù)各自有一個(gè)的LDT。有了LDT,就可以使給定任務(wù)的代碼、數(shù)據(jù)與別的任務(wù)相隔離。
每一個(gè)任務(wù)的局部描述符表LDT 本身也用一個(gè)描述符來(lái)表示,稱為L(zhǎng)DT 描述符,它包含
了有關(guān)局部描述符表的信息,被放在全局描述符表GDT 中,使用LDTR進(jìn)行索引。
在實(shí)模式下,段寄存器存儲(chǔ)的是真實(shí)的段基址,在保護(hù)模式下,16 位的段寄存器無(wú)法放
下32 位的段基址,因此,它們被稱為選擇符,即段寄存器的作用是用來(lái)選擇描述符。選擇符
的結(jié)構(gòu)如圖2.16 所示。
可以看出,選擇符有3 個(gè)域:第15~3 位這13 位是索引域,表示的數(shù)據(jù)為0~8129,用于
指向全局描述符表中相應(yīng)的描述符。第2 位為選擇域,如果TI=1,就從局部描述符表中選擇
相應(yīng)的描述符,如果TI=0,就從全局描述符表中選擇描述符。第1、0 位是特權(quán)級(jí),表示選
擇符的特權(quán)級(jí),被稱為請(qǐng)求者特權(quán)級(jí)
RPL(Requestor Privilege Level
)。只有請(qǐng)求者特權(quán)
級(jí)RPL 高于(數(shù)字低于)或等于相應(yīng)的描述符特權(quán)級(jí)DPL,描述符才能被存取,這就可以實(shí)
現(xiàn)一定程度的保護(hù)。
下面講一下在沒(méi)有分頁(yè)操作時(shí),尋址一個(gè)存儲(chǔ)器操作數(shù)的步驟。
(1)在段選擇符中裝入16 位數(shù),同時(shí)給出32 位地址偏移量(比如在ESI、EDI 中等)。
(2)先根據(jù)相應(yīng)描述符表寄存器中的段地址(
確定描述符表的地址
)和
段界限
(確定描述符表的大小)
,根據(jù)段選擇符的TI決定從哪種描述符表中取,再根據(jù)段選擇符的索引找到相應(yīng)段描述符的位置
,比較RPL與DPL,若該段無(wú)問(wèn)題,就取出相應(yīng)的段
描述符放入段描述符高速緩沖寄存器中。
(3)將段描述符中的32 位段基地址和放在ESI、EDI 等中的32 位有效地址相加,就形成
了32 位物理地址。
5、linux中的段機(jī)制
從2.2 版開(kāi)始,Linux 讓所有的進(jìn)程(或叫任務(wù))都使用相同的邏輯地址空間,因此就
沒(méi)有必要使用局部描述符表LDT。
Linux 在啟動(dòng)的過(guò)程中設(shè)置了段寄存器的值和全局描述符表GDT 的內(nèi)容,段寄存器的定義在
include/asm-i386/segment.h 中:
C++ Code
|
1 |
#define__KERNEL_CS0x10 |
從定義看出,沒(méi)有定義堆棧段,實(shí)際上,Linux 內(nèi)核不區(qū)分?jǐn)?shù)據(jù)段和堆棧段,這也體現(xiàn)
了Linux 內(nèi)核盡量減少段的使用。因?yàn)闆](méi)有使用LDT,因此,TI=0,并把這4 個(gè)段描述符都放在GDT
中, index 就是某個(gè)段描述符在GDT 表中的下標(biāo)。內(nèi)核代碼段和數(shù)據(jù)段具有最高特權(quán),因此其RPL
為0,而用戶代碼段和數(shù)據(jù)段具有最低特權(quán),因此其RPL 為3。
全局描述符表的定義在arch/i386/kernel/head.S 中:
C++ Code
|
1 |
ENTRY(gdt_table) |
從代碼可以看出,GDT 放在數(shù)組變量gdt_table 中。按Intel 規(guī)定,GDT 中的第一項(xiàng)為
空,這是為了防止加電后段寄存器未經(jīng)初始化就進(jìn)入保護(hù)模式而使用GDT 的。第二項(xiàng)也沒(méi)用。
從下標(biāo)2~5 共4 項(xiàng)對(duì)應(yīng)于前面的4 種段描述符值。對(duì)照?qǐng)D2.10,從描述符的數(shù)值可以得出:
• 段的基地址全部為0x00000000;
• 段的上限全部為0xffff;
• 段的粒度G 為1,即段長(zhǎng)單位為4KB;
• 段的D 位為1,即對(duì)這4 個(gè)段的訪問(wèn)都為32 位指令;
• 段的P 位為1,即4 個(gè)段都在內(nèi)存。
由此可以得出,每個(gè)段的邏輯地址空間范圍為0~4GB。
每個(gè)段的基地址為0,因此,邏輯地
址到線性地址映射保持不變,也就是說(shuō),
偏移量就是線性地址
,我們以后所提到的邏輯地址
(或虛擬地址)和線性地址指的也就是同一地址。看來(lái),Linux 巧妙地把段機(jī)制給繞過(guò)去了,
它只把段分為兩種:用戶態(tài)(RPL
=3)的段和內(nèi)核態(tài)(RPL=0)的段,
而完全利用了分頁(yè)機(jī)制。
按Intel 的規(guī)定,每個(gè)進(jìn)程有一個(gè)任務(wù)狀態(tài)段(TSS)和局部描述符表LDT,但Linux 也
沒(méi)有完全遵循Intel 的設(shè)計(jì)思路。如前所述,Linux 的進(jìn)程沒(méi)有使用LDT,而對(duì)TSS 的使用也
非常有限,每個(gè)CPU 僅使用一個(gè)TSS。
TSS 有它自己 8 字節(jié)的任務(wù)段描述符(Task State Segment Descriptor ,簡(jiǎn)稱
TSSD)。這個(gè)描述符包括指向TSS 起始地址的32 位基地址域,20 位界限域,界限域值不能小
于十進(jìn)制104(由TSS 段的最小長(zhǎng)度決定)。TSS 描述符存放在GDT 中,它是GDT 中的一個(gè)表
項(xiàng),由中斷描述符表(IDT)中的任務(wù)門(存放TSS段的選擇符)裝入TR來(lái)進(jìn)行索引。
7、頁(yè)目錄項(xiàng)、頁(yè)表項(xiàng)、頁(yè)面項(xiàng)
80386 使用4K 字節(jié)大小的頁(yè)。每一頁(yè)都有4K 字節(jié)長(zhǎng),并在4K 字節(jié)的邊界上對(duì)齊,即每
一頁(yè)的起始地址都能被4K 整除。因此,80386 把4G 字節(jié)的線性地址空間,劃分為1G 個(gè)頁(yè)面,
每頁(yè)有4K 字節(jié)大小。分頁(yè)機(jī)制通過(guò)把線性地址空間中的頁(yè),重新定位到物理地址空間來(lái)進(jìn)行
管理,因?yàn)槊總€(gè)頁(yè)面的整個(gè)4K 字節(jié)作為一個(gè)單位進(jìn)行映射,并且每個(gè)頁(yè)面都對(duì)齊4K 字節(jié)的
邊界,因此,線性地址的低12 位經(jīng)過(guò)分頁(yè)機(jī)制直接地作為物理地址的低12 位使用。
頁(yè)目錄表
,
存儲(chǔ)在一個(gè)4K 字節(jié)的頁(yè)面中,
最多可包含1024 個(gè)
頁(yè)目錄項(xiàng)
,每個(gè)頁(yè)目錄項(xiàng)為4 個(gè)字節(jié),結(jié)
構(gòu)如圖2.22 所示。
•
第31~12 位是20 位頁(yè)表地址,由于頁(yè)表地址的低12 位總為0,所以用高20 位指出
32 位頁(yè)表地址就可以了。
•
第0 位是存在位,如果P=1,表示頁(yè)表地址指向的該頁(yè)在內(nèi)存中,如果P=0,表示不
在內(nèi)存中。
•
第1 位是讀/寫(xiě)位,第2 位是用戶/管理員位,這兩位為頁(yè)目錄項(xiàng)提供硬件保護(hù)。當(dāng)特
權(quán)級(jí)為3 的進(jìn)程要想訪問(wèn)頁(yè)面時(shí),需要通過(guò)頁(yè)保護(hù)檢查,而特權(quán)級(jí)為0 的進(jìn)程就可以繞過(guò)頁(yè)
保護(hù),如圖2.23 所示。
•
第3 位是PWT(Page Write-Through)位,表示是否采用寫(xiě)透方式,寫(xiě)透方式就是既
寫(xiě)內(nèi)存(RAM)也寫(xiě)高速緩存,該位為1 表示采用寫(xiě)透方式。
第4 位是PCD(Page Cache Disable)位,表示是否啟用高速緩存,該位為1 表示啟
用高速緩存。
•
第5 位是訪問(wèn)位,當(dāng)對(duì)頁(yè)目錄項(xiàng)進(jìn)行訪問(wèn)時(shí),A 位=1。
•
第7 位是Page Size 標(biāo)志,只適用于頁(yè)目錄項(xiàng)。如果置為1,頁(yè)目錄項(xiàng)指的是4MB 的
頁(yè)面,即擴(kuò)展分頁(yè)。
80386 的每個(gè)頁(yè)目錄項(xiàng)指向一個(gè)
頁(yè)表
,
存儲(chǔ)在一個(gè)4K 字節(jié)的頁(yè)面中,
頁(yè)表最多含有1024 個(gè)
頁(yè)面項(xiàng)
,每項(xiàng)4 個(gè)字節(jié),包
含頁(yè)面的起始地址和有關(guān)該頁(yè)面的信息。頁(yè)面的起始地址也是4K 的整數(shù)倍,所以頁(yè)面的低
12 位也留作它用,如圖2.24 所示。
第31~12 位是
20 位物理頁(yè)面地址
,除第6 位外第0~5 位及9~11 位的用途和頁(yè)目錄
項(xiàng)一樣,第6 位是頁(yè)面項(xiàng)獨(dú)有的,當(dāng)對(duì)涉及的頁(yè)面進(jìn)行寫(xiě)操作時(shí),D 位被置1。
4GB 的存儲(chǔ)器只有一個(gè)頁(yè)目錄,它最多有1024 個(gè)頁(yè)目錄項(xiàng),每個(gè)頁(yè)目錄項(xiàng)又含有1024
個(gè)頁(yè)面項(xiàng),因此,存儲(chǔ)器一共可以分成1024×1024=1M 個(gè)頁(yè)面。由于每個(gè)頁(yè)面為4K 個(gè)字節(jié),
所以,存儲(chǔ)器的大小正好最多為4GB。
當(dāng)訪問(wèn)一個(gè)操作單元時(shí),如何由分段結(jié)構(gòu)確定的32 位線性地址通過(guò)分頁(yè)操作轉(zhuǎn)化成32
位物理地址呢?
第一步,CR3 包含著頁(yè)目錄的起始地址,用32 位線性地址的最高10 位A31~A22 作為頁(yè)
目錄表的頁(yè)目錄項(xiàng)的索引,將它乘以4,與CR3 中的頁(yè)目錄表的起始地址相加,形成相應(yīng)頁(yè)目錄項(xiàng)的
地址。
第二步,從指定的地址中取出32 位頁(yè)目錄項(xiàng),它的低12 位為0,這32 位是頁(yè)表的起始
地址。用32 位線性地址中的A21~A12 位作為頁(yè)表中的頁(yè)表項(xiàng)的索引,將它乘以4,與頁(yè)表的起
始地址相加,形成相應(yīng)頁(yè)表項(xiàng)的地址。
第三步,從指定地址中取出32位頁(yè)表項(xiàng),它的低12位為0,這32位是頁(yè)面地址,將A11~A0 作為相對(duì)于頁(yè)面地址的偏移量,與32 位頁(yè)面地址相加,形成32 位
物理地址。
8、linux 中的分頁(yè)機(jī)制
Linux 的分段機(jī)制使得所有的進(jìn)程都使用相同的段寄存器值,這就使得內(nèi)存管理變得
簡(jiǎn)單,也就是說(shuō),所有的進(jìn)程都使用同樣的線性地址空間(0~4GB)。
Linux 采用三級(jí)分頁(yè)模式而不是兩級(jí)
。如圖2.28 所示為三級(jí)分頁(yè)模式,為此,Linux
定義了3 種類型的表。
• 總目錄PGD(Page Global Directory)
• 中間目錄PMD(Page Middle Derectory)
• 頁(yè)表PT(Page Table)
總結(jié)
以上是生活随笔為你收集整理的80386的分段机制、分页机制和物理地址的形成的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。