以個人理解,內存的分段管理機制,就是人爲的把內存分紅幾個小段(Segment),各段獨立使用。
程序員
爲何要把內存分紅不少小段使用呢?緣由一是要多個程序同時運行:開QQ勾搭妹子,開網易雲音樂聽歌,開瀏覽器看網頁。。。。。。好幾個程序一塊兒開着呢!若是幾個程序都用同一塊內存,那就亂了!因此,把內存分紅幾段:QQ用一段,別的程序不能訪問;網易雲音樂用另外一段,其餘程序也不能訪問。。。。。。緣由二是不一樣程序的權力不同:操做系統能夠啓動、關閉應用程序,應用程序可不能對操做系統指手畫腳,也就是各段內存的被訪問權限是不一樣的。瀏覽器
很明顯,要準肯定義一個段要三個參數:該段從物理內存的哪一個位置開始(段開始的實際內存地址)、該段佔用多大的內存空間(段的長度)、該段能被哪些程序訪問(段的屬性),用專業術語說就是段基址(Segment Base)、段界限(Segment Limit)、段屬性(Segment Attritbute)。數據結構
用一個數據結構來描述段的三個屬性,這個數據結構就叫段描述符(Descriptor)。因爲歷史的緣由(爲了和80286兼容),這個數據結構看起來至關糾結:三個參數居然不各自獨立連續存放,而是被拆開混存的!spa
; 段描述符圖示操作系統
;orm
; ------ ┏━━┳━━━┓內存高地址索引
; ┃ 7 ┃ 段 ┃ip
; ┣━━┫ 基 ┃內存
; ┆ ┆ 址 ┆it
; 字節 ┆ ┆ 高 ┆
; 7 ┣━━┫ 8 ┃
; ┃ 0 ┃ 位 ┃
; ------ ┣━━╋━━━┫
; ┃ 7 ┃ G ┃
; ┣━━╉━━━┨
; ┃ 6 ┃D/B┃
; ┣━━╉━━━┨
; ┃ 5 ┃ 未 ┃
; ┣━━┫ 定 ┃
; ┃ 4 ┃ 義 ┃
; 字節 ┣━━╉━━━┨
; 6 ┃ 3 ┃ ┃
; ┣━━┫ 段 ┃
; ┃ 2 ┃ 界 ┃
; ┣━━┫ 限 ┃
; ┃ 1 ┃ 高 ┃
; ┣━━┫ 4 ┃
; ┃ 0 ┃ 位 ┃
; ------ ┣━━╋━━━┫
; ┃ 7 ┃ P ┃
; ┣━━╉━━━┨
; ┃ 6 ┃ D ┃
; ┣━━┫ P ┃
; ┃ 5 ┃ L ┃
; ┣━━╉━━━┨
; ┃ 4 ┃ S ┃
; 字節 ┣━━╉━━━┨
; 5 ┃ 3 ┃ ┃
; ┣━━┫ T ┃
; ┃ 2 ┃ Y ┃
; ┣━━┫ P ┃
; ┃ 1 ┃ E ┃
; ┣━━┫ ┃
; ┃ 0 ┃ ┃
; ----- ┣━━╋━━━┫
; ┃23┃ ┃
; ┣━━┫ ┃
; ┃22┃ 段 ┃
; ┣━━┫ 基 ┃
; ┆ ┆ 址 ┆
; 字節 ┆ ┆ 低 ┆
; 2,3 ┣━━┫ 24 ┃
; 4 ┃ 1 ┃ 位 ┃
; ┣━━┫ ┃
; ┃ 0 ┃ ┃
; ----- ┣━━╋━━━┫
; ┃15┃ ┃
; ┣━━┫ ┃
; ┃14┃ 段 ┃
; ┣━━┫ 界 ┃
; ┆ ┆ 限 ┆
; 字節 ┆ ┆ 低 ┆
; 0,1 ┣━━┫ 16┃
; ┃ 1 ┃ 位 ┃
; ┣━━┫ ┃
; ┃ 0 ┃ ┃
; ------ ┗━━┻━━━┛內存低地址
段基址和段界限好理解。段屬性包含的內容好多,今天先跳過無論,之後再補吧!
從上面的宏知道一個段描述符長 8 字節,即 8 * 8 = 64 位。若是直接經過一個 64 位的段描述符來引用一個段的時候,就必須使用一個 64 位長的段寄存器裝入這個段描述符。但Intel爲了保持向後兼容,將段寄存器仍然規定爲 16 位,找不到 64 位長度的段寄存器來直接引用 64 位的段描述符。怎麼辦?
既然內存被分紅了不少段,每一個段都由一個段描述符定義,這些個數量不定的段描述符能夠用線性表來存儲。這個存放描述符的線性表就叫段描述符表(Descriptor Table)。要引用描述符表中的某一項,只要知道該描述符在描述符表中的序號就行,即描述符索引(Index),專業術語叫段選擇子(Segment Selector)。如今好辦了,舊的 16 位段寄存器就能夠經過將段寄存器中的值做爲下標索引來間接引用 64 位的段描述符了。
實際上,段選擇子裏除了放了描述符索引以外,還存了描述符表指示位(Table Index)、請求特權級(Requested Privilege Level)。一個段選擇子 16 位,低 2 位(第0、1位)存放請求特權級,用於特權檢查;第 2 位存放描述符指示位,= 0 表示從全局描述符表中讀取描述符, = 1 表示從局部描述符表中讀取描述符;高 13 位存放描述符索引,即描述符在描述符表中的序號。管理所有物理內存的描述符表叫全局描述符表(Global Descriptor Table,GDT)。實際上,在 GDT 中存放的不只僅是段描述符,還有其它描述符。
還有兩個問題,描述符表和段選擇子放在哪裏呢?怎麼訪問呢?
描述符表必然是放在內存裏的,並且能夠被放在內存的任何位置。實際上全局描述符表自己也佔用一個內存段,只不過這個段比較特殊,不能用一個段描述符定義後做爲一個表項存放到別的描述符表中去。全局描述符表須要在定義後,程序員本身保存其基址和界限。有一個寄存器 GDTR 專門用來存放 GDT 的入口地址,能夠經過 LGDT 指令將 GDT 的入口地址裝入此寄存器,CPU 根據此寄存器中的內容做爲 GDT 的入口來訪問 GDT。
段選擇子存放在段寄存器裏!實模式下段寄存器裏存放段地址,保護模式下段寄存器裏存放段選擇子,段寄存器的值就是段選擇子。要訪問內存的某個段,先要把該段的選擇子加載到某一個段寄存器。CPU 提供了 6 個段寄存器:CS、DS、SS、ES、FS、GS,即同一時刻有 6 個段可供當即訪問。實際上每一個段寄存器都支持某種特定類型(代碼、數據、堆棧)的內存引用:代碼段 CS,數據段 DS,堆棧段 SS,輔助數據段 ES、FS、GS。
有兩點建議:
一、LDT 只是一個可選的數據結構,你徹底能夠不用它。使用它或許能夠帶來一些方便性,但同時也帶來複雜性,若是你想讓你的OS內核保持簡潔性,以及可移植性,則最好不要使用它。
二、若是一個 OS 不使用虛擬內存,段模式會是一個不錯的選擇,無需考慮頁模式(實際是段頁模式)。
在啓動階段只須要初步設置一下 GDT,等真正進入保護模式,啓動了 Kernel 以後,具體 OS 打算如何設置 GDT,使用何種內存管理模式,由 Kernel 自身來設置,啓動只須要給 Kernel 的數據段和代碼段設置所有線性空間就能夠了。