19. AMD 記憶體加密¶
安全記憶體加密 (SME) 和安全加密虛擬化 (SEV) 是 AMD 處理器上的特性。
SME 提供了使用標準 x86 頁表將單個記憶體頁標記為加密的能力。 標記為加密的頁面在從 DRAM 讀取時會自動解密,在寫入 DRAM 時會自動加密。 因此,SME 可用於保護 DRAM 的內容免受對系統的物理攻擊。
SEV 允許執行加密虛擬機器 (VM),其中來賓 VM 的程式碼和資料受到保護,因此只有在 VM 本身中才能獲得解密版本。 SEV 來賓 VM 具有私有記憶體和共享記憶體的概念。 私有記憶體使用來賓特定金鑰加密,而共享記憶體可以使用虛擬機器監控程式金鑰加密。 啟用 SME 後,虛擬機器監控程式金鑰與 SME 中使用的金鑰相同。
當頁表條目設定了加密位時,該頁會被加密(請參閱下文,瞭解如何確定其位置)。 加密位也可以在 cr3 暫存器中指定,從而允許加密 PGD 表。 透過在指向下一個頁表的頁表條目中設定加密位,也可以加密每個連續級別的頁表。 這允許加密整個頁表層次結構。 請注意,這表示僅僅因為 cr3 中設定了加密位,並不意味著整個層次結構都被加密。 層次結構中的每個頁表條目都需要設定加密位才能實現這一點。 因此,從理論上講,您可以在 cr3 中設定加密位以便加密 PGD,但不在 PGD 條目中設定 PUD 的加密位,這會導致該條目指向的 PUD 不被加密。
啟用 SEV 後,指令頁和來賓頁表始終被視為私有。 來賓內部的所有 DMA 操作都必須在共享記憶體上執行。 由於記憶體加密位在 64 位或 32 位 PAE 模式下執行時由來賓作業系統控制,因此在所有其他模式下,SEV 硬體強制記憶體加密位為 1。
可以透過 CPUID 指令確定對 SME 和 SEV 的支援。 CPUID 函式 0x8000001f 報告與 SME 相關的資訊
0x8000001f[eax]:
Bit[0] indicates support for SME
Bit[1] indicates support for SEV
0x8000001f[ebx]:
Bits[5:0] pagetable bit number used to activate memory
encryption
Bits[11:6] reduction in physical address space, in bits, when
memory encryption is enabled (this only affects
system physical addresses, not guest physical
addresses)
如果存在對 SME 的支援,則可以使用 MSR 0xc00100010 (MSR_AMD64_SYSCFG) 來確定是否啟用了 SME 和/或啟用記憶體加密
0xc0010010:
Bit[23] 0 = memory encryption features are disabled
1 = memory encryption features are enabled
如果支援 SEV,則可以使用 MSR 0xc0010131 (MSR_AMD64_SEV) 來確定 SEV 是否處於活動狀態
0xc0010131:
Bit[0] 0 = memory encryption is not active
1 = memory encryption is active
如果 BIOS 確定啟用記憶體加密(請參閱上面的 CPUID 資訊)導致的物理地址空間減少不會與系統的地址空間資源需求衝突,則 Linux 依賴於 BIOS 來設定此位。 如果 Linux 啟動時未設定此位,則 Linux 本身不會設定它,並且記憶體加密將無法實現。
Linux 核心中 SME 的狀態可以記錄如下
支援:CPU 支援 SME(透過 CPUID 指令確定)。
已啟用:支援且已設定 MSR_AMD64_SYSCFG 的第 23 位。
活動:支援、已啟用且 Linux 核心正在主動將加密位應用於頁表條目(核心中的 SME 掩碼非零)。
也可以在 BIOS 中啟用和啟用 SME。 如果在 BIOS 中啟用和啟用 SME,則所有記憶體訪問都將被加密,並且無需啟用 Linux 記憶體加密支援。
如果 BIOS 僅啟用 SME(設定 MSR_AMD64_SYSCFG 的第 23 位),則可以透過在核心命令列上提供 mem_encrypt=on 來啟用記憶體加密。 但是,如果 BIOS 未啟用 SME,則即使預設配置為啟用或指定了 mem_encrypt=on 命令列引數,Linux 也將無法啟用記憶體加密。
19.1. 安全巢狀分頁 (SNP)¶
SEV-SNP 引入了新特性 (SEV_FEATURES[1:63]),虛擬機器監控程式可以啟用這些特性以增強安全性。 其中一些特性需要來賓端實現才能正常執行。 下表列出了來賓/虛擬機器監控程式 SNP 特性支援的各種可能場景下,預期的來賓行為。
由 HV 啟用的特性 |
來賓需要實現 |
來賓具有實現 |
來賓啟動行為 |
|---|---|---|---|
否 |
否 |
否 |
啟動 |
否 |
是 |
否 |
啟動 |
否 |
是 |
是 |
啟動 |
是 |
否 |
否 |
啟動時啟用特性 |
是 |
是 |
否 |
優雅的啟動失敗 |
是 |
是 |
是 |
啟動時啟用特性 |
更多詳細資訊請參見 AMD64 APM[1] Vol 2: 15.34.10 SEV_STATUS MSR
19.2. 反向對映表 (RMP)¶
RMP 是系統記憶體中的一種結構,用於確保系統物理地址和來賓物理地址之間存在一對一的對映。 每個可能分配給來賓的記憶體頁在 RMP 中都有一個條目。
RMP 表可以是記憶體中的連續結構,也可以是記憶體中的段的集合。
19.2.1. 連續 RMP¶
當存在對 SEV-SNP 的支援時,就存在對此形式的 RMP 的支援,這可以使用 CPUID 指令來確定
0x8000001f[eax]:
Bit[4] indicates support for SEV-SNP
透過兩個 MSR 向硬體標識 RMP 的位置
0xc0010132 (RMP_BASE):
System physical address of the first byte of the RMP
0xc0010133 (RMP_END):
System physical address of the last byte of the RMP
硬體要求 RMP_BASE 和 (RPM_END + 1) 必須是 8KB 對齊的,但 SEV 韌體將對齊要求提高到需要 1MB 對齊。
RMP 由一個用於處理器記賬的 16KB 區域和隨後的 RMP 條目組成,RMP 條目的大小為 16 位元組。 RMP 的大小決定了虛擬機器監控程式可以分配給 SEV-SNP 來賓的物理記憶體範圍。 RMP 涵蓋來自以下地址的系統物理地址:
0 to ((RMP_END + 1 - RMP_BASE - 16KB) / 16B) x 4KB.
當前的 Linux 支援依賴於 BIOS 為 RMP 分配/保留記憶體並適當設定 RMP_BASE 和 RMP_END。 Linux 使用 MSR 值來定位 RMP 並確定 RMP 的大小。 為了使 Linux 能夠啟用 SEV-SNP,RMP 必須覆蓋所有系統記憶體。
19.2.2. 分段 RMP¶
分段 RMP 支援是一種表示 RMP 佈局的新方法。 初始 RMP 支援要求 RMP 表在記憶體中是連續的。 從 RMP 不駐留的 NUMA 節點訪問 RMP 可能比從 RMP 駐留的 NUMA 節點訪問 RMP 花費更長的時間。 分段 RMP 支援允許 RMP 條目與 RMP 覆蓋的記憶體位於同一節點上,從而可能減少與訪問與記憶體關聯的 RMP 條目相關的延遲。 每個 RMP 段覆蓋特定的系統物理地址範圍。
可以使用 CPUID 指令確定對此形式的 RMP 的支援
0x8000001f[eax]:
Bit[23] indicates support for segmented RMP
如果支援,可以使用 CPUID 指令找到分段 RMP 屬性
0x80000025[eax]:
Bits[5:0] minimum supported RMP segment size
Bits[11:6] maximum supported RMP segment size
0x80000025[ebx]:
Bits[9:0] number of cacheable RMP segment definitions
Bit[10] indicates if the number of cacheable RMP segments
is a hard limit
要啟用分段 RMP,可以使用新的 MSR
0xc0010136 (RMP_CFG):
Bit[0] indicates if segmented RMP is enabled
Bits[13:8] contains the size of memory covered by an RMP
segment (expressed as a power of 2)
RMP_CFG MSR 中定義的 RMP 段大小適用於 RMP 的所有段。 因此,每個 RMP 段覆蓋特定的系統物理地址範圍。 例如,如果 RMP_CFG MSR 值為 0x2401,則 RMP 段覆蓋值為 0x24 => 36,這意味著 RMP 段覆蓋的記憶體大小為 64GB (1 << 36)。 因此,第一個 RMP 段覆蓋從 0 到 0xF_FFFF_FFFF 的物理地址,第二個 RMP 段覆蓋從 0x10_0000_0000 到 0x1F_FFFF_FFFF 的物理地址,依此類推。
啟用分段 RMP 後,RMP_BASE 指向 RMP 記賬區域,就像現在一樣(大小為 16K)。 但是,RMP 條目不是在記賬區域之後立即開始,而是有一個 4K RMP 段表 (RST)。 RST 中的每個條目大小為 8 位元組,表示一個 RMP 段
Bits[19:0] mapped size (in GB)
The mapped size can be less than the defined segment size.
A value of zero, indicates that no RMP exists for the range
of system physical addresses associated with this segment.
Bits[51:20] segment physical address
This address is left shift 20-bits (or just masked when
read) to form the physical address of the segment (1MB
alignment).
RST 可以容納 512 個段條目,但如果可快取 RMP 段的數量是硬限制 (CPUID 0x80000025_EBX[10]),則可以將大小限制為可快取 RMP 段的數量 (CPUID 0x80000025_EBX[9:0])。
當前的 Linux 支援依賴於 BIOS 為分段 RMP(記賬區域、RST 和所有段)分配/保留記憶體,構建 RST 並適當設定 RMP_BASE、RMP_END 和 RMP_CFG。 Linux 使用 MSR 值來定位 RMP 並確定 RMP 段的大小和位置。 為了使 Linux 能夠啟用 SEV-SNP,RMP 必須覆蓋所有系統記憶體。
更多詳細資訊請參見 AMD64 APM Vol 2,section “15.36.3 Reverse Map Table”,docID: 24593。
19.3. 安全 VM 服務模組 (SVSM)¶
SNP 提供了一個稱為虛擬機器特權級別 (VMPL) 的特性,該特性定義了來賓軟體可以執行的四個特權級別。 特權最高的級別為 0,數值較高的數字具有較低的特權。 更多詳細資訊請參見 AMD64 APM Vol 2,section “15.35.7 Virtual Machine Privilege Levels”,docID: 24593。
使用該特性時,不同的服務可以在不同的保護級別執行,與來賓作業系統分離,但仍然在安全的 SNP 環境中。 它們可以為來賓提供服務,例如 vTPM。
當來賓未在 VMPL0 執行時,它需要與在 VMPL0 執行的軟體通訊,以執行特權操作或與安全服務互動。 例如,一個重要的特權操作是 PVALIDATE,它必須在 VMPL0 上執行。
在這種情況下,在 VMPL0 執行的軟體通常稱為安全 VM 服務模組 (SVSM)。 SVSM 的發現以及用於與其通訊的 API 在“Secure VM Service Module for SEV-SNP Guests”中進行了說明,docID: 58019。
(可以透過使用像 duckduckgo.com 這樣的搜尋引擎並鍵入以下內容來找到上述文件的最新版本:
site:amd.com “Secure VM Service Module for SEV-SNP Guests”, docID: 58019
例如。)