【轉】操做系統 gdt ldt

GDT的由來:

 
 
在Protected Mode下,一個重要的必不可少的數據結構就是GDT(Global Descriptor Table)。
爲何要有GDT?咱們首先考慮一下在Real Mode下的編程模型:
在Real Mode下,咱們對一個內存地址的訪問是經過Segment:Offset的方式來進行的,其中Segment是一個段的Base Address,一個Segment的最大長度是64 KB,這是16-bit系統所能表示的最大長度。而Offset則是相對於此Segment Base Address的偏移量。Base Address+Offset就是一個內存絕對地址。由此,咱們能夠看出,一個段具有兩個因素:Base Address和Limit(段的最大長度),而對一個內存地址的訪問,則是須要指出:使用哪一個段?以及相對於這個段Base Address的Offset,這個Offset應該小於此段的Limit。固然對於16-bit系統,Limit不要指定,默認爲最大長度64KB,而 16-bit的Offset也永遠不可能大於此Limit。咱們在實際編程的時候,使用16-bit段寄存器CS(Code Segment),DS(Data Segment),SS(Stack Segment)來指定Segment,CPU將段積存器中的數值向左偏移4-bit,放到20-bit的地址線上就成爲20-bit的Base Address。
到了Protected Mode,內存的管理模式分爲兩種,段模式和頁模式,其中頁模式也是基於段模式的。也就是說,Protected Mode的內存管理模式事實上是:純段模式和段頁式。進一步說,段模式是必不可少的,而頁模式則是可選的——若是使用頁模式,則是段頁式;不然這是純段模式。
既然是這樣,咱們就先不去考慮頁模式。對於段模式來說,訪問一個內存地址仍然使用Segment:Offset的方式,這是很天然的。因爲 Protected Mode運行在32-bit系統上,那麼Segment的兩個因素:Base Address和Limit也都是32位的。IA-32容許將一個段的Base Address設爲32-bit所能表示的任何值(Limit則能夠被設爲32-bit所能表示的,以2^12爲倍數的任何指),而不像Real Mode下,一個段的Base Address只能是16的倍數(由於其低4-bit是經過左移運算得來的,只能爲0,從而達到使用16-bit段寄存器表示20-bit Base Address的目的),而一個段的Limit只能爲固定值64 KB。另外,Protected Mode,顧名思義,又爲段模式提供了保護機制,也就說一個段的描述符須要規定對自身的訪問權限(Access)。因此,在Protected Mode下,對一個段的描述則包括3方面因素:【Base Address, Limit, Access】,它們加在一塊兒被放在一個64-bit長的數據結構中,被稱爲段描述符。這種狀況下,若是咱們直接經過一個64-bit段描述符來引用一個段的時候,就必須使用一個64-bit長的段寄存器裝入這個段描述符。但Intel爲了保持向後兼容,將段寄存器仍然規定爲16-bit(儘管每一個段寄存器事實上有一個64-bit長的不可見部分,但對於程序員來講,段寄存器就是16-bit的),那麼很明顯,咱們沒法經過16-bit長度的段寄存器來直接引用64-bit的段描述符。
怎麼辦?解決的方法就是把這些長度爲64-bit的段描述符放入一個數組中,而將段寄存器中的值做爲下標索引來間接引用(事實上,是將段寄存器中的高13 -bit的內容做爲索引)。這個全局的數組就是GDT。事實上,在GDT中存放的不只僅是段描述符,還有其它描述符,它們都是64-bit長。GDT是Protected Mode所必須的數據結構,也是惟一的。另外,正像它的名字(Global Descriptor Table)所揭示的,它是全局可見的,對任何一個任務而言都是這樣。
 

GDT的構成:

 
GDT的結構圖以下:(GDT表至關於一個64bit的數組)
 
一、G:
(1)、G=0時,段限長的20位爲實際段限長,最大限長爲2^20=1MB
(2)、G=1時,則實際段限長爲20位段限長乘以2^12=4KB,最大限長達到4GB

二、D/B:
當描述符指向的是可執行代碼段時,這一位叫作D位,D=1使用32位地址和32/8位操做數,D=0使用16位地址和16/8位操做數。若是指向的是向下擴展的數據段,這一位叫作B位,B=1時段的上界爲4GB,B=0時段的上界爲64KB。若是指向的是堆棧段,這一位叫作B位,B=1使用32位操做數,堆棧指針用ESP,B=0時使用16位操做數,堆棧指針用SP。

三、DPL:特權級,0爲最高特權級,3爲最低,表示訪問該段時CPU所需處於的最低特權級

四、type : 類型
(1)、type<8時:數據段
 
(2)、type>=8時:代碼段
 
 

GDTR是什麼?

GDT能夠被放在內存的任何位置,那麼當程序員經過段寄存器來引用一個段描述符時,CPU必須知道GDT的入口,也就是基地址放在哪裏,因此Intel的設計者門提供了一個寄存器GDTR用來存放GDT的入口地址,程序員將GDT設定在內存中某個位置以後,能夠經過LGDT指令將GDT的入口地址裝入此寄存器,今後之後,CPU就根據此寄存器中的內容做爲GDT的入口來訪問GDT了。
 

LDT是什麼?

除了GDT以外,IA-32還容許程序員構建與GDT相似的數據結構,它們被稱做LDT(Local Descriptor Table,局部描述符表),但與GDT不一樣的是,LDT在系統中能夠存在多個,而且從LDT的名字能夠得知,LDT不是全局可見的,它們只對引用它們的任務可見,每一個任務最多能夠擁有一個LDT。另外,每個LDT自身做爲一個段存在,它們的段描述符被放在GDT中。
 LDT只是一個可選的數據結構,你徹底能夠不用它。使用它或許能夠帶來一些方便性,但同時也帶來複雜性,若是你想讓你的OS內核保持簡潔性,以及可移植性,則最好不要使用它。
 
 

LDTR是什麼?

 
IA-32爲LDT的入口地址也提供了一個寄存器LDTR,由於在任什麼時候刻只能有一個任務在運行,因此LDT寄存器全局也只須要有一個。若是一個任務擁有自身的LDT,那麼當它須要引用自身的LDT時,它須要經過lldt指令將其LDT的段描述符裝入此寄存器。lldt指令與lgdt指令不一樣的時,lgdt指令的操做數是一個32-bit的內存地址,這個內存地址處存放的是一個32-bit GDT的入口地址,以及16-bit的GDT Limit。而lldt指令的操做數是一個16-bit的選擇子,這個選擇子主要內容是:被裝入的LDT的段描述符在GDT中的索引值。
 
 
至此,咱們能夠這樣理解GDT和LDT:GDT爲一級描述符表,LDT爲二級描述符表。如圖:
例如:若是咱們想在表LDT2中選擇第三個描述符所描述的段的地址12345678h。

1. 首先須要裝載LDTR使它指向LDT2:使用指令lldt將Select2裝載到LDTR。
2. 經過邏輯地址(SEL:OFFSET)訪問時SEL的index=3表明選擇第三個描述符;TI=1表明選擇子是在LDT選擇,此時LDTR指向的是LDT2,因此是在LDT2中選擇,此時的SEL值爲1C h(二進制爲11 1 00b),OFFSET=12345678h。邏輯地址爲1C:12345678h。
3. 由SEL選擇出描述符,由描述符中的基址(Base)加上OFFSET可獲得線性地址,例如基址是11111111h,則線性地址=11111111h+12345678h=23456789h。
4. 此時若再想訪問LDT1中的第三個描述符,只要使用lldt指令將選擇子Selector 1裝入再執行二、3兩步就能夠了(由於此時LDTR又指向了LDT1)。

因爲每一個進程都有本身的一套程序段、數據段、堆棧段,有了局部描述符表則能夠將每一個進程的程序段、數據段、堆棧段封裝在一塊兒,只要改變LDTR就能夠實現對不一樣進程的段進行訪問。
 
 

段選擇子是什麼?

引用GDT和LDT中的段描述符所描述的段,是經過一個16-bit的數據結構來實現的,這個數據結構叫作Segment Selector——段選擇子。它的高13位做爲被引用的段描述符在GDT/LDT中的下標索引,bit 2用來指定被引用段描述符被放在GDT中仍是到LDT中,bit 0和bit 1是RPL——請求特權等級,被用來作保護目的。如圖所示:
 
前面所討論的裝入段寄存器中做爲GDT/LDT索引的就是Segment Selector,當須要引用一個內存地址時,使用的仍然是Segment:Offset模式,具體操做是:在相應的段寄存器裝入Segment Selector,按照這個Segment Selector能夠到GDT或LDT中找到相應的Segment Descriptor,這個Segment Descriptor中記錄了此段的Base Address,而後加上Offset,就獲得了最後的內存地址。
 
段選擇子包括三部分:描述符索引(index)、TI、請求特權級(RPL)。它的index(描述符索引)部分表示所須要的段的描述符在描述符表的位置,由這個位置再根據在GDTR中存儲的描述符表基址就能夠找到相應的描述符。而後用描述符表中的段基址加上邏輯地址(SEL:OFFSET)的OFFSET就能夠轉換成線性地址,段選擇子中的TI值只有一位0或1,0表明選擇子是在GDT選擇,1表明選擇子是在LDT選擇。請求特權級(RPL)則表明選擇子的特權級,共有4個特權級(0級、1級、2級、3級)。
關於特權級的說明:任務中的每個段都有一個特定的級別。每當一個程序試圖訪問某一個段時,就將該程序所擁有的特權級與要訪問的特權級進行比較,以決定可否訪問該段。系統約定,CPU只能訪問同一特權級或級別較低特權級的段。
例如給出邏輯地址:21h:12345678h 轉換爲線性地址的步驟以下:
(1)、選擇子SEL=21h=0000000000100 0 01b 它表明的意思是:選擇子的index=4即選擇GDT中的第4個描述符;TI=0表明選擇子是在GDT選擇;最後的01表明特權級RPL=1
(2)、OFFSET=12345678h若此時GDT第四個描述符中描述的段基址(Base)爲11111111h,則線性地址=11111111h+12345678h=23456789h
 

關係:

計算機由實模式進入到保護模式要加載gdt,保護模式下的段寄存器由16位的選擇器與64位的段描述符寄存器構成。
段描述符寄存器: 存儲段描述符;
選擇器:存儲段描述符的索引;
原先實模式下的各個段寄存器做爲保護模式下的段選擇器,80486中有6個(即CS,SS,DS,ES,FS,GS)16位的段寄存器
 
GDT能夠被放在內存的任何位置,但CPU必須知道GDT的入口,也就是基地址放在哪裏,Intel的設計者門提供了一個寄存器GDTR用來存放GDT的入口地址,程序員將GDT設定在內存中某個位置以後,能夠經過LGDT指令將GDT的入口地址裝入此積存器,今後之後,CPU就根據此寄存器中的內容做爲GDT的入口來訪問GDT了。GDTR中存放的是GDT在內存中的基地址和其表長界限。
48bit的GDTR的結構:
由GDTR訪問GDT是經過「段選擇子」(實模式下的段寄存器)來完成的,即:
GDTR(48bit)+Segment Selector(由實模式下的段寄存器充當,16bit)= GDT中的某一項 (64bit)
 
 
Tips:
(1)、GDT中的全部描述符(除0項外,包括LDT描述符這種類型的描述符)都指定一個段,GDT中的LDT描述符指定的是一個特殊的段, 這個段中只能存放LDT表,之因此說GDT中一個描述符是一個LDT段的描述符,是由於這個描述符中有屬性說明這是一個LDT段.
(2)、
GDTR是一個48位的全局描述符寄存器,高32位存放GDT的基址,低16位存放GDT限長。
LDTR是一個16位的局部描述符寄存器,高13位存放LDT在GDT中的索引值。
GDT相似於一個 「數組」 ,「數組元素」 能夠是段描述符,也能夠是LDT描述符。

例如:
若給定一個邏輯地址是 a:b ,根據邏輯地址的a(段選擇符)的T1位肯定是選擇GDT仍是LDT。
a、如果T1位選擇GDT,根據GDTR找到GDT的基址,根據a的 3~15位肯定它的段描述符X在GDT中的位置(GDTR即基址+a的3-15bit即相對位置):肯定段描述符X,再根據段描述符提取出其中包含的段基址信息,段基址+b(段內偏移),最終肯定線性地址。
2)如果T1位選擇LDT,根據GDTR找到GDT的基址,根據LDTR的高13位肯定它的LDTX描述符在GDT中的位置(GDTR基址+LDTR13bit即相對位置):肯定LDTX描述符。LDTX描述符能夠肯定LDT的基址(LDTX描述符肯定LDT表在內存中的起始位置),再根據段選擇符a肯定的相對位置,能夠肯定LDT中的私有段描述符Y。接下來同上面的:再根據段描述符提取出其中包含的段基址信息,段基址+b(段內偏移),最終肯定線性地址。

GDT中包含的段描述符X和LDT中包含的私有段描述符Y,所佔空間相同。
GDT中包含的段描述符X和GDT中包含的LDT描述符,所佔用空間相同。
結論是:LDT不包含在GDT中。GDT中只是包含了LDT描述符(一個指向LDT起始地址的指針)。
相關文章
相關標籤/搜索