4、保護模式以內存分段管理機制

    以個人理解,內存的分段管理機制,就是人爲的把內存分紅幾個小段(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 的數據段和代碼段設置所有線性空間就能夠了。

相關文章
相關標籤/搜索