詳解 ARM64 核心中對 52 位虛擬地址的支援

大雄45發表於2021-02-16
導讀 當 64 位硬體變得可用之後,處理更大地址空間(大於 232 位元組)的需求變得顯而易見。現如今一些公司已經提供 64TiB 或更大記憶體的伺服器,x86_64 架構和 arm64 架構現在允許定址的地址空間大於 248 位元組(可以使用預設的 48 位地址支援)。

詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援

x86_64 架構透過讓硬體和軟體啟用五級頁表以支援這些用例。它允許定址的地址空間等於 257 位元組(詳情見x86:在 4.12 核心中啟用 5 級頁表)。它突破了過去虛擬地址空間 128PiB 和實體地址空間 4PiB 的上限。

arm64 架構透過引入兩個新的體系結構 —— ARMv8.2 LVA(更大的虛擬定址) 和 ARMv8.2 LPA(更大的實體地址定址) —— 擴充來實現相同的功能。這允許使用 4PiB 的虛擬地址空間和 4PiB 的實體地址空間(即分別為 252 位)。

隨著新的 arm64 CPU 中支援了 ARMv8.2 體系結構擴充,同時現在開源軟體也支援了這兩種新的硬體擴充。

從   5.4 核心開始, arm64 架構中的 52 位(大)虛擬地址(VA)和實體地址(PA)得到支援。儘管核心文件描述了這些特性和新的核心執行時對舊的 CPU(硬體層面不支援 52 位虛擬地址擴充)和新的 CPU(硬體層面支援 52 位虛擬地址擴充)的影響,但對普通使用者而言,理解這些並且如何 “選擇使用” 52 位的地址空間可能會很複雜。

因此,我會在本文中介紹下面這些比較新的概念:

1. 在增加了對這些功能的支援後,核心的記憶體佈局如何“翻轉”到 Arm64 架構

2. 對使用者態應用的影響,尤其是對提供除錯支援的程式(例如:kexec-tools、 makedumpfile 和 crash-utility)

3. 如何透過指定大於 48 位的 mmap 引數,使使用者態應用“選擇”從 52 位地址空間接受 VA?

ARMv8.2 架構的 LVA 和 LPA 擴充

ARMv8.2 架構提供兩種重要的擴充:大虛擬定址(LVA)和大物理定址(LPA)。

當使用 64 KB 轉換粒度時,ARMv8.2-LVA 為每個翻譯表基地址暫存器提供了一個更大的 52 位虛擬地址空間。

在 ARMv8.2-LVA 中允許:

當使用 64 KB 轉換粒度時,中間實體地址(IPA)和實體地址空間擴充為 52 位。
如果使用 64 KB 轉換粒度來實現對 52 位實體地址的支援,那麼一級塊將會覆蓋 4TB 的地址空間。
需要注意的是這些特性僅在 AArch64 架構中支援。

目前下列的 Arm64 Cortex-A 處理器支援 ARMv8.2 擴充:

Cortex-A55
Cortex-A75
Cortex-A76
更多細節請參考 Armv8 架構參考手冊。

Arm64 的核心記憶體佈局

伴隨著 ARMv8.2 擴充增加了對 LVA 地址的支援(僅當以頁大小為 64 KB 執行時可用),在第一級轉換中,描述符的數量會增加。

使用者地址將 63-48 位位置為 0,然而核心地址將這些位設定為 1。TTBRx 的選擇由虛擬地址的 63 位決定。swapper_pg_dir 僅包含核心(全域性)對映,然而 pgd 僅包含使用者(非全域性)的對映。swapper_pg_dir 地址會寫入 TTBR1,且永遠不會寫入 TTBR0。

頁面大小為 64 KB 和三個級別的(具有 52 位硬體支援)的 AArch64 架構下 Linux 記憶體佈局如下:

詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援

4 KB 頁面的轉換查詢表如下:>
詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援

64 KB 頁面的轉換查詢表如下:

詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援
詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援

核心對 52 位虛擬地址的支援

因為支援 LVA 的較新的核心應該可以在舊的 CPU(硬體不支援 LVA 擴充)和新的 CPU(硬體支援 LVA 擴充)上都正常執行,因此採用的設計方法是使用單個二進位制檔案來支援 52 位(如果硬體不支援該特性,則必須在剛開始啟動時能回退到 48 位)。也就是說,為了滿足 52 位的虛擬地址以及固定大小的 PAGE_OFFSET,VMEMMAP 必須設定得足夠大。

這樣的設計方式要求核心為了新的虛擬地址空間而支援下面的變數:

VA_BITS         常量       *最大的* 虛擬地址空間大小
vabits_actual   變數       *實際的* 虛擬地址空間大小
翻轉核心記憶體佈局

保持一個單一核心二進位制檔案的設計方法要求核心的 .text 位於高位地址中,因此它們對於 48/52 位虛擬地址是不變的。因為核心地址檢測器(KASAN)區域僅佔整個核心虛擬地址空間的一小部分,因此對於 48 位或 52 位的虛擬地址空間,KASAN 區域的末尾也必須在核心虛擬地址空間的上半部分。(從 48 位切換到 52 位,KASAN 區域的末尾是不變的,且依賴於 ~0UL,而起始地址將“增長”到低位地址)

為了最佳化 phys_to_virt() 和 virt_to_phys(),頁偏移量將被保持在 0xFFF0000000000000 (對應於 52 位),這消除了讀取額外變數的需求。在早期啟動時將會計算 physvirt 和 vmemmap 偏移量以啟用這個邏輯。

考慮下面的物理和虛擬 RAM 地址空間的轉換:

詳解 ARM64 核心中對 52 位虛擬地址的支援詳解 ARM64 核心中對 52 位虛擬地址的支援

對用於除錯核心的使用者態程式的影響

有幾個使用者空間應用程式可以用於除錯正在執行的/活動中的核心或者分析系統崩潰時的 vmcore 轉儲(例如確定核心奔潰的根本原因):kexec-tools、makedumpfile 和 crash-utility。

當用它們來除錯 Arm64 核心時,因為 Arm64 核心記憶體對映被“翻轉”,因此也會對它們產生影響。這些應用程式還需要遍歷轉換表以確定與虛擬地址相應的實體地址(類似於核心中的完成方式)。

相應地,在將“翻轉”引入核心記憶體對映之後,由於上游破壞了使用者態應用程式,因此必須對其進行修改。

我已經提議了對三個受影響的使用者態應用程式的修復;有一些已經被上游接受,但其他仍在等待中:

提議 makedumpfile 上游的修復
提議 kexec-tools 上游的修復
已接受的 crash-utility 的修復
除非在使用者空間應用程式進行了這些修改,否則它們將仍然無法除錯執行/活動中的核心或分析系統崩潰時的 vmcore 轉儲。

52 位使用者態虛擬地址

為了保持與依賴 ARMv8.0 虛擬地址空間的最大為 48 位的使用者空間應用程式的相容性,在預設情況下核心會將虛擬地址從 48 位範圍返回給使用者空間。

透過指定大於 48 位的 mmap 提示引數,使用者態程式可以“選擇”從 52 位空間接收虛擬地址。
例如:

.mmap_high_addr.c
----
   maybe_high_address = mmap(~0UL, size, prot, flags,...);

透過啟用以下的核心配置選項,還可以構建一個從 52 位空間返回地址的除錯核心:

CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y
結論

總結一下:

  • 核心版本從 5.14 開始,新的 Armv8.2 硬體擴充 LVA 和 LPA 在核心中得到良好支援。
  • 像 kexec-tools 和 makedumpfile 被用來除錯核心的使用者態應用程式現在無法支援新擴充,仍在等待上游接受修補。
  • 過去的使用者態應用程式依賴於 Arm64 核心提供的 48 位虛擬地址將繼續原樣工作,而較新的使用者態應用程式通構指定超過 48 位更大的 mmap 提示引數來 “選擇加入”已接受來自 52 位的虛擬地址。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2757309/,如需轉載,請註明出處,否則將追究法律責任。

相關文章