轉(zhuǎn)載自:http://blog.csdn.net/michael2012zhao/article/details/17421383
一融柬、 段寄存器的產(chǎn)生
段寄存器的產(chǎn)生源于Intel 8086 CPU體系結(jié)構(gòu)中數(shù)據(jù)總線與地址總線的寬度不一致磅网。
數(shù)據(jù)總線的寬度,也即是ALU(算數(shù)邏輯單元)的寬度剩瓶,平常說一個CPU是“16位”或者“32位”指的就是這個。8086CPU的數(shù)據(jù)總線是16位哟忍。
地址總線的寬度不一定要與ALU的寬度相同鹅髓。因為ALU的寬度是固定的,它受限于當(dāng)時的工藝水平廓八,當(dāng)時只能制造出16位的ALU奉芦;但地址總線不一樣赵抢,它可以設(shè)計得更寬。地址總線的寬度如果與ALU相同當(dāng)然是不錯的辦法声功,這樣CPU的結(jié)構(gòu)比較均衡烦却,尋址可以在單個指令周期內(nèi)完成,效率最高减噪;而且從軟件的解決來看短绸,一個變量地址的長度可以用整型或者長整型來表示會比較方便。
但是筹裕,地址總線的寬度還要受制于需求醋闭,因為地址總線的寬度決定了系統(tǒng)可尋址的范圍,即可以支持多少內(nèi)存朝卒。如果地址總線太窄的話证逻,可尋址范圍會很小。如果地址總線設(shè)計為16位的話抗斤,可尋址空間是2^16=64KB囚企,這在當(dāng)時被認(rèn)為是不夠的;Intel最終決定要讓8086的地址空間為1M瑞眼,也就是20位地址總線龙宏。
地址總線寬度大于數(shù)據(jù)總線會帶來一些麻煩,ALU無法在單個指令周期里完成對地址數(shù)據(jù)的運算伤疙。有一些容易想到的可行的辦法银酗,比如定義一個新的寄存器專門用于存放地址的高4位,但這樣增加了計算的復(fù)雜性徒像,程序員要增加成倍的匯編代碼來操作地址數(shù)據(jù)而且無法保持兼容性黍特。
Intel想到了一個折中的辦法:把內(nèi)存分段,并設(shè)計了4個段寄存器锯蛀,CS灭衷,DS,ES和SS旁涤,分別用于指令翔曲、數(shù)據(jù)、其它和堆棧劈愚。把內(nèi)存分為很多段瞳遍,每一段有一個段基址,當(dāng)然段基址也是一個20位的內(nèi)存地址造虎。不過段寄存器仍然是16位的傅蹂,它的內(nèi)容代表了段基址的高16位,這個16位的地址后面再加上4個0就構(gòu)成20位的段基址。而原來的16位地址只是段內(nèi)的偏移量份蝴。這樣犁功,一個完整的物理內(nèi)存地址就由兩部分組成,高16位的段基址和低16位的段內(nèi)偏移量婚夫,當(dāng)然它們有12位是重疊的浸卦,它們兩部分相加在一起,才構(gòu)成完整的物理地址案糙。
| Base | b15 ~ b12 | b11 ~ b0 | |
| Offset | | o15 ~ o4 | o3 ~ o0 |
| Address | a19 ~ a0 |
這種尋址模式也就是“實地址模式”限嫌。在8086中,段寄存器還只是一個單純的16位寄存器时捌,而且操作寄存器的指令也不是特權(quán)指令怒医。通過設(shè)置段寄存器和段內(nèi)偏移,程序就可以訪問整個物理內(nèi)存奢讨,無安全性可言稚叹。
總之一句話,段寄存器的設(shè)計是一個權(quán)宜之計拿诸,現(xiàn)在看來可以說是一個臨時性的解決方案扒袖,設(shè)計它的目的是為了把地址空間從64KB擴展為1MB,僅此而已亩码。但是它的加入?yún)s為日后Intel系列芯片的發(fā)展帶來諸多不便季率,也為理解i386體系帶來困擾。
二描沟、 實現(xiàn)保護(hù)模式
到了80386問世的時候飒泻,工藝已經(jīng)有了很大的進(jìn)步,386的ALU有已經(jīng)從16位躍升為32位啊掏,也就是說蠢络,38086是32位的CPU衰猛,而且結(jié)構(gòu)也已經(jīng)比較成熟迟蜜,接下來的80486一直到Pentium系列雖然速度提高了幾個數(shù)量級,但并沒有質(zhì)的變化啡省,所以被統(tǒng)稱為i386結(jié)構(gòu)娜睛。
對于32位的CPU來說,只要地址總線寬度與數(shù)據(jù)總線寬度相同卦睹,就可以尋址2^32=4GB的內(nèi)存空間畦戒,這已經(jīng)足夠用,已經(jīng)不再需要段寄存器來幫助擴展结序。但這時Intel已經(jīng)無法把段寄存器從產(chǎn)品中去掉障斋,因為新的CPU也是產(chǎn)品系列中的一員,根據(jù)兼容性的需要,段寄存器必須保留下來垃环。
這時邀层,技術(shù)的發(fā)展需求Intel在其CPU中實現(xiàn)“保護(hù)模式”,用戶程序的可訪問內(nèi)存范圍必須受到限制遂庄,不能再任意地訪問內(nèi)存所有地址寥院。Intel決定利用段寄存器來實現(xiàn)他們的保護(hù)模式,把保護(hù)模式建立在段寄存器的基礎(chǔ)之上涛目。
對于段的描述不再只是一個20位的起始地址秸谢,而是全新地定義了“段描述項”。段描述項的結(jié)構(gòu)如下:
| B31 ~ B24 | DES1 (4 bit) | L19 ~ L16 |
| DES2 (8 bit) | B23 ~ B16 |
| B15 ~ B0 |
| L15 ~ L0 |
每一行是兩個字節(jié)霹肝,總共8個字節(jié)估蹄,64位。
DES1和DES2分別是一些描述信息沫换,用于描述本段是數(shù)據(jù)段還是代碼段元媚,以及讀寫權(quán)限等等。B0B31是段的基地址苗沧,L0L19是段的長度刊棕。
注意,規(guī)定段的長度是非常必要的待逞,如果不限定段長度甥角,“保護(hù)”就無從談起,用戶程序的訪問至少不能超過段的范圍识樱。另外嗤无,段長度只有20位,所代表的最大可能長度為220=1M怜庸,而整個地址空間是232=4GB当犯,這樣來看,段的長度是不是太短了割疾?其實嚎卫,在DES1中,有一位用于表示段長度的單位宏榕,當(dāng)它被置1時(一般情況下都是如此)拓诸,表示長度單位為4KB,這樣麻昼,一個段的最大可能尺寸就成了1M*4K=4G奠支,與地址空間相穩(wěn)合。4KB也正是一個內(nèi)存頁的大小抚芦,說明段的大小也是向頁對齊的倍谜。
另外迈螟,注意到一個有趣的現(xiàn)象嗎?段描述項的結(jié)構(gòu)被設(shè)計得不連續(xù)尔崔,不論是段基地址還是段長度井联,都被分成了兩節(jié)表示。這樣的設(shè)計與80286的過渡有關(guān)您旁。上面的段描述項結(jié)構(gòu)去掉第一行后剩下的三行正是286的段描述項烙常。286被設(shè)計為24位地址總線,所以段基址是24位鹤盒,相應(yīng)地段長是16位蚕脏。在386的地址總線擴展為32位之后,還必須兼容286產(chǎn)品的設(shè)計侦锯,所以只好在段描述項上“打補丁”驼鞭。
在386中,段寄存器還是16位尺碰,那么16位的段寄存器如何存放得下64位的段描述項挣棕? 段描述項不再由段寄存器直接持有。段描述項存放在內(nèi)存里亲桥,系統(tǒng)中可以有很多個段描述項洛心,這些項連續(xù)存放,共同構(gòu)成一張表题篷,16位的段寄存器里只是含有這張表里的一個索引词身,但也并不僅是一個簡單的序號,而是存儲了一種數(shù)據(jù)結(jié)構(gòu)番枚,這種結(jié)構(gòu)的定義如下:
| index (b15 ~ b3) | TI (b2) | RPL (b1 ~ b0) |
其中index是段描述表的索引法严,它指向其中的某一個段描述項。RPL表示權(quán)限葫笼,00最高深啤,11最低。
還有一個關(guān)鍵的問題路星,內(nèi)存中的段描述表的起始地址在哪里溯街?顯然光有索引是有不夠的。為此奥额,Intel又設(shè)計了兩個新的寄存器:GDTR(global descriptor table register)和LDTR(local descriptor table register)苫幢,分別用來存儲段描述表的地址访诱。段寄存器中的TI位正是用于指示使用GDTR還是LDTR垫挨。
當(dāng)用戶程序要求訪問內(nèi)存時,CPU根據(jù)指令的性質(zhì)確定使用哪個段寄存器触菜,轉(zhuǎn)移指令中的地址在代碼段九榔,取數(shù)指令中的地址在數(shù)據(jù)段;根據(jù)段寄存器中的索引值,找到段描述項哲泊,取得段基址剩蟀;指令中的地址是段內(nèi)偏移,與段長比較切威,確保沒有越界育特;檢查權(quán)限;把段基址和偏移相加先朦,構(gòu)成物理地址缰冤,取得數(shù)據(jù)。
新的設(shè)計中處處有權(quán)限與范圍的限制喳魏,用戶程序只能訪問被授權(quán)的內(nèi)存空間棉浸,從而實現(xiàn)了保護(hù)機制。就這樣刺彩,在段寄存器的基礎(chǔ)上迷郑,Intel實現(xiàn)了自己的“保護(hù)模式”。
三创倔、 與頁式存管并存
現(xiàn)代操作系統(tǒng)的發(fā)展要求CPU支持頁式存儲管理嗡害。
頁式存管本身是與段式存管分立的,兩者沒有什么關(guān)系畦攘。但對于Intel來說就漾,同樣是由于“段寄存器”這個歷史的原因,它必須把頁式存管建立在段式存管的基礎(chǔ)之上念搬,盡管這從設(shè)計的角度來說這是沒有道理抑堡,也根本沒有必要的。
在段式存管中朗徊,由程序發(fā)出的變量地址經(jīng)映射(段基址+段內(nèi)偏移)之后首妖,得到的32位地址就是一個物理地址,是可以直接放到地址總線是去取數(shù)的爷恳。
在頁式存管中有缆,過程也是相似的,由程序發(fā)出的變量地址并不是實際的物理地址温亲,而是一個三層的索引結(jié)構(gòu)棚壁,這個地址經(jīng)過一系統(tǒng)的映射之后才可以得到物理地址。
現(xiàn)在對于Intel CPU來說栈虚,以上兩個映射過程就要先后各做一次袖外。由程序發(fā)出的變量地址稱為“邏輯地址”,先經(jīng)過段式映射成為“線性地址”魂务,線性地址再做為頁式映射的輸入曼验,最后得到“物理地址”泌射。
Linux內(nèi)核實現(xiàn)了頁式存儲管理,而且并沒有因為兩層存管的映射而變得更復(fù)雜鬓照。Linux更關(guān)注頁式內(nèi)存管理熔酷,對于段式映射,采用了特殊的方式把它簡化豺裆。讓每個段寄存器都指向同一個段描述項拒秘,即只設(shè)了一個段,而這個段的基地址為0臭猜,段長度設(shè)為最大值4G翼抠,這個段就與整個物理內(nèi)存相重合,邏輯地址經(jīng)映射之后就與線性地址相同获讳,從而把段式存管變成“透明”的阴颖。
這,就是Intel處理器中“段寄存器”的故事丐膝。