【硬核】MMU是如何完成地址翻譯的

嵌入式與Linux那些事發表於2021-08-03

虛擬記憶體是現代作業系統中最偉大的發明之一。它為每個程式提供了一個一致的、私有的地址空間,讓每個程式產生了一種自己在獨享主存的錯覺。

為了講清楚MMU是如何一步一步完成地址翻譯,取出資料的,本篇文章在前4節中講解了虛擬記憶體中一些重要的概念,比如,虛擬記憶體的作用,頁命中,缺頁異常處理,為什麼需要TLB等等。最後,通過兩個地址翻譯的例子,詳細解釋了MMU地址翻譯的過程。

1. 什麼是虛擬記憶體?

  • 虛擬記憶體能夠建立一個連續的更大的空間給程式使用,出現的原因是由於主存的空間是有限

  • 當執行多個程式或者一個程式需要更大的空間進行儲存執行,主存顯然是不夠的,這個時候就需要更大更便宜的磁碟進行儲存一部分資料。

  • 對於程式來說,虛擬記憶體就是一張連續的記憶體空間,這個空間有些在主存中,有些在磁碟中。

2. 虛擬記憶體的作用

  • 虛擬記憶體將主存看成是一個儲存在磁碟上的地址空間的快取記憶體,在主存中只儲存活動區域,並根據需要在磁碟和主存之間來回傳送資料,通過這種方式,可以高效地使用主存

  • 虛擬記憶體為每個程式提供了一致的地址空間,簡化了記憶體管理。

  • 虛擬記憶體保護了每個程式的地址空間不被其他程式破壞。

3. 虛擬記憶體與實體記憶體

3.1 CPU存取資料

CPU通過MMU找到虛擬地址對應的實體地址

我們先來看下,CPU是如何根據地址取得資料的。

CPU 在這裡生成的實體地址為 4,把地址傳送給記憶體,然後記憶體從該地址獲取其中儲存的字,最後將其傳送回 CPU。

MMU(Memory Management Unit)叫做記憶體管理單元,主要用來管理虛擬記憶體與實體記憶體的對映,由硬體自動完成。

3.2 實體地址常用術語

實體地址

這裡需要比較燒腦地介紹幾個名詞,後面理解MMU地址翻譯的時候會用到

  • 實體記憶體(physical memory),主存RAM,實際能使用的物理空間。
  • 物理頁(physical page),把實體記憶體按照頁表的大小進行劃分。
  • 實體地址(physical address,PA), 實體記憶體劃分了根據物理頁劃分為很多塊,通過實體地址進行定位。
  • 物理頁號(physical page number,PPN) ,定位快取中的資料字。
  • 物理頁號偏移 (physical page offset, PPO),定位快取中的資料塊。
  • 快取標記(cache tag,CT),在快取記憶體中作為行匹配。
  • 快取索引(cache index,CI),在快取記憶體中作為組索引。
  • 快取偏移(cache offset,CO),在快取記憶體中用作行內偏移來選擇目的資料塊。
  • 物理頁號偏移PPO = 組索引CI + 行內偏移CO。
  • 物理頁號PPN = 行匹配CT。
  • 實體地址 PA = 物理頁號 + 物理頁號偏移 = PPN * page size + ppo。

3.3 虛擬地址常用術語

虛擬地址

  • 虛擬記憶體(virtual memory),每個程式獨有,存放在磁碟上,由多個虛擬頁(VP, virtual page)組成。
  • 虛擬記憶體的地址編碼稱虛擬地址空間(virtual address space VAS),跟實體記憶體一樣,但虛擬記憶體是每個程式獨有的,其大小是根據作業系統的指令集位有關,如32位,64位,32位,每個程式就有4G,64位有個百億的GB。
  • 虛擬頁(virtual page,VP ),把虛擬記憶體按照頁表的大小進行劃分。
  • 虛擬地址(virtual address),通俗說是計算機程式載入地址的指令,程式給的虛擬地址通過MMU進行獲取地址計算實體地址空間,然後獲取實體地址對應的資料傳送到CPU上。
  • 虛擬頁號(virtual page number ,VPN) ,用於定位頁表的PTE。
  • 虛擬頁號偏移(virtual page offset VPO) ,跟PPO值一樣,定位實體記憶體的地址。
  • TLB索引(TLB index,TLBI),在頁表中作為組索引。
  • TLBT標記(TLB tag,TLBT),在頁表中作為行匹配。
  • 虛擬頁號VPN = TLBT + TLBI。
  • 虛擬地址 VA = 虛擬頁號 + 虛擬頁號偏移 。

3.4 頁表常用術語

頁表

  • 頁表(page tables),虛擬地址與實體地址的對應表集合。程式虛擬地址轉換成實體地址,程式需要用到資料放在物理主存或磁碟某個位置,頁表是儲存在主存中。

  • 頁表條目(page table entry PTE),虛擬地址與實體地址具體對應記錄。頁表是由多個頁表條目PTE組成的陣列,PTE 由一個有效位 和 n位地址欄位組成,如果設定了有效位,那麼地址欄位就標識DRAM中相應的物理頁的起始位置。

3.5 頁命中/缺頁

頁命中

  1. 處理器產生一個虛擬地址。
  2. MMU生成PTE地址,並從快取記憶體/主存請求得到它。
  3. 快取記憶體/主存向MMU返回PTE。
  4. MMU構造實體地址,並把它傳送給快取記憶體/主存。
  5. 快取記憶體/主存返回所請求的資料字給處理器。

缺頁

  1. 處理器產生一個虛擬地址。
  2. MMU生成PTE地址,並從快取記憶體/主存請求得到它。
  3. 快取記憶體/主存向MMU返回PTE。
  4. PTE中的有效位是零,所以MMU觸發了一次異常,傳遞CPU中的控制到作業系統核心中的缺頁異常處理程式。
  5. 缺頁處理程式確定出實體記憶體中的犧牲頁,如果這個頁面已經被修改了,則把它換出到磁碟。
  6. 缺頁處理程式頁面調入新的頁面,並更新記憶體中的PTE。
  7. 缺頁處理程式返回到原來的程式,再次執行導致缺頁的指令。CPU將引起缺頁的虛擬地址重新傳送給MMU。因為虛擬頁面現在快取在實體記憶體中,所以就會命中,主存就會將所請求字返回給處理器。

4. 為什麼有了快取記憶體,還需要TLB呢?

區域性性原則保證了在任意時刻, 程式將往往在一個較小的活動頁面集合上工作,這個集合叫做工作集或者常駐集。

換句話說, 區域性性原則揭示了一個現象:在一段時間內,我們會反覆調入或調出同一個或幾個虛擬頁頁面。而且,每次CPU產生一個VA時, MMU就必須查閱PTE,以便將VA翻譯為PA, 注意是每次,所以開銷很大

解決方法: 為了消除這樣的開銷,在MMU中包括了一個關於PTE的小快取,稱為翻譯後備緩衝器,TLB(Translation Lookaside Buffer)。

關鍵點: 所有的地址翻譯步驟都是在晶片上的MMU中執行的, 因此執行速度非常快。

說了這麼多,下面就是本文的重點,我們看兩個例子,虛擬地址是如何轉換為實體地址的。

5. MMU是如何完成地址翻譯的?

5.1 準備工作

5.1.1 記憶體系統的基本條件

簡單記憶體系統的地址組成

假設我們有一個簡單記憶體系統,我們做出如下規定:

  • 虛擬地址(VA):14 位

  • 實體地址(PA): 12 位

  • 頁面大小:64 位元組

  • 虛擬頁號(VPN):8位

  • 虛擬頁面偏移量(VPO): 6 位(64 = 2^6)

  • 物理頁號(PPN):6位

  • 物理頁偏移量(PPO):6位

5.1.2 TLB

TLB

假設TLB 有 16 個條目,並且是 4 路組相連的。TLB 快取的是頁表條目,頁表條目是虛擬頁號的唯一標識。所以,我們只需要用虛擬頁號去訪問 TLB。

我們使用 VPN 的低兩位(2^2=4)作為組索引。剩下的6位作為標記位。然後用不同的值來初始化 TLB。

左邊的紅色區域(第一個列)並不是 TLB 的條目,僅僅是為了方便區分是哪一組

我們只根據索引來查詢組,每一個條目都有一個標記位。一個 TLB 條目如果有效,它就含有一個實體地址。

5.1.3 頁表

頁表的前 16 個條目

現在,我們還需要頁表。假設,圖中是我們頁表的前 16 個條目。每一個頁表有一個物理頁號和一個有效位

如果有效位有效,則表示那個虛擬頁面對應的物理頁面在記憶體中,並且 PPN 項給出了對應的物理頁號。

5.2 產生虛擬地址

CPU產生的虛擬地址

假設 CPU 執行了一條指令,它產生了一個有效地址 0x3d4。它把這個地址傳遞給了 MMU。

我們需要找出對應的實體地址,然後從快取或記憶體中取出資料

在這個例子中,虛擬頁面偏移(VPO)是0x24,虛擬頁號(VPN)是 0xf,TLB 索引(TLBI)是虛擬頁號的低兩位是 0b11,也就是 0x3。TLB 標記位(TLBT)是 3。

TLB

MMU 做的第一件是就是查詢 TLB,所以,我們先取出索引位,值為 3。

我們找到第 3 組,我們在第 3 組中找標記位為 3 的表項

遍歷這 4 個條目,有一個標記位為 7 的項,但它不是我們想要的,它的有效位為 0。再往後找,找到一個標記位為 3 並且有效位為 1

所以,我們在 TLB 中找到了頁表條目。頁表條目返回這個值。MMU 返回的物理頁號是 0x0D

5.3 構造實體地址

構造實體地址

現在我們可以構造實體地址,PPO的值總是等於VPO的值,可以直接拷貝過來,為0x24。

PPN的值從 TLB 快取的 PTE 中得到,為0x0d。合在一起構成了實體地址 0x354

下一步是使用這個實體地址去看快取記憶體中有沒有這個實體地址的快取。

5.4 遍歷快取記憶體

把 0x354送入快取記憶體,請求快取記憶體返回對應實體地址上的值,在這個例子中,我們只需要返回一個位元組。

快取記憶體

快取記憶體收到請求後,首先去檢查快取記憶體中是否有塊快取了該位元組

快取記憶體先取出實體地址的索引位是 0b00101,也就是 0x5。

接著去第 5 組找。找標記位為 0xd 的項,有一個匹配的標記位且有效位為 1。這就是我們要在快取記憶體中找的項。

偏移量是 0,所以我們去請求第五組偏移量為 0 的位元組,值為 0x36。

快取命中,快取記憶體把這個位元組返回給 MMU, MMU 把它傳遞給處理器。最後處理器可能把這個位元組儲存在一個暫存器裡。

以上就是一個完整的地址翻譯的例子,在這個例子中,並沒有出現缺頁的情況。

下面我們看一個在缺頁異常處理中,是如何完成地址翻譯的。

5.5 缺頁處理

好了,我們來看下一個例子。這次 CPU 傳送給 MMU 的虛擬地址是 0x0020。

虛擬地址0x0020

和之前的例子一樣,我們可以得到VPN為0x00,VPO為0x01,TLBI為0,TLBT為0x00。

TLB

第一步是檢查 TLB 看是否有頁表條目的快取

在 TLB 中,如果快取存在,它應該在第一組,並且它的標記位應該為 0。所以,我們在第 0 組內找標記位為 0 的項。

第一項是 0x03,不匹配,第二項是 0x09,不匹配,第三項是 0x00,匹配,但是有效位為 0。所以,這次 TLB 快取不命中

TLB不命中只能去頁表中查詢

查詢快取失敗了,我們只能去記憶體中去讀取頁表中對應的頁表條目

檢視頁表,尋找虛擬頁號為 0 的項。檢查對應的頁表條目,看虛擬頁是否在記憶體中

虛擬頁號為 0 的項的有效位為1,我們就可以得到一個物理頁號為0x28。根據物理頁號和物理頁面偏移量就可以構造出實體地址。

構造實體地址

現在 MMU 擁有了實體地址,就可以將其傳送到快取記憶體。並請求快取記憶體返回對應的實體地址上的一個位元組。

構造出的實體地址

快取記憶體得到了這個實體地址。它取出對應的索引位,在這個例子中是 0x8。

所以我們去快取記憶體的第八組,然後尋找對應的標記位,在這個例子中是0x28。

快取記憶體

第八組有一個條目,它的標記位是 24,這裡是一次快取不命中

所以,快取就要向記憶體傳遞實體地址去得到所需要的位元組。相關內容本篇就不再做具體講解,可以參考下這篇文章。24張圖7000字詳解計算機中的快取記憶體

6. 總結

虛擬儲存器的工作原理是有一些複雜,本文描述的也並不全是最真實的計算機中的工作方式,比如,PTE由一個有效位和一個地址欄位組成其實是為了便於理解而假設出來的。

但是這種方式成功的解決了直接使用實體記憶體會出現的問題。比如,虛擬記憶體中連續儲存解決了實體記憶體碎片化,資源利用率過低的問題;每個程式只能訪問自己獨立的使用者空間而核心空間是共用的解決了程式間的安全問題;缺頁異常和選擇犧牲頁的演算法提高了記憶體讀寫的效率等等。

我們應該對虛擬儲存器的工作原理有深層次的理解,可以更好的幫助我們理解系統是如何工作的,也可以幫助我們避免在使用malloc這類的管理虛擬儲存器的分配程式時遇到的一些錯誤。

本文參考 《深入理解計算機系統》

相關文章