共用方式為


虛擬安全模式

虛擬安全模式 (VSM) 是一組提供給主機和客體分割區的 Hypervisor 功能和啟發式,可讓您在作業系統軟體內建立和管理新的安全性界限。 VSM 是Windows安全性功能的 Hypervisor 設備,包括 Device Guard、Credential Guard、虛擬 TPM 和受防護的 VM。 這些安全性功能是在 Windows 10 和 Windows Server 2016 中引進。

VSM 可讓根分區和客體分割區中的作業系統軟體建立隔離的記憶體區域,以便儲存和處理系統安全性資產。 這些隔離區域的存取權只會透過 Hypervisor 來控制並授與,這是系統受信任計算基底 (TCB) 具有高度特殊許可權、高度信任的部分。 由於 Hypervisor 是以高於作業系統軟體的許可權等級執行,並具有主要系統硬體資源的獨佔控制,例如 CPU MMU 和 IOMMU 中的記憶體存取權限控制,因此 Hypervisor 可以在系統初始化初期保護這些隔離區域免于未經授權的存取,即使是作業系統軟體 (,例如作業系統核心和設備磁碟機,) 具有監督員模式存取 (,亦即 CPL0, 或 "Ring 0") 。

透過此架構,即使以監督員模式執行的一般系統層級軟體 (例如核心、驅動程式等) 遭到惡意軟體入侵,受 Hypervisor 保護的隔離區域中的資產仍可受到保護。

虛擬信任等級 (VTL)

VSM 可透過虛擬信任等級 (VTL) 來達成和維護隔離。 VTL 會以個別分割區和每個虛擬處理器為基礎來啟用和管理。

虛擬信任層級是階層式的,較高層級的許可權高於較低層級。 VTL0 是最低許可權層級,VTL1 的許可權高於 VTL0、VTL2 的許可權高於 VTL1 等。

在架構上,最多支援 16 個層級的 VTL;不過,Hypervisor 可能會選擇實作少於 16 個 VTL。 目前,只會實作兩個 VTL。

typedef UINT8 HV_VTL, *PHV_VTL;

#define HV_NUM_VTLS 2
#define HV_INVALID_VTL ((HV_VTL) -1)
#define HV_VTL_ALL 0xF

每個 VTL 都有自己的記憶體存取保護集。 這些存取保護是由分割區實體位址空間中的 Hypervisor 管理,因此無法由資料分割中執行的系統層級軟體修改。

由於具有更多特殊許可權的 VTL 可以強制執行自己的記憶體保護,因此較高的 VTL 可以有效地保護記憶體區域免于降低 VTL。 實際上,這可讓較低的 VTL 使用較高的 VTL 來保護隔離的記憶體區域。 例如,VTL0 可以將秘密儲存在 VTL1 中,此時只有 VTL1 可以存取它。 即使 VTL0 遭到入侵,秘密仍會是安全的。

VTL 保護

有多個 Facet 可達到 VTL 之間的隔離:

  • 記憶體存取保護:每個 VTL 都會維護一組客體實體記憶體存取保護。 在特定 VTL 上執行的軟體只能根據這些保護來存取記憶體。
  • 虛擬處理器狀態:虛擬處理器會維護個別的個別 VTL 狀態。 例如,每個 VTL 都會定義一組私人 VP 註冊。 在較低 VTL 執行的軟體無法存取較高 VTL 的私人虛擬處理器註冊狀態。
  • 中斷:除了個別的處理器狀態之外,每個 VTL 也會有自己的插斷子系統 (本機 APIC) 。 這可讓較高的 VTL 處理中斷,而不會有降低 VTL 干擾的風險。
  • 重迭頁面:會維護每個 VTL 的特定重迭頁面,讓較高的 VTL 具有可靠的存取權。 例如,每個 VTL 都有個別的超重迭頁面。

VSM 偵測和狀態

VSM 功能會透過 AccessVsm 分割區許可權旗標向分割區公告。 只有具有下列擁有權限的資料分割可以使用 VSM:AccessVsm、AccessVpRegisters 和 AccessSynicRegs。

VSM 功能偵測

來賓應該使用下列模型特定的暫存器來存取 VSM 功能的報告:

MSR 位址 註冊名稱 描述
0x000D0006 HV_X64_REGISTER_VSM_CAPABILITIES VSM 功能的報表。

註冊 VSM 功能 MSR 的格式如下:

Bits 描述 屬性
63 Dr6Shared 讀取
62:47 MbecVtlMask 讀取
46 DenyLowerVtlStartup 讀取
45:0 RsvdZ 讀取

Dr6Shared 會向來賓指出 Dr6 是否為 VTLs 之間的共用暫存器。

MvecVtlMask 會向來賓指出可以啟用 Mbec 的 VTL。

DenyLowerVtlStartup 會向來賓指出 Vtl 是否可以拒絕較低 VTL 的 VP 重設。

VSM 狀態暫存器

除了分割區許可權旗標之外,還可以使用兩個虛擬暫存器來瞭解 VSM 狀態的其他資訊: HvRegisterVsmPartitionStatusHvRegisterVsmVpStatus

HvRegisterVsmPartitionStatus

HvRegisterVsmPartitionStatus 是跨所有 VTL 共用的每個分割區唯讀暫存器。 此暫存器提供已針對分割區啟用哪些 VTL、已啟用模式型執行控制項的 VTL,以及允許的最大 VTL 的相關資訊。

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 EnabledVtlSet : 16;
        UINT64 MaximumVtl : 4;
        UINT64 MbecEnabledVtlSet: 16;
        UINT64 ReservedZ : 28;
    };
} HV_REGISTER_VSM_PARTITION_STATUS;

HvRegisterVsmVpStatus

HvRegisterVsmVpStatus 是唯讀的暫存器,而且會在所有 VTL 之間共用。 它是每一 VP 暫存器,這表示每個虛擬處理器都會維護自己的實例。 此暫存器提供哪些 VTL 已啟用、處於作用中狀態,以及 VPN 上作用中的 MBEC 模式的相關資訊。

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 ActiveVtl : 4;
        UINT64 ActiveMbecEnabled : 1;
        UINT64 ReservedZ0 : 11;
        UINT64 EnabledVtlSet : 16;
        UINT64 ReservedZ1 : 32;
    };
} HV_REGISTER_VSM_VP_STATUS;

ActiveVtl 是虛擬處理器上目前作用中之 VTL 內容的識別碼。

ActiveMbecEnabled 指定虛擬處理器上目前使用 MBEC。

EnabledVtlSet 是虛擬處理器上啟用之 VTL 的點陣圖。

資料分割 VTL 初始狀態

當分割區啟動或重設時,它會開始在 VTL0 中執行。 所有其他 VTL 會在分割區建立時停用。

VTL 啟用

若要開始使用 VTL,較低的 VTL 必須起始下列專案:

  1. 啟用分割區的目標 VTL。 這可讓 VTL 正式可供分割區使用。
  2. 在一或多個虛擬處理器上啟用目標 VTL。 這可讓 VTL 可供 VP 使用,並設定其初始內容。 建議所有 VM 都具有相同啟用的 VTL。 在某些 VM 上啟用 VTL (,但並非所有) 都會導致非預期的行為。
  3. 啟用磁碟分割和 VP 的 VTL 之後,只要設定 EnableVtlProtection 旗標,就可以開始設定存取保護。

請注意,VTL 不一定是連續的。

為分割區啟用目標 VTL

HvCallEnablePartitionVtl hypercall 可用來啟用特定分割區的 VTL。 請注意,在軟體實際可在特定 VTL 中執行之前,必須在磁碟分割中的虛擬處理器上啟用 VTL。

啟用虛擬處理器的目標 VTL

一旦為分割區啟用 VTL,就可以在分割區的虛擬處理器上加以啟用。 HvCallEnableVpVtl hypercall 可用來為虛擬處理器啟用 VTL,以設定其初始內容。

虛擬處理器每個 VTL 都有一個「內容」。 如果 VTL 已切換,也會切換 VTL 的私人 狀態

VTL 組態

啟用 VTL 之後,執行于等於或更高 VTL 的 VP 即可變更其設定。

資料分割組態

您可以使用 HvRegisterVsmPartitionConfig 暫存器來設定全分割屬性。 每個 VTL 都有一個實例 (在每個分割區上大於 0) 。

每個 VTL 都可以修改自己的HV_REGISTER_VSM_PARTITION_CONFIG實例,以及較低 VTL 的實例。 VTL 可能不會針對較高的 VTL 修改此暫存器。

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 EnableVtlProtection : 1;
        UINT64 DefaultVtlProtectionMask : 4;
        UINT64 ZeroMemoryOnReset : 1;
        UINT64 DenyLowerVtlStartup : 1;
        UINT64 ReservedZ : 2;
        UINT64 InterceptVpStartup : 1;
        UINT64 ReservedZ : 54; };
} HV_REGISTER_VSM_PARTITION_CONFIG;

以下說明此暫存器欄位。

啟用 VTL 保護

啟用 VTL 之後,必須先設定 EnableVtlProtection 旗標,才能開始套用記憶體保護。 此旗標是寫入一次,這表示一旦設定,就無法修改它。

預設保護遮罩

根據預設,系統會將 RWX 保護套用至所有目前對應的頁面,以及任何未來的「熱新增」頁面。 新增熱頁面是指在調整大小作業期間新增至分割區的任何記憶體。

較高的 VTL 可以在 HV_REGISTER_VSM_PARTITION_CONFIG中指定 DefaultVtlProtectionMask 來設定不同的預設記憶體保護原則。 啟用 VTL 時必須設定此遮罩。 設定之後,就無法變更它,而且只會由分割區重設清除。

bit 描述
0 讀取
1 寫入
2 核心模式執行 (KMX)
3 使用者模式執行 (UMX)

重設時為零記憶體

ZeroMemOnReset 是一個位,可控制是否在重設分割區之前將記憶體零。 此設定預設為開啟。 如果已設定位,則分割區的記憶體會在重設時零,讓較低的 VTL 無法危害較高的 VTL 記憶體。 如果清除此位,則重設時不會將分割區的記憶體零。

DenyLowerVtlStartup

DenyLowerVtlStartup 旗標可控制虛擬處理器是否可以由較低的 VTL 啟動或重設。 這包括重設虛擬處理器 (的架構方式,例如 X64) 上的 STO,以及 HvCallStartVirtualProcessor hypercall

InterceptVpStartup

如果已設定 InterceptVpStartup 旗標,啟動或重設虛擬處理器會產生較高 VTL 的攔截。

設定較低的 VTL

較高的 VTL 可以使用下列暫存器來設定較低 VTL 的行為:

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 MbecEnabled : 1;
        UINT64 TlbLocked : 1;
        UINT64 ReservedZ : 62;
    };
} HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG;

每個 VTL (高於 0) 每個 VTL 都有一個實例,每個 VTL 低於本身。 例如,VTL2 會有兩個此暫存器實例 –一個用於 VTL1,另一個用於 VTL0。

以下說明此暫存器欄位。

MbecEnabled

此欄位會設定是否為較低的 VTL 啟用 MBEC。

TlbLocked

此欄位會鎖定下層 VTL 的 TLB。 這項功能可用來防止較低的 VTL 造成 TLB 失效,這可能會干擾較高的 VTL。 設定此位時,會封鎖來自下層 VTL 的所有位址空間排清要求,直到鎖定解除為止。

若要解除鎖定 TLB,較高的 VTL 可以清除此位。 此外,當 VP 回到較低的 VTL 之後,它會釋放它當時保留的所有 TLB 鎖定。

VTL 專案

當 VP 從較低的 VTL 切換到較高的 VTL 時,VTL 會「輸入」。 這可能因為以下原因而發生:

  1. VTL 呼叫:這是當軟體明確想要在較高的 VTL 中叫用程式碼時。
  2. 安全中斷:如果收到較高 VTL 的中斷,則 VP 會進入較高的 VTL。
  3. 安全攔截:某些動作會觸發安全中斷, (存取特定 MSR,例如) 。

輸入 VTL 之後,它必須主動結束。 較低的 VTL 無法先占較高的 VTL。

識別 VTL 專案原因

為了適當地回應專案,較高的 VTL 可能需要知道輸入的原因。 為了區分輸入原因,VTL 專案會包含在 HV_VP_VTL_CONTROL 結構中。

VTL 通話

例如,當較低的 VTL 起始進入較高的 VTL (時,即會透過 HvCallVtlCall 超call 保護具有較高 VTL) 記憶體區域時,則為 「VTL 呼叫」。

VTL 呼叫會保留跨 VTL 交換器共用暫存器的狀態。 私人暫存器會保留在每一 VTL 層級上。 這些限制的例外狀況是 VTL 呼叫序列所需的暫存器。 VTL 呼叫需要下列暫存器:

x64 x86 描述
RCX EDX:EAX 指定 Hypervisor 的 VTL 呼叫控制項輸入
RAX ECX 保留

VTL 呼叫控制項輸入中的所有位目前都會保留。

VTL 通話限制

VTL 呼叫只能從最特殊許可權的處理器模式起始。 例如,在 x64 系統上,VTL 呼叫只能來自 CPL0。 從處理器模式起始的 VTL 呼叫,這是系統上最特殊許可權的任何專案,會導致 Hypervisor 將#UD例外狀況插入虛擬處理器中。

VTL 呼叫只能切換至下一個最高 VTL。 換句話說,如果已啟用多個 VTL,則呼叫無法「略過」VTL。 下列動作會導致#UD例外狀況:

  • 從處理器模式起始的 VTL 呼叫,這是系統 (架構特定) 以外的任何許可權。
  • 來自實際模式的 VTL 呼叫 (x86/x64)
  • 虛擬處理器上的 VTL 呼叫,其中目標 VTL 已停用 (或尚未啟用) 。
  • 具有無效控制項輸入值的 VTL 呼叫

VTL Exit

切換至較低 VTL 的稱為「傳回」。 VTL 完成處理之後,就可以起始 VTL 傳回,以切換至較低的 VTL。 VTL 傳回的唯一方式是,如果較高的 VTL 主動起始 VTL, 較低的 VTL 永遠不會先占較高的 VTL。

VTL 傳回

「VTL 傳回」是當較高的 VTL 透過 HvCallVtlReturn hypercall 起始切換至較低的 VTL 時。 與 VTL 呼叫類似,私用處理器狀態會切換出來,且共用狀態會保持原狀。 如果較低的 VTL 明確呼叫至較高的 VTL,Hypervisor 會在傳回完成之前遞增較高的 VTL 指令指標,以便在 VTL 呼叫之後繼續。

VTL 傳回碼序列需要使用下列暫存器:

x64 x86 描述
RCX EDX:EAX 指定 Hypervisor 的 VTL 傳回控制項輸入
RAX ECX 保留

VTL 傳回控制項輸入的格式如下:

Bits 欄位 描述
63:1 RsvdZ
0 快速傳回 暫存器未還原

下列動作會產生#UD例外狀況:

  • 嘗試在目前使用中最低 VTL 時傳回 VTL
  • 嘗試使用不正確控制輸入值傳回 VTL
  • 嘗試從處理器模式傳回 VTL,這是系統 (架構特定) 以外的任何許可權

快速傳回

在處理傳回時,Hypervisor 可以從 HV_VP_VTL_CONTROL 結構還原較低 VTL 的註冊狀態。 例如,在處理安全中斷之後,較高的 VTL 可能會想要傳回,而不會中斷較低的 VTL 狀態。 因此,Hypervisor 提供一種機制,只將較低的 VTL 暫存器還原至儲存在 VTL 控制結構中的預先呼叫值。

如果不需要此行為,較高的 VTL 可以使用「快速傳回」。 快速傳回是 Hypervisor 不會從控制結構還原暫存器狀態時。 這應該盡可能使用,以避免不必要的處理。

此欄位可以使用 VTL 傳回輸入的位 0 來設定。 如果設定為 0,則會從 HV_VP_VTL_CONTROL 結構還原暫存器。 如果此位設定為 1,則不會還原暫存器 (快速傳回) 。

Hypercall 頁面協助工具

Hypervisor 提供機制來協助 VTL 呼叫,並透過 Hypercall 頁面傳回。 此頁面會抽象化切換 VTL 所需的特定程式碼順序。

執行 VTL 呼叫和傳回的程式碼序列,可以在 hypercall 頁面中執行特定指示來存取。 呼叫/傳回區塊位於 HvRegisterVsmCodePageOffset 虛擬暫存器所決定的 hypercall 頁面中的位移。 這是唯讀且全分割的暫存器,每個 VTL 有個別的實例。

VTL 可以使用 CALL 指令來執行 VTL 呼叫/傳回。 Hypercall 頁面中正確位置的呼叫將會起始 VTL 呼叫/傳回。

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 VtlCallOffset : 12;
        UINT64 VtlReturnOffset : 12;
        UINT64 ReservedZ : 40;
    };
} HV_REGISTER_VSM_CODE_PAGE_OFFSETS;

總而言之,使用 hypercall 頁面呼叫程式碼序列的步驟如下:

  1. 將 Hypercall 頁面對應至 VTL 的 GPA 空間
  2. 判斷程式碼序列的正確位移, (VTL 呼叫或傳回) 。
  3. 使用 CALL 執行程式碼順序。

記憶體存取保護

VSM 所提供的一個必要保護是能夠隔離記憶體存取。

較高的 VTL 對於較低 VTL 允許的記憶體存取類型具有高度的控制。 特定 GPA 頁面的 VTL 可以指定三種基本保護類型:讀取、寫入和 eXecute。 下表中定義了這些:

名稱 描述
讀取 控制是否允許讀取存取記憶體頁面
寫入 控制是否允許寫入記憶體頁面
執行 控制是否允許記憶體頁面的指令擷取。

這三種結合適用于下列類型的記憶體保護:

  1. 無存取權
  2. 唯讀,無執行
  3. 唯讀、執行
  4. 讀取/寫入,無執行
  5. 讀取/寫入、執行

如果已啟用「模式型執行控制 (MBEC) 」,則可以個別設定使用者和核心模式執行保護。

較高的 VTL 可以透過 HvCallModifyVtlProtectionMask hypercall 來設定 GPA 的記憶體保護。

記憶體保護階層

記憶體存取權限可由特定 VTL 的多個來源設定。 每個 VTL 的許可權可能受限於一些其他 VTL,以及主機分割區。 套用保護的順序如下:

  1. 主機所設定的記憶體保護
  2. 較高 VTL 所設定的記憶體保護

換句話說,VTL 保護會取代主機保護。 較高層級的 VTL 會取代較低層級的 VTL。 請注意,VTL 本身可能不會設定記憶體存取權限。

一致性介面預期不會在 RAM 上重迭任何非 RAM 類型。

記憶體存取違規

如果在較低 VTL 執行的 VP 嘗試違反較高 VTL 所設定的記憶體保護,則會產生攔截。 此攔截是由設定保護的較高 VTL 接收。 這可讓較高的 VTL 依大小寫處理違規。 例如,較高的 VTL 可以選擇傳回錯誤,或模擬存取權。

以模式為基礎的執行控制項 (MBEC)

當 VTL 在較低的 VTL 上放置記憶體限制時,可能會想要在授與「執行」許可權時區分使用者和核心模式。 例如,如果程式碼完整性檢查是在較高的 VTL 中進行,則區分使用者模式和核心模式的能力,表示 VTL 只能針對核心模式應用程式強制執行程式碼完整性。

除了傳統的三個記憶體保護 (讀取、寫入、執行) 之外,MBEC 也引進了使用者模式與核心模式之間的區別,以進行執行保護。 因此,如果已啟用 MBEC,VTL 有機會設定四種類型的記憶體保護:

名稱 描述
讀取 控制是否允許讀取存取記憶體頁面
寫入 控制是否允許寫入記憶體頁面
使用者模式執行 (UMX) 控制是否允許記憶體頁面在使用者模式中產生的指令擷取。 注意:如果停用 MBEC,則會忽略此設定。
核心模式執行 (UMX) 控制是否允許記憶體頁面在核心模式中產生的指令擷取。 注意:如果停用 MBEC,此設定可控制使用者模式和核心模式執行存取。

只有在虛擬處理器以使用者模式模式執行時,標示為「使用者模式執行」保護的記憶體才會是可執行檔。 同樣地,只有在虛擬處理器以核心模式執行時,才會執行「核心模式執行」記憶體。

KMX 和 UMX 可以獨立設定,讓執行許可權在使用者和核心模式之間以不同方式強制執行。 除了 KMX=1、UMX=0 以外,支援所有 UMX 和 KMX 的組合。 這個組合的行為未定義。

預設會停用所有 VTL 和虛擬處理器的 MBEC。 停用 MBEC 時,核心模式執行位會決定記憶體存取限制。 因此,如果停用 MBEC,KMX=1 程式碼在核心和使用者模式中都是可執行檔。

描述項資料表

任何存取描述中繼資料表的使用者模式程式碼都必須在標示為 KMX=UMX=1 的 GPA 頁面中。 不支援從標示 KMX=0 的 GPA 頁面存取描述中繼資料表的使用者模式軟體,並導致一般保護錯誤。

MBEC 組態

若要使用模式型執行控制項,必須在兩個層級啟用它:

  1. 啟用磁碟分割的 VTL 時,必須使用 HvCallEnablePartitionVtl 啟用 MBEC
  2. MBEC 必須使用 HvRegisterVsmVpSecureVtlConfig,以每個 VP 和每個 VTL 為基礎進行設定。

MBEC 與監督員模式執行防護互動 (SMEP)

Supervisor-Mode SMEP) (執行防護是某些平臺上支援的處理器功能。 SMEP 可能會因為對記憶體頁面的監督員存取限制而影響 MBEC 的作業。 Hypervisor 遵守下列與 SMEP 相關的原則:

  • 如果客體 OS 無法使用 SMEP, (它是否因為硬體功能或處理器相容性模式而) ,MBEC 會運作不受影響。
  • 如果 SMEP 可用且已啟用,MBEC 就會不受影響。
  • 如果 SMEP 可用且已停用,則所有執行限制都會受到 KMX 控制項控管。 因此,只允許標示 KMX=1 的程式碼執行。

虛擬處理器狀態隔離

虛擬處理器會針對每個作用中的 VTL 維護個別狀態。 不過,某些此狀態是特定 VTL 的私人狀態,而其餘狀態則會在所有 VTL 之間共用。

每個 VTL () 私人狀態) 會由 Hypervisor 跨 VTL 轉換儲存的狀態。 如果起始 VTL 參數,Hypervisor 會儲存作用中 VTL 的目前私人狀態,然後切換至目標 VTL 的私人狀態。 不論 VTL 交換器為何,共用狀態都會保持作用中。

私人狀態

一般而言,每個 VTL 都有自己的控制暫存器、RIP 暫存器、RSP 註冊和 MSR。 以下是每個 VTL 專用的特定暫存器和 MSR 清單。

私人 MSR:

  • SYSENTER_CS、SYSENTER_ESP、SYSENTER_EIP、STAR、LSTAR、CSTAR、SFMASK、EFER、PAT、KERNEL_GSBASE、FS。BASE、GS。BASE、TSC_AUX
  • HV_X64_MSR_HYPERCALL
  • HV_X64_MSR_GUEST_OS_ID
  • HV_X64_MSR_REFERENCE_TSC
  • HV_X64_MSR_APIC_FREQUENCY
  • HV_X64_MSR_EOI
  • HV_X64_MSR_ICR
  • HV_X64_MSR_TPR
  • HV_X64_MSR_APIC_ASSIST_PAGE
  • HV_X64_MSR_NPIEP_CONFIG
  • HV_X64_MSR_SIRBP
  • HV_X64_MSR_SCONTROL
  • HV_X64_MSR_SVERSION
  • HV_X64_MSR_SIEFP
  • HV_X64_MSR_SIMP
  • HV_X64_MSR_EOM
  • HV_X64_MSR_SINT0 – HV_X64_MSR_SINT15
  • HV_X64_MSR_STIMER0_CONFIG – HV_X64_MSR_STIMER3_CONFIG
  • HV_X64_MSR_STIMER0_COUNT – HV_X64_MSR_STIMER3_COUNT
  • 本機 APIC 註冊 (包括 CR8/TPR)

私人暫存器:

  • RIP、RSP
  • RFLAGS
  • CR0、CR3、CR4
  • DR7
  • IDTR、GDTR
  • CS、DS、ES、FS、GS、SS、TR、LDTR
  • TSC
  • DR6 (*相依于處理器類型。讀取 HvRegisterVsmCapabilities 虛擬暫存器以判斷共用/私人狀態)

共用狀態

VTL 會共用狀態,以降低切換內容的額外負荷。 共用狀態也允許 VTL 之間的一些必要通訊。 大部分的一般用途和浮點暫存器都會共用,如同大部分的架構 MSR。 以下是所有 VTL 之間共用的特定 MSR 和註冊清單:

共用 MSR:

  • HV_X64_MSR_TSC_FREQUENCY
  • HV_X64_MSR_VP_INDEX
  • HV_X64_MSR_VP_RUNTIME
  • HV_X64_MSR_RESET
  • HV_X64_MSR_TIME_REF_COUNT
  • HV_X64_MSR_GUEST_IDLE
  • HV_X64_MSR_DEBUG_DEVICE_OPTIONS
  • MTRR
  • MCG_CAP
  • MCG_STATUS

共用暫存器:

  • Rax、Rbx、Rcx、Rdx、Rsi、Rdi、Rbp
  • CR2
  • R8 – R15
  • DR0 – DR5
  • X87 浮點狀態
  • XMM 狀態
  • AVX 狀態
  • XCR0 (XFEM)
  • DR6 (*相依于處理器類型。讀取 HvRegisterVsmCapabilities 虛擬暫存器以判斷共用/私人狀態)

實境模式

任何大於 0 的 VTL 都不支援實境模式。 大於 0 的 VTL 可以在 32 位或 64 位模式中執行。

VTL 中斷管理

為了達到虛擬信任層級之間的高度隔離,虛擬安全模式會針對虛擬處理器上啟用的每個 VTL 提供個別的中斷子系統。 這可確保 VTL 能夠同時傳送和接收中斷,而不會干擾較不安全的 VTL。

每個 VTL 都有自己的中斷控制器,只有在虛擬處理器在該特定 VTL 中執行時才作用中。 如果虛擬處理器切換 VTL 狀態,處理器上的中斷控制器也會切換。

以 VTL 為目標且高於作用中 VTL 的中斷會導致立即的 VTL 交換器。 然後,較高的 VTL 可以接收中斷。 如果較高的 VTL 因為 TPR/CR8 值而無法接收中斷,則中斷會保留為「擱置中」,且 VTL 不會切換。 如果有多個具有擱置中斷的 VTL,則最高 VTL 的優先順序會 (,而不會注意到較低的 VTL) 。

當中斷以較低的 VTL 為目標時,在下次虛擬處理器轉換成目標 VTL 之前,不會傳遞中斷。 在啟用較高 VTL 的虛擬處理器上,會捨棄以較低 VTL 為目標的 INIT 和啟動 IP。 由於 INIT/SBASE 遭到封鎖,因此應該使用 HvCallStartVirtualProcessor hypercall 來啟動處理器。

RFLAGS。如果

為了切換 VTL,RFLAGS。IF 不會影響安全中斷是否觸發 VTL 參數。 如果 RFLAGS 為 。如果清除以遮罩中斷,中斷至較高的 VTL 仍會導致 VTL 切換至較高的 VTL。 決定是否要立即中斷時,只會考慮較高的 VTL TPR/CR8 值。

此行為也會影響 VTL 傳回時的擱置中斷。 如果 RFLAGS。如果清除 bit 以遮罩指定 VTL 中的中斷,且 VTL 會傳回 (至較低的 VTL) ,Hypervisor 會重新評估任何擱置的中斷。 這會導致立即回呼較高的 VTL。

虛擬中斷通知協助

如果 VTL 正在封鎖對相同虛擬處理器較低 VTL 的立即傳遞,則較高的 VTL 可能會註冊以接收通知。 較高的 VTL 可以透過虛擬暫存器 HvRegisterVsmVina 啟用虛擬插斷通知協助 (VINA) :

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 Vector : 8;
        UINT64 Enabled : 1;
        UINT64 AutoReset : 1;
        UINT64 AutoEoi : 1;
        UINT64 ReservedP : 53;
    };
} HV_REGISTER_VSM_VINA;

每個 VP 上的每個 VTL 都有自己的 VINA 實例,以及自己的 HvRegisterVsmVina 版本。 當較低 VTL 的中斷準備好立即傳遞時,VINA 設備會產生目前作用中較高 VTL 的邊緣觸發中斷。

為了防止在啟用此設施時發生中斷,VINA 設施包含一些有限的狀態。 產生 VINA 中斷時,VINA 設施的狀態會變更為「判斷提示」。 將中斷結束傳送至與 VINA 設施相關聯的 SINT 將不會清除「判斷提示」狀態。 判斷提示狀態只能以下列兩種方式之一清除:

  1. 寫入 HV_VP_VTL_CONTROL 結構的 VinaAsserted 欄位,即可手動清除狀態。
  2. 如果在 HvRegisterVsmVina 暫存器中啟用 [在 VTL 專案上自動重設] 選項,則 VTL 的下一個專案會自動清除狀態。

這可讓在安全 VTL 上執行的程式碼,只收到針對較低 VTL 收到的第一個中斷通知。 如果安全的 VTL 希望收到其他中斷的通知,它可以清除 VP 輔助頁面的 VinaAsserted 欄位,並會收到下一個新的中斷通知。

安全攔截

Hypervisor 可讓較高的 VTL 針對在較低 VTL 內容中發生的事件安裝攔截。 這可讓較高的 VTL 提高對較低 VTL 資源的控制層級。 安全攔截可用來保護系統關鍵資源,並防止攻擊降低 VTL。

安全攔截會排入佇列至較高的 VTL,且該 VTL 可在 VP 上執行。

安全攔截類型

攔截類型 攔截適用于
記憶體存取 嘗試存取較高 VTL 所建立的 GPA 保護。
控制註冊存取 嘗試存取較高 VTL 所指定的一組控制項暫存器。

巢狀攔截

在較低的 VTL 中,多個 VTL 可以安裝相同事件的安全攔截。 因此,系統會建立階層來決定通知巢狀攔截的位置。 下列清單是通知攔截位置的順序:

  1. 較低的 VTL
  2. 較高的 VTL

處理安全攔截

一旦 VTL 收到安全攔截的通知,它就必須採取動作,讓較低的 VTL 可以繼續。 較高的 VTL 可以透過數種方式來處理攔截,包括:插入例外狀況、模擬存取,或提供 Proxy 給存取。 在任何情況下,如果需要修改較低 VTL VP 的私人狀態,則應該使用 HvCallSetVpRegisters

安全暫存器攔截

較高的 VTL 可以在存取特定控制暫存器時攔截。 這可藉由使用 HvCallSetVpRegisters hypercall 設定 HvX64RegisterCrInterceptControl 來達成。 在 HvX64RegisterCrInterceptControl 中設定控制位,將會針對對應控制項暫存器的每個存取觸發攔截。

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 Cr0Write : 1;
        UINT64 Cr4Write : 1;
        UINT64 XCr0Write : 1;
        UINT64 IA32MiscEnableRead : 1;
        UINT64 IA32MiscEnableWrite : 1;
        UINT64 MsrLstarRead : 1;
        UINT64 MsrLstarWrite : 1;
        UINT64 MsrStarRead : 1;
        UINT64 MsrStarWrite : 1;
        UINT64 MsrCstarRead : 1;
        UINT64 MsrCstarWrite : 1;
        UINT64 ApicBaseMsrRead : 1;
        UINT64 ApicBaseMsrWrite : 1;
        UINT64 MsrEferRead : 1;
        UINT64 MsrEferWrite : 1;
        UINT64 GdtrWrite : 1;
        UINT64 IdtrWrite : 1;
        UINT64 LdtrWrite : 1;
        UINT64 TrWrite : 1;
        UINT64 MsrSysenterCsWrite : 1;
        UINT64 MsrSysenterEipWrite : 1;
        UINT64 MsrSysenterEspWrite : 1;
        UINT64 MsrSfmaskWrite : 1;
        UINT64 MsrTscAuxWrite : 1;
        UINT64 MsrSgxLaunchControlWrite : 1;
        UINT64 RsvdZ : 39;
    };
} HV_REGISTER_CR_INTERCEPT_CONTROL;

遮罩暫存器

若要允許更精細的控制,控制項暫存器的子集也有對應的遮罩暫存器。 遮罩暫存器可用來在對應控制項暫存器子集上安裝攔截。 未定義遮罩暫存器時,HvX64RegisterCrInterceptControl 所定義的任何存取 () 都會觸發攔截。

Hypervisor 支援下列遮罩暫存器:HvX64RegisterCrInterceptCr0Mask、HvX64RegisterCrInterceptCr4Mask 和 HvX64RegisterCrInterceptIa32MiscEnableMask。

DMA 和裝置

裝置實際上具有與 VTL0 相同的許可權等級。 啟用 VSM 時,所有裝置配置的記憶體都會標示為 VTL0。 任何 DMA 存取的許可權都與 VTL0 相同。