BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

When SEV-SNP is active, the GHCB page is mapped un-encrypted in the
initial page table built by the reset vector code. Just clearing the
encryption attribute from the page table is not enough. The page also
needs to be added as shared in the RMP table.

The GHCB page was part of the pre-validated memory range specified
through the SnpBootBlock GUID. To maintain the security guarantees,
we must invalidate the GHCB page before clearing the encryption
attribute from the page table, and add the page shared in the RMP
table.

Cc: James Bottomley <j...@linux.ibm.com>
Cc: Min Xu <min.m...@intel.com>
Cc: Jiewen Yao <jiewen....@intel.com>
Cc: Tom Lendacky <thomas.lenda...@amd.com>
Cc: Jordan Justen <jordan.l.jus...@intel.com>
Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
Cc: Laszlo Ersek <ler...@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.si...@amd.com>
---
 OvmfPkg/ResetVector/Ia32/PageTables64.asm | 106 ++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm 
b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9..63b864bcf2 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -62,6 +62,99 @@ BITS    32
 %define GHCB_CPUID_REGISTER_SHIFT  30
 %define CPUID_INSN_LEN              2
 
+; GHCB Page Invalidate request and response protocol values
+;
+%define GHCB_PAGE_STATE_CHANGE_REQUEST    20
+%define GHCB_PAGE_STATE_CHANGE_RESPONSE   21
+%define   GHCB_PAGE_STATE_SHARED          2
+
+; GHCB request to terminate protocol values
+%define GHCB_GENERAL_TERMINATE_REQUEST    255
+
+;
+; If SEV-SNP is enabled, invalidate the GHCB page
+InvalidateGHCBPage:
+    ; Read the SEV_STATUS MSR to check whether SEV-SNP is enabled.
+    ;  MSR_0xC0010131 - Bit 2 (SEV-SNP enabled)
+    mov     ecx, 0xc0010131
+    rdmsr
+    bt      eax, 2
+    jnc     InvalidateGHCBPageDone
+
+    ; Use PVALIDATE instruction to invalidate the page
+    mov     eax, GHCB_BASE
+    mov     ecx, 0
+    mov     edx, 0
+    DB      0xF2, 0x0F, 0x01, 0xFF
+    cmp     eax, 0
+    jnz     ValidationFailure
+
+    ; Ask hypervisor to change the page state to shared using the
+    ; Page State Change VMGEXIT.
+    ;
+    ; Setup GHCB MSR
+    ;   GHCB_MSR[55:52] = Page Operation
+    ;   GHCB_MSR[51:12] = Guest Physical Frame Number
+    ;   GHCB_MSR[11:0]  = Page State Change Request
+    ;
+    mov     eax, (GHCB_BASE >> 12)
+    shl     eax, 12
+    or      eax, GHCB_PAGE_STATE_CHANGE_REQUEST
+    mov     edx, (GHCB_PAGE_STATE_SHARED << 20)
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+    ;
+    ; Response GHCB MSR
+    ;   GHCB_MSR[51:12] = Guest Physical Frame Number
+    ;   GHCB_MSR[11:0]  = Page State Change Response
+    ;
+    mov     ecx, 0xc0010130
+    rdmsr
+    and     eax, 0xfff
+    cmp     eax, GHCB_PAGE_STATE_CHANGE_RESPONSE
+    jnz     ValidationFailure
+    cmp     edx, 0
+    jnz     ValidationFailure
+
+    jmp     InvalidateGHCBPageDone
+
+ValidationFailure:
+    ;
+    ; Setup GHCB MSR
+    ;   GHCB_MSR[23:16] = 0
+    ;   GHCB_MSR[15:12] = 0
+    ;   GHCB_MSR[11:0]  = Terminate Request
+    ;
+    mov     edx, 0
+    mov     eax, GHCB_GENERAL_TERMINATE_REQUEST
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+SnpPageStateFailureHlt:
+    cli
+    hlt
+    jmp     SnpPageStateFailureHlt
+
+InvalidateGHCBPageDone:
+    OneTimeCallRet InvalidateGHCBPage
+
 
 ; Check if Secure Encrypted Virtualization (SEV) features are enabled.
 ;
@@ -316,6 +409,19 @@ clearGhcbMemoryLoop:
     mov     dword[ecx * 4 + GHCB_BASE - 4], eax
     loop    clearGhcbMemoryLoop
 
+    ;
+    ; The page table built above cleared the memory encryption mask from the
+    ; GHCB_BASE (aka made it shared). When SEV-SNP is enabled, to maintain
+    ; the security guarantees, the page state transition from private to
+    ; shared must go through the page invalidation steps. Invalidate the
+    ; memory range before loading the page table below.
+    ;
+    ; NOTE: the invalidation must happen after zeroing the GHCB memory. This
+    ;       is because, in the 32-bit mode all the access are considered 
private.
+    ;       The invalidation before the zero'ing will cause a #VC.
+    ;
+    OneTimeCall  InvalidateGHCBPage
+
 SetCr3:
     ;
     ; Set CR3 now that the paging structures are available
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73227): https://edk2.groups.io/g/devel/message/73227
Mute This Topic: https://groups.io/mt/81584588/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to