天天看點

第七學 linux核心——記憶體尋址——段機制(1)

        x86的段機制是實作程式的邏輯位址到線性位址的映射的一種機制。

       我們先介紹實作這個機制的幾個組成部件,它包括一些軟體的東西和一些硬體的東西:硬體的東西有:段寄存器、分段部件、段描述符高速緩沖器;軟體的東西有(即幾個資料結構):段描述符表、段描述符;另外得知道的兩個概念前面已經介紹過了:邏輯位址和線性位址。

       下面我們看段機制是怎麼用這些概念實作的。

       由于段寄存器是16位的,是以它不能存儲32位的基位址,但是這32位基位址又必須得存,于是我們把這32位基址存儲到一塊記憶體中,而把這個位址的索引放段寄存器裡邊,進而得到段基址,這是大體思路。但x86做得更好。

       我們知道程式都有子產品性,一個複雜的大程式總可以分解成多個在邏輯上相對獨立的子產品或者線程。每個子產品都是一個單獨的段,都以該段的起點為0相對編址。也就是說,我們得用一個資料結構描述各個段的相關資訊,比如該段裝進記憶體的基址(段基址),該段的長度,以及該段是否存在記憶體中等資訊,這個資料結構就是段描述符。言下之意,我們每個子產品都有一個段描述符,用來描述該段的屬性,而段描述符表其實就是用來盛載這些段描述符的一個表格,一個段描述表可能長這樣:

第七學 linux核心——記憶體尋址——段機制(1)

        其中的表項就是段描述符,段描述要存儲三個資訊:基位址、段長度和段屬性。我們用8個位元組來存儲這三個資訊,首先我們說段基址是32位,是以基址占四個位元組32位,然後我們用20位來描述段長度。那麼這8個位元組64位還剩下12位,就用來存儲段的屬性資訊了。

第七學 linux核心——記憶體尋址——段機制(1)

        G:一位,G=0:表示以位元組為機關表示段的長度,剛才我們說了我們用20位存儲段的長度,那麼這樣我們段的最大長度就是2^20次方,即1M大小,即我們給程式分段的時候,一個段最大是1M。G=1:表示以4KB表示段的長度,這樣我們一個段的最大長度就是2^20次方乘以4KB,即4GB。後邊我們會知道linux核心就讓這個G等于1,進而直接越過x86的段機制,使邏輯位址沒映射線性位址,再映射到實體位址,而是直接映射到實體位址(分頁機制)。

        D:一位,表示操作數的位數,D=1表示32位操作數,D=0表示16位操作數,這顯然是為向下相容而設計的。

        接下來兩位暫時沒用,可留作擴充。

        P:一位,表示這個段是否在記憶體中,如果我們要把這個段加載進記憶體,那麼在加載進去的時候把這個值修改為1,否則讓它等于0。

       DPL:兩位,表示段描述符的特權級。

        S:一位,表示這個段是系統段還是使用者段。S=0,則為系統段,即核心專門使用的段,S=1,表示使用者段,即為程式的代碼段、資料段或堆棧段。

       類型占三位:依次是E、D、W。E=0,為資料段描述符,這時D位表示資料的擴充方向,D=0,表示向位址增大的方向擴充,反之,向位址減小的方向擴充。E=1時,直接表示的是資料段,此時W=0時表示資料段不能寫(我們就可以想到C++中定義const變量的時候,最後肯定是修改了這個值的),W=1,資料段可寫。

        保護模式下,有三種類型的描述符表,分别是全局描述符表(GDT),中段描述符表(IDT),局部描述符表(LDT)。為了加快對這些表的通路,Inter設計了三個專門的寄存器,GDTR、IDTR、LDTT,以存放這些表的基位址和表的長度界限。

      下來我們看段寄存器。我們說過段寄存器存放的就是段描述符在段描述符表中的索引,其實段寄存器還存了另外兩個資訊,這意味着,我們不能用着16位全部來存儲索引值。其實Inter隻用了13位來存儲段描述符的索引,另外還用1位标志我們是從全局描述符表(GDT)中選擇段描述符還是從局部描述符表(LDT)中選擇段描述符。剩下兩位表示請求者的特權級。

        保護模式提供了4個特權級,用0-3表示。0表示最高特權級,對應核心态,此時它可以通路核心代碼,也可以通路使用者代碼;3表示最低特權級,對應使用者态,此時它隻能通路使用者态代碼。

        下面是段機制的硬體構成:

第七學 linux核心——記憶體尋址——段機制(1)

        這樣就完成了邏輯位址到線性位址的映射。

繼續閱讀