大學(xué)也上過微機(jī)原理,但那個(gè)時(shí)候整天玩PHP,VC++,C# .net...數(shù)據(jù)庫管理系統(tǒng)...沒有意識(shí)到她是一門非常重要的課。于是上這些基礎(chǔ)課的時(shí)候都在下面看那些xxx從入門到精通之類的書了或者干脆翹了去圖書館看(當(dāng)然我不會(huì)否認(rèn)正是因?yàn)檫@些書讓我玩計(jì)算機(jī)的興趣堅(jiān)持了下去)。大學(xué)畢業(yè)同學(xué)都把書賣了。我當(dāng)時(shí)感到像微機(jī)原理組成原理之類的書可能以后有用,于是沒有賣(因?yàn)槲抑雷约旱呐d趣所在)。 畢業(yè)后感覺那些xxx從入門到精通之類的書太無聊也太多。更多的是興趣吧,于是慢慢的啃起微機(jī)原理,操作系統(tǒng)來了。 廢話還是少說,總結(jié)下80386保護(hù)模式內(nèi)存尋址。防止以后忘了可以看看,再者希望有相同興趣的人看到了減少他們的彎路和指出我理解的錯(cuò)誤。
一、概括對(duì)比下8086和80386的尋址
8086的邏輯地址由16位的段地址和16位的段內(nèi)偏移組成。尋址方式:段地址由用戶程序指定,保存在段寄存器中。以后程序直接使用段內(nèi)偏移地址(就是段內(nèi)的偏移量)就行了。內(nèi)存尋址時(shí)(如何得到物理內(nèi)存地址): 1.取得相應(yīng)的段地址(保存段寄存器中)。 2.取得偏移地址(這個(gè)一般都是指令中給出的)。 3.經(jīng)過一個(gè)運(yùn)算規(guī)則A 4.得到物理內(nèi)存地址
80386的邏輯地址是也分兩部分:16位段選擇子+32位段內(nèi)偏移。尋址方式:邏輯地址(這里用虛擬地址合理)在程序編譯時(shí)候決定(可能是操作系統(tǒng),編譯器,連接器給出的)。內(nèi)存尋址時(shí): 1.取得相應(yīng)的段選擇子(保存段寄存器中)。(段選擇子其實(shí)還是在16位段寄存器中。只是名字改了而已。后面會(huì)說明為什么) 2.取得偏移地址(這個(gè)一般都是指令中給出的)。 3.經(jīng)過一個(gè)運(yùn)算規(guī)則B 4.得到物理內(nèi)存地址(如果沒有分頁)
從上面可以看出從8086到80386段內(nèi)存管理是本質(zhì)上是一樣的。都是通過段寄存器和偏移地址來尋址:尋址方式可表示成段寄存器:[段內(nèi)偏移] 不同的地方是從8086到80386上面的步驟3中的運(yùn)算規(guī)則和偏移地址長度改變了而已。
現(xiàn)在具體寫下步驟3中的地址運(yùn)算規(guī)則: 運(yùn)算規(guī)則A(8086): 20位的物理地址 = 段地址(16位)*10h + 段內(nèi)偏移(16位) 這就是傳說中的段地址左移四位+偏移地址形成20位物理地址。運(yùn)算規(guī)則B(8386): 1.根據(jù)段選擇子找到段基地址(32位) 2.32位物理地址 = 段基地址(32位) + 段內(nèi)偏移(32位) 之所以叫80386改名叫選擇子時(shí)因?yàn)槎位刂肥怯啥渭拇嫫髦械膬?nèi)容選擇出來的。其實(shí)這一切還是很簡單。要說復(fù)雜那就是80386多了些計(jì)算步驟而已。但是不用擔(dān)心。這些尋址由硬件完成不用你自己計(jì)算。
最后要說明的是80386還多了一個(gè)分頁的功能,這個(gè)功能是可選的。要是啟用分頁,上面得到地址其實(shí)是線性地址,還要變換才能形成物理地址。
二、相關(guān)寄存器和數(shù)據(jù)結(jié)構(gòu)
這個(gè)地方可以先隨便看看(但是很重要的其實(shí)),不懂的繞過。等看到看下面可以返回來查閱。
Descriptor 描述符一個(gè)固定結(jié)構(gòu)的結(jié)構(gòu)體(struct)長度是8字節(jié)也就是64位,那么這個(gè)結(jié)構(gòu)體是干嘛的呢?用來描述一個(gè)段基地址。這個(gè)結(jié)構(gòu)體內(nèi)容包括段基地址,段長度,段屬性。這個(gè)被描述的段基地址就是上面我們說的?。常参晃锢淼刂?= 段基地址(32位) + 段內(nèi)偏移(32位) 中的段基地址。描述符有兩種,也就是說這種結(jié)構(gòu)體有兩種不同的結(jié)構(gòu)(其實(shí)其中包含的內(nèi)容都幾乎一樣只有一些細(xì)小的差別)。一種用來描述數(shù)據(jù)段,代碼段和堆棧段的,稱為非系統(tǒng)描述符,另一種就是用來描述LDT和TSS的,(LDT和TSS在后面有說明)稱為系統(tǒng)段描述符。
GDT 全局描述符表(Global Descripter Table) 顧名思義,就是一個(gè)表而已。這個(gè)表存儲(chǔ)在內(nèi)存中,相當(dāng)于一個(gè)結(jié)構(gòu)體數(shù)組。數(shù)組的每一項(xiàng)就是上面所說的描述符了。這個(gè)表中可以包含四種信息的描述符。1.全局的數(shù)據(jù)段代碼段堆棧段,這些段一般操作系統(tǒng)內(nèi)核使用。(每個(gè)單獨(dú)的用戶任務(wù)由LDT描述,LDT后面有說明) 2.對(duì)LDT的描述 這個(gè)描述符的基址就是是LDT所在內(nèi)存中的起始地址 3.對(duì)TSS的描述 這個(gè)描述符的基址是TSS所在內(nèi)存中的起始地址 4.一些門描述符(調(diào)用門,中斷門...) 其中#1用的是上面說的非系統(tǒng)段描述符,#2,#3,#4用的是系統(tǒng)段描述符。不同門買描述符,LDT,TSS雖然都用系統(tǒng)段描述符但是其中一些屬性值用拉區(qū)分不同的描述符。 BTW:LDT,TSS都是屬于每個(gè)任務(wù)的所以一般成對(duì)出現(xiàn)在GDT中。
GDTR 全局描述符表寄存器(Global Descripter Table?。遥錱ister) GDTR就是一個(gè)寄存器,和AX BX.. CS DS...一個(gè)概念。這個(gè)寄存器共有48位。其中32位地址指出GDT在內(nèi)存中的位置(可以說這個(gè)是一個(gè)32位的物理地址,如果沒有分頁開啟),另外16位為GDT的大?。℅DT最多可以有多少項(xiàng))。
LDT 局部描述符表(Local Descripter Table) 和GDT的結(jié)構(gòu)差不多,所不同的是LDT只是包含對(duì)具體每個(gè)用戶任務(wù)的代碼段堆棧段數(shù)據(jù)段描述(當(dāng)然就沒有包含對(duì)TSS,和LDT的描述項(xiàng)了).
LDTR 局部描述符表寄存器(Global Descripter Table?。遥錱ister) LDTR和GDTR一樣也是寄存器,不同的是它只有16位大小。為什么不和GDTR不是48位呢?原因如下: 1.GDT在一個(gè)多任務(wù)系統(tǒng)中一般只有一個(gè),所以基址由一個(gè)GDTR確定,之后幾乎不會(huì)改變。但是LDT的數(shù)量是可以和用戶任務(wù)相等的,就是每個(gè)用戶任務(wù)都可能擁有自己的LDT,這里L(fēng)DTR不方便和GDTR一樣使用一個(gè)48位的寄存器給出基址,因?yàn)槿蝿?wù)的切換這個(gè)之前基址就丟失了。任務(wù)就切換不回來了?;蛘呷蝿?wù)切換回來重建自己的LDT,效率很低。 2.LDTR中存放的是一個(gè)16位選擇子,根據(jù)這個(gè)選擇子去在GDT中尋址找到LDT的基址。換句話說:全局描述符表(GDT)的基址是存在GDTR中的(就是說GDT靠GDTR定位),而局部描述符表(LDT)的基址是存在GDT中的,作為GDT這張表中的一項(xiàng)描述的(注意,前面我們說過GDT中描述符項(xiàng)包括對(duì)LDT段的描述)。 LDTR當(dāng)作為選擇子,LDT作為一項(xiàng)在GDT中描述好處在于:每個(gè)用戶任務(wù)的局部描述符表(LDT)的起始內(nèi)存地址放在GDT中,這樣切換任務(wù)的時(shí)候只要改變選擇子就能實(shí)現(xiàn)LDT的切換,而且由于每個(gè)LDT在GDT中都有描述,不會(huì)丟失,方便任務(wù)切換回來。
TR 任務(wù)寄存器(Task Register) 是一個(gè)16為的選擇子,作用和LDTR類似,都是用來索引全局描述符表(GDT)中的一項(xiàng)。所不同的是TR選擇的描述符描述的不再是LDT的段了。TR選擇的描述符描述的一個(gè)任務(wù)狀態(tài)段(TSS:Task Status Segment)。
TSS 任務(wù)狀態(tài)段(Task State Segment) 正如前面所說,任務(wù)狀態(tài)段(TSS)是在GDT中描述的。任務(wù)狀態(tài)段是做什么的呢?任務(wù)狀態(tài)段就是內(nèi)存中的一個(gè)數(shù)據(jù)結(jié)構(gòu)。這個(gè)結(jié)構(gòu)中保存著和任務(wù)相關(guān)的信息。當(dāng)發(fā)生任務(wù)切換的時(shí)候會(huì)把當(dāng)前任務(wù)用到的寄存器內(nèi)容(CS EIP DS SS...)包括LDT的選擇子等保存在TSS中以便任務(wù)切換回來時(shí)候繼續(xù)使用。
其實(shí)除了上述寄存器以外,還有一些不可訪問的隱藏寄存器,這些隱藏寄存器其實(shí)是高速緩沖寄存器,可以忽略它的存在。為了降低理解復(fù)雜度上面沒有寫出。將在下面部分給出解釋。
Selector 選擇子按照用途共有三種(其實(shí)就是一種,因?yàn)楦袷酵耆粯?, 1.TR中的選擇子,用來從GDT中選擇一個(gè)TSS的描述符。 2.LDTR中的選擇子,用來從GDT中選擇一個(gè)LDT的描述符。 3.用戶程序中的邏輯地址(虛擬地址,這個(gè)地址48位 = 16位選擇子+32位偏移地址)中包含的選擇子。用來選擇程序用到的段在LDT(或者GDT)中的描述符(數(shù)據(jù)段,代碼段...)。這個(gè)選擇子由編譯或者連接或者操作系統(tǒng)決定的.
三、分頁
CR0中保存一個(gè)頁基址A,線性地址經(jīng)兩級(jí)頁變換成物理地址:具體見下圖(摘自80386 manual).
線性地址從高到底被分成三個(gè)部分高10位B,中間10位C,末12位D。變換過程不再描述(語言描述可能看上去復(fù)雜,其實(shí)很簡單)。這里給出一個(gè)變換公式比較明了: 頁基址 = A; 頁基址 = 頁基址 + B * 4; /* 查一級(jí)目錄頁表,在(頁基址+B*4)處取得二級(jí)頁表的的基址,這里等號(hào)的意思是查表 */ 頁基址 = 頁基址 + C * 4 ; /* 查二級(jí)目錄頁表,在(頁基址+B*4)處取得物理基址,這里等號(hào)的意思是查表 */ 物理地址 = 物理基址 + D; 為什么要X4?因?yàn)轫摫戆?位對(duì)齊的。頁目錄項(xiàng)后四位不用。順便說下選擇子去GDT/LDT中索引是:描述符地址 = Base+Selector*8.為什么要X8?道理類似,GDT/LDT中一項(xiàng)8字節(jié)。四、80386內(nèi)存管理和任務(wù)切換(具體過程)
一個(gè)80386操作系系統(tǒng)中運(yùn)行兩個(gè)用戶任務(wù)A和B 具體如下圖:
這個(gè)過程沒有畫出包括上門說的不可訪問的隱藏寄存器。實(shí)際上,TR,LDTR之后都有一個(gè)64位(內(nèi)容和描述符一樣)外部不可訪問的高速緩沖寄存器。內(nèi)容為當(dāng)前選擇子對(duì)應(yīng)的描述符。這樣只有在切換任務(wù)的時(shí)候才去內(nèi)存中GDT索引。具體任務(wù)在執(zhí)行代碼或者數(shù)據(jù)尋址時(shí)CPU直接讀取高速緩沖寄存器中保存的某個(gè)和TR或者LDTR相對(duì)應(yīng)的描述符。
任務(wù)A運(yùn)行
任務(wù)B運(yùn)行
聯(lián)系客服