1. 程式人生 > >Linux記憶體管理解析(一) : 分段與分頁機制

Linux記憶體管理解析(一) : 分段與分頁機制

背景 : 在此文章裡會從分頁分段機制去解析Linux記憶體管理系統如何工作的,由於Linux記憶體管理過於複雜而本人能力有限。會盡量將自己總結歸納的部分寫清晰。

從真實模式到保護模式的定址方式的不同 : 

  16位CPU的定址方式 : 在 8086 CPU 中,提供了兩類暫存器來進行定址,分別為段暫存器(例如 CS,DS,SS)和段偏移暫存器(例如 SI,DI,SP)。而這幾種暫存器的長度都為16bit,定址方式也很簡單 : cs:ip = (cs << 4 + ip)。也就是說 cs暫存器的值左移4位加上ip的值得到的就是實體地址(實體地址就是記憶體中真實的值)。

  32位CPU的定址方式 : 在80X86 CPU 中,提供了分段與分頁機制。對於CPU的定址而言,不再像 8086 CPU 那般將 段暫存器段偏移暫存器 直接運算得到結果。

  1)那麼在32位CPU中是如何定址的呢?

  i)如何開啟分頁分段模式?

    首先要介紹的就是 CR0 暫存器(如下圖):

    

 

    對於CR0來說,存在兩個bit : 

    PE位 :  如若置位(1)則表示開啟保護(分段)模式。

    PG位 : 在PE位置位的前提下置位PG位表示開啟分頁模式。

  ii)分段機制如何進行定址(得到線性地址)?

    簡述 : 段暫存器(例如CS) 裡面存在一個索引(index),它會根據GDTR暫存器找到一個表(GDT),然後這個表裡面有元素,元素內部含有段基址。而這個段基址加上段變址暫存器的值就直接得到了線性地址的值。

    詳述 :

    在開啟分段模式之後,段暫存器裡面的值的含義就不再只是一個簡單段基址了(也就是 (cs << 4)得到段基址),當下段暫存器載入的值稱為段選擇子,結構如下:

    

    可以看到這裡有一個由幾個bit組成的 描述符索引(也就是簡述裡所說的index),以及TI和RPL位(但目前不用管它)。

    GDTR : 

    

    可以看到GDTR和IDTR(這個其實是另一個類似於GDTR的暫存器)都是由線性基地址和表長度組成,線性基地址也就是說這個表的頭部所在的線性基地址(類似於陣列名),表長度也就是這個表的長度啦。

    那麼自然我們就能得到一個類似於陣列(由連續的地址組成)的表。

    對於這個"陣列"來說,它的元素則被稱為 段描述符:

    

    可以看到段描述符很長(一共64bit)...但是沒關係,我們當下只需要把其分為三個部分 : 段基地址,段限長,段屬性。即可。(這裡之所以基地址和段限長啥的分了幾個部分主要是因為歷史遺留問題,但是沒關係,他們只不過需要把幾個分開的連在一起就能得到了真正的段基地址了)。

    那麼得到了段基址,我們自然將其與段變址暫存器內的值相加就得到了線性地址了!

    iii)分頁機制如何進行定址(得到實體地址)?

    如若我們開始分頁了,那麼就表示我們已經得到了一個線性地址(分頁是在分段的基礎上進行的)。

    簡述 : 首先我們把線性地址分為幾個部分,目錄(本質是頁目錄表的索引),頁面(本質是頁表的索引),頁內偏移(本質是偏移量)。

    由 CR3暫存器 作為 頁目錄表 的指標,通過CR3暫存器就可以得到一個表稱為頁目錄表,頁目錄表內元素 稱為 頁目錄項, 頁目錄項本質也是一個指標,指向一個 頁表, 而頁表內元素稱為頁表項,頁表項記憶體在著 頁基地址, 實體地址 = 頁基地址(物理基地址) + 頁內偏移(物理偏移地址)。

    簡單來說我們可以把 頁目錄表和頁表想象成一個二維的陣列。頁目錄表元素是頁表(一維陣列),頁表元素則是頁基地址。 

    

    我們只需要有兩個元素(頁目錄表索引和頁表索引)就可以得到一個物理(頁)基地址,然後我們再將 頁內偏移加上物理基地址,就得到了真正的實體地址了!而一個頁在80x86中是4K大小(頁基址 至 頁基址 + 4K 為一頁)。所以記憶體管理的頁也是4K大小。

    附圖(暫存器資料) :

    

    由圖我門可以知道,頁基地址(頁幀),是4K對齊的(2^12 = 4K),也就是說頁表項內只有12 - 31位是頁基地址,其他的位是頁屬性,每次通過頁表項計算實體地址只需要將 0 - 11位復位(0),即可。

    對於頁屬性 : 表述這個頁的許可權之類的,因為有的頁面是屬於核心才能去使用的。更重要的一點是 : 這個頁是否存在。

    頁目錄和頁表的表項格式:

  

    如圖所示 : 我們可以知道當 P位 被置位則表示頁面存在,當 P位復位(為0) 則表示頁面不存在,如若頁面不存在,那麼就會產生缺頁中斷,執行缺頁中斷處理程式。

&n