您好,登錄后才能下訂單哦!
Linux系統中怎么實現內存管理,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
在8086處理器誕生之前,內存尋址方式就是直接訪問物理地址。這就是直觀的令人能很好理解的訪問模式,cpu中的地址值就是我們要訪問的內存的地址值。我們稱之為cpu的實模式。
由于8086處理器想要訪問1MB(220)的內存,但是以前處理器只有16位(216=64kB),所以在8086時,設計師將CPU的地址總線升級為20位,但是,問題在于ALU只能處理16位數據,這時就想出了新的地址訪問方法,就是分段機制。
分段機制:就是將整個一塊內存分成幾個段:CS, DS, SS, ES(代碼段,數據段,堆棧段,附加段)。然后每個段內空間就變小,就可以對內存進行正常訪問了。基本原理就是分段越多,段內需要訪問的地址范圍就越小。
所以,8086采用分段機制以后,物理地址的訪問就變成,首先需要知道要訪問的是哪個段,那個段的首地址是多少,然后在這個段內我需要訪問的位置離首地址有多遠。具體實現:物理地址=(段的首地址<<4) +段內偏移
因為寄存器是16位,而CPU總線為20位,所以從段寄存器中讀出16位的段首地址放到CPU20位中的高16位。也就是說段首地址一定是24(16k)的倍數。然后再加上段內偏移就是我們CPU需要訪問內存的實際地址。
重要問題:為什么是將段首地址向上移動4位而不是16位(整個段的長度)?
因為這里工程師進行設計的時候,只有20位的數據總線位數和16位的寄存器及ALU位數。沒有20-16=4位的寄存器。所以工程師要利用16位合成20位。這里就想到了將一個16位放到20位的高16.將另一個16位放到20位的低16位。然后相加就是我們的尋址地址。這樣做出現的問題就是每個段并不是獨立的,而是重疊的。
舉個例子。假設要訪問030H地址的內存空間,可以使用段1的首地址:010H,段偏移是020H,則030H=010H+020H。
也可以使用段2的首地址:00H,段偏移是030H,則030H=000H+030H. 總之要想訪問某個物理地址,只要湊出合適的段基地址和段內偏移地址,其和為該物理地址就行了。
因為段是重疊的,不同段可以訪問到重疊地址的數據,所以在定義段的時候加上了段長數據來使不同段不重合。
隨著時代的發展,出現了80386處理器是一個32位處理器,通常我們所說的CPU位數是指ALU可以處理數據的位數,通用寄存器的位數,數據總線的寬度中最小的一位。ALU和地址總線都是32位的,尋址空間達 4G。也就是說它可以不通過分段機制,直接訪問4G的內存空間。但是為了兼容以前的訪問模式,也為了方便其自己的內存訪問,所以該處理器提供了兩種內存訪問模式:實模式和保護模式(分段機制)。所以其保留了幾個分段寄存器CS,DS,SS,ES。
實模式特點:
CPU剛上電時是出于實模式之下的,CPU訪問的地址就是輸入的物理。
實模式的物理地址=16位段基址<< 4 + 16位段偏移量
實模式下對任意段都具有讀寫權限。
實模式下可以訪問的內存大小為1M(0x00000-0xfffff)
80386處理器提供的這種具有兩種內存訪問模式:實模式和保護模式。保留幾個16位的分段寄存器的機制就是成為IA32架構。
在 8086 的實模式下,把某一段寄存器左移4位,然后與地址ADDR相加后被直接送到內存總線上,這個相加后的地址就是內存單元的物理地址,而程序中的這個地址就叫邏輯地址(或叫虛地址,就是CPU輸出程序員寫入的地址)。在IA32的保護模式下,這個邏輯地址不是被直接送到內存總線而是被送到內存管理單元(MMU)。MMU由一個或一組芯片組成,其功能是把邏輯地址映射為物理地址,即進行地址轉換,如圖所示。
MMU是一種硬件電路,它包含兩個部件,一個是分段部件,一個是分頁部件,在此,我們把它們分別叫做分段機制和分頁機制,以利于從邏輯的角度來理解硬件的實現機制。分段機制把一個邏輯地址轉換為線性地址;接著,分頁機制把一個線性地址轉換為物理地址。
IA32中有六個16位段寄存器:CS, DS, SS, ES,FS, GS.跟8086的段寄存器不同的是,這些寄存器存放的不再是某個段的基地址,而是某個段的選擇符(Selector)。
1.GDT與GDTR的出現
隨著CPU和操作系統的發展,人們對內存訪問的要求越來越高,不僅僅要求能夠訪問到內存,還要求要對內存進行訪問權限,段的大小等屬性的設置與查看等。所以80386處理器與8086處理器的分段模式并非完全相同的,而是進行了相當大的改進,把分段目的從能訪問到更大內存轉變成了對內存的訪問能進行控制,實現段保護,所以成為保護模式。
但是16位的段寄存器還是存儲的信息是完全不夠的,所以CPU規定操作系統必須提供一個表,這個表中存儲了每個段的的段描述符(段描述符中包括了:段的基地址,段的界限,段的保護屬性)。這張表就是我們稱的GDT表。所以,我們就減輕段寄存器的工作,只需要其找到這張表上的對應的段描述符既可。所以,每個CPU一定有一個GDT表,同時為了找到這張表,CPU提供一個專門的寄存器來存儲這張表的地址,成為GDTR寄存器。
2.段描述符(GDT表項)的解析
段描述符是一個8字節的數據結構。
3.實例分析
1>實驗性分析
這個是gdt表的一部分,我們可以看到,第2段和第6段分別是存放64位下的內核代碼和用戶代碼的段信息。其中保存了段大小,段的內存地址以及訪問權限等信息。
不過,通過分析,在linux中,不同段的基地址都相同,為0.代表linux只是使用了分段機制的權限保護功能,而沒有使用其訪問更大內存的功能。
2>源碼性分析
GDTR寄存器的值是GDT表的內存地址,是需要linux內核寫入的。而GDT表示屬于per cpu變量中gdt_page中存儲的。per cpu變量是每個CPU獨有的變量,是linux系統分配給cpu的。
一個邏輯地址經過分段機制轉換為一個線性地址之后,便需要分頁單元將線性地址轉換為實際的物理地址。
從80386開始,所有的80x86處理器都支持分頁。是否開啟分頁通過設置cr0寄存器的PG標志來決定,當PG為0時,表示不開啟分頁,此時線性地址唄解釋為物理地址。
分頁機制管理的對象是固定大小的存儲塊,稱之為頁(page)。分頁機制把整個線性地址空間及整個物理地址空間都看成由頁組成,在線性地址空間中的任何一頁,可以映射為物理地址空間中的任何一頁(我們把物理空間中的一頁叫做一個頁面或頁框(page frame))。
80386中每一頁的大小都為4KB,每一頁的起始地址都能被4K整除(低12位全為0)。因此,80386把4G的線性地址空間,劃分為1M個頁面。
把線性地址映射到物理地址的數據結構稱為頁表,頁表存放在主存中,由內核進行適當的初始化。
一個線性地址被分頁機制解析為三部分:目錄項(高10位),頁表(中間10位),頁內偏移量(最低12位)
cr3寄存器:存儲頁目錄基地址
目錄項:存儲在頁目錄中的偏移量
頁表(中間10位):存儲在頁表內存中的偏移量
頁內偏移量:存儲在頁內的偏移量
頁目錄:每一項都是一張頁表的基地址
頁表:每一項都是一個頁
頁:存儲數據的地方,每一個頁對應一個數據塊。
在linux中使用了4級分頁模型
看完上述內容,你們掌握Linux系統中怎么實現內存管理的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。