首先我們要注意的是虛擬空間分為核心空間和使用者空間。
1. 從邏輯位址到線性位址的轉換
對於linux來說,基本不使用分段的機制,或者說,linux中的分段機制只是為了相容ia32的硬體而設計的。
linux核心的設計並沒有全部採用intel所提供的段方案,僅僅有限度地使用了一下分段機制。這不僅簡化了linux核心的設計,而且為把linux移植到其他平台創造了條件。
在 ia32 上任意給出的位址都是乙個虛擬位址,即任意乙個位址都是通過「選擇符:偏移量」的方式給出的,這是段機制存訪問模式的基本特點。所以在ia32上設計作業系統時無法迴避使用段機制。乙個虛擬位址最終會通過「段基位址+偏移量」的方式轉化為乙個線性位址。 但是,由於絕大多數硬體平台都不支援段機制,只支援分頁機制,所以為了讓 linux 具有更好的可移植性,我們需要去掉段機制而只使用分頁機制。但不幸的是,ia32規定段機制是不可禁止的,因此不可能繞過它直接給出線性位址空間的位址。萬般無奈之下,linux的設計人員乾脆讓段的基位址為0,而段的界限為4gb,這時任意給出乙個偏移量,則等式為「0+偏移量=線性位址」,也就是說「偏移量==線性位址」。即 邏輯位址==線性位址。
段機制把邏輯位址轉換為線性位址,分頁機制進一步把該線性位址再轉換為實體地址。
2. 從線性位址到實體地址的轉換
先來普及一些基礎知識:
虛擬位址空間是根據cpu的位數而定,當cpu的位數為32位,虛擬位址空間總共是2^32次方,即4g大小。
cpu的位數越大,cpu處理數字的運算能力就越強,位數指的是資料匯流排的條數,資料匯流排與位址匯流排相同是比較好的一種情況
cpu的指令集(mov lea add call )可以使cpu明白自己需要完成的是什麼事
在8086處理器誕生之前,記憶體定址方式就是直接訪問實體地址。8086處理器為了定址1m的記憶體空間,把位址匯流排擴充套件到了20位。但是,乙個尷尬的問題出現了,alu的寬度只有16位,也就是說,alu不能計算20位的位址。為了解決這個問題,分段機制被引入。
x86體系:
1. 未保護模式下(8086處理器為代表):
在 8086 的實模式(未保護模式)下,把某一段暫存器左移4位,然後與位址addr相加後被直接送到記憶體匯流排上,這個相加後的位址就是記憶體單元的實體地址。
ds<<4 + ip(偏移量) = 實體地址(不安全,ds可能被修改)
保護模式的出現:
80386處理器是乙個32位處理器,alu和位址匯流排都是32位的,定址空間達 4g。也就是說它可以不通過分段機制,直接訪問4g的記憶體空間。然而由於相容之前的處理器。因此必須支援實模式和保護模式。所以80386要在段暫存器的基礎上構築保護模式,並且保留16位的段暫存器。
從80386之後的處理器,架構基本相似,統稱為ia32(32 bit intel architecture)。
2.保護模式下
在ia32的保護模式下,邏輯位址不是被直接送到記憶體匯流排而是被送到記憶體管理單元(mmu)。mmu由乙個或一組晶元組成,其功能是把邏輯位址對映為實體地址,即進行位址轉換。
保護模式下三個位址的關係:
ia32下設定了6個段暫存器,段暫存器中儲存的是段選擇符:
* 段選擇符:*
gdt和ldt
1)根據指令的性質判斷它是在哪個段暫存器中
2)檢查段暫存器的ti欄位,看其屬於ldt還是gdt
3)根據段暫存器的index,將段暫存器中的位址右移3位,計算段描述符的位址
4)在記憶體管理暫存器ldtr和gdtr中分別找ldt和gdt的位址,每個位址對應乙個段暫存器和乙個記憶體管理暫存器
5)將指令發出的位址作為位移,與段描述符表項進行對比,檢視是否越界
6)根據指令的性質和段描述符中的許可權,檢視是否越權
7)將ip偏移量(邏輯位址)與gdt[ds >> 3] 相加可得到線性位址
gdt[ds >> 3].baseaddr + 邏輯位址 = 線性位址
如果作業系統只開啟記憶體分段: 線性位址== 實體地址
如果作業系統開啟了記憶體分頁: 線性位址(多級頁表對映)—>實體地址
線性位址中的相鄰位址在對映到實體地址上時,不一定是相鄰的,因為有可能不在同乙個頁面。反之亦然。
分頁機制通過把線性位址空間中的頁,重新定位到實體地址空間來進行管理,因為每個頁面的整個4k位元組作為乙個單位進行對映,並且每個頁面都對齊4k位元組的邊界,因此,線性位址的低12位經過分頁機制直接地作為實體地址的低12位使用。
對映過程:
1)從cr3中獲取得頁目錄的基位址
2)以線性位址的dir位段為下標,在目錄表中取得相應頁面表的基位址
3)以線性位址中的page位段為下標,在得到的頁面表中獲得相應頁面描述符
4)將頁面描述符項中給出的頁面基位址,與線性位址中的offset段相加得到實體地址
總結:
位址的轉換過程是通過軟體的完美配合來實現的。乙個是作業系統核心,乙個是cpu中的mmu(也可以在mmu中設定tlb,加快位址翻譯速度)。核心主要提供暫存器,頁目錄,頁表等,mmu主要負責計算過程。
要注意的是,分段機制是ia32提供的定址方式,這是硬體層面的。無論windows還是linux,只要使用ia32的cpu訪問記憶體,都需經過mmu的轉換流程才能得到實體地址,也就是說必須經過邏輯位址–線性位址–實體地址的轉換。
就ia32架構的cpu來說,就有多種分頁實現,常規分頁機制,pae機制等。linux的分頁機制是建立在硬體基礎之上的,不同的平台需要有不同的實現。linux在軟體層面構造的虛擬位址,最終還是要通過mmu轉換為實體地址,不管linux的分頁機制是怎樣實現,cpu只按照它的分頁實現來解讀線性位址,所以linux傳給cpu的線性位址必然是滿足硬體實現的。比如說:linux在32位cpu上,它的四級頁表結構就會相容到硬體的兩級頁表結構。可見,linux在軟體層面上做了一層抽象,用四級頁表的方式相容32位和64位cpu記憶體定址的不同硬體實現。
讀者也可通過工具bochs 2.6.8來計算從邏輯位址到實體地址的轉換過程。
位址對映 分段分頁
linux核心採用頁式儲存管理。虛擬位址空間劃分成固定大小的 頁面 由mmu將虛擬位址對映成某個物理記憶體頁面中的位址。一 三種不同的位址 邏輯位址經分段機制後就成線性位址 如果不啟用分頁,那麼此線性位址和實體地址相同。線性位址經分頁轉換後就成了實體地址。二 分段 1 段選擇符和段暫存器 index...
Linux下的位址對映
在cpu中設定四個 段暫存器 cs ds ss es 分別用於可執行 即指令,資料,堆疊和其他 每個段暫存器都是16位,對應位址匯流排的高16位。每條 訪內指令 的內部位址都是16位。訪內 的內部位址 16位 轉化成實際位址 20位 段暫存器中內基位址 4 內部位址 對於每乙個由段暫存器的內容確定的...
linux分段分頁機制
mmu使用分段單元硬體把邏輯位址轉換為虛擬位址,再使用分頁單元硬體把虛擬位址轉換為實體地址。因為這兩部分表示乙個獨一無二的邏輯位址,虛擬位址作為這個段位址另一種形式,當然也需要這兩個部分作為轉換的 原材料。這裡涉及乙個叫做段的暫存器,它的作用是放段選擇符 識別符號 共有六種 cs 儲存指向 的段的選...