public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support
@ 2021-06-30 12:52 Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 01/28] OvmfPkg/ResetVector: move SEV specific code in a separate file Brijesh Singh
                   ` (28 more replies)
  0 siblings, 29 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

SEV-SNP builds upon existing SEV and SEV-ES functionality while adding
new hardware-based memory protections. SEV-SNP adds strong memory integrity
protection to help prevent malicious hypervisor-based attacks like data
replay, memory re-mapping and more in order to create an isolated memory
encryption environment.
 
This series provides the basic building blocks to support booting the SEV-SNP
VMs, it does not cover all the security enhancement introduced by the SEV-SNP
such as interrupt protection.

Many of the integrity guarantees of SEV-SNP are enforced through a new
structure called the Reverse Map Table (RMP). Adding a new page to SEV-SNP
VM requires a 2-step process. First, the hypervisor assigns a page to the
guest using the new RMPUPDATE instruction. This transitions the page to
guest-invalid. Second, the guest validates the page using the new PVALIDATE
instruction. The SEV-SNP VMs can use the new "Page State Change Request NAE"
defined in the GHCB specification to ask hypervisor to add or remove page
from the RMP table.

Each page assigned to the SEV-SNP VM can either be validated or unvalidated,
as indicated by the Validated flag in the page's RMP entry. There are two
approaches that can be taken for the page validation: Pre-validation and
Lazy Validation.

Under pre-validation, the pages are validated prior to first use. And under
lazy validation, pages are validated when first accessed. An access to a
unvalidated page results in a #VC exception, at which time the exception
handler may validate the page. Lazy validation requires careful tracking of
the validated pages to avoid validating the same GPA more than once. The
recently introduced "Unaccepted" memory type can be used to communicate the
unvalidated memory ranges to the Guest OS.

At this time we only support the pre-validation. OVMF detects all the available
system RAM in the PEI phase. When SEV-SNP is enabled, the memory is validated
before it is made available to the EDK2 core.

This series does not implements the following SEV-SNP features yet:

* CPUID filtering
* Lazy validation
* Interrupt security

Additional resources
---------------------
SEV-SNP whitepaper
https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf

APM 2: https://www.amd.com/system/files/TechDocs/24593.pdf (section 15.36)

The complete source is available at
https://github.com/AMDESE/ovmf/tree/sev-snp-rfc-5

GHCB spec:
https://developer.amd.com/wp-content/resources/56421.pdf

SEV-SNP firmware specification:
https://www.amd.com/system/files/TechDocs/56860.pdf

Change since v4:
 * Use the correct MSR for the SEV_STATUS
 * Add VMPL-0 check

Change since v3:
 * ResetVector: move all SEV specific code in AmdSev.asm and add macros to keep
   the code readable.
 * Drop extending the EsWorkArea to contain SNP specific state.
 * Drop the GhcbGpa library and call the VmgExit directly to register GHCB GPA.
 * Install the CC blob config table from AmdSevDxe instead of extending the
   AmdSev/SecretsDxe for it.
 * Add the separate PCDs for the SNP Secrets.

Changes since v2:
 * Add support for the AP creation.
 * Use the module-scoping override to make AmdSevDxe use the IO port for PCI reads.
 * Use the reserved memory type for CPUID and Secrets page.
 * 
Changes since v1:
 * Drop the interval tree support to detect the pre-validated overlap region.
 * Use an array to keep track of pre-validated regions.
 * Add support to query the Hypervisor feature and verify that SNP feature is supported.
 * Introduce MemEncryptSevClearMmioPageEncMask() to clear the C-bit from MMIO ranges.
 * Pull the SevSecretDxe and SevSecretPei into OVMF package build.
 * Extend the SevSecretDxe to expose confidential computing blob location through
   EFI configuration table.

Brijesh Singh (27):
  OvmfPkg/ResetVector: move SEV specific code in a separate file
  OvmfPkg/ResetVector: add the macro to invoke MSR protocol based
    VMGEXIT
  OvmfPkg/ResetVector: add the macro to request guest termination
  OvmfPkg: reserve SNP secrets page
  OvmfPkg: reserve CPUID page for SEV-SNP
  OvmfPkg/ResetVector: introduce SEV-SNP boot block GUID
  OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  OvmfPkg/ResetVector: invalidate the GHCB page
  OvmfPkg/ResetVector: check the vmpl level
  UefiCpuPkg: Define the SEV-SNP specific dynamic PCDs
  OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled()
  OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  OvmfPkg/AmdSevDxe: do not use extended PCI config space
  OvmfPkg/MemEncryptSevLib: add support to validate system RAM
  OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM
  OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI
    phase
  OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  OvmfPkg/PlatformPei: validate the system RAM when SNP is active
  OvmfPkg/PlatformPei: set the SEV-SNP enabled PCD
  OvmfPkg/PlatformPei: set the Hypervisor Features PCD
  MdePkg/GHCB: increase the GHCB protocol max version
  UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is
    enabled
  OvmfPkg/MemEncryptSevLib: change the page state in the RMP table
  OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address
  OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map
  OvmfPkg/AmdSev: expose the SNP reserved pages through configuration
    table

Tom Lendacky (1):
  UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs

 OvmfPkg/OvmfPkg.dec                           |  24 +
 UefiCpuPkg/UefiCpuPkg.dec                     |  11 +
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |   5 +-
 OvmfPkg/Bhyve/BhyveX64.dsc                    |   5 +-
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   6 +-
 OvmfPkg/OvmfPkgX64.dsc                        |   5 +-
 OvmfPkg/OvmfXen.dsc                           |   5 +-
 OvmfPkg/OvmfPkgX64.fdf                        |  14 +-
 OvmfPkg/AmdSevDxe/AmdSevDxe.inf               |   7 +
 .../DxeMemEncryptSevLib.inf                   |   3 +
 .../PeiMemEncryptSevLib.inf                   |   7 +
 .../SecMemEncryptSevLib.inf                   |   3 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |   8 +
 OvmfPkg/ResetVector/ResetVector.inf           |   6 +
 OvmfPkg/Sec/SecMain.inf                       |   3 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   4 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   4 +
 MdePkg/Include/Register/Amd/Ghcb.h            |   2 +-
 .../Guid/ConfidentialComputingSecret.h        |  18 +
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |  26 +
 .../X64/SnpPageStateChange.h                  |  31 ++
 .../BaseMemEncryptSevLib/X64/VirtualMemory.h  |  19 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  19 +
 OvmfPkg/AmdSevDxe/AmdSevDxe.c                 |  23 +
 .../DxeMemEncryptSevLibInternal.c             |  27 +
 .../Ia32/MemEncryptSevLib.c                   |  17 +
 .../PeiMemEncryptSevLibInternal.c             |  27 +
 .../SecMemEncryptSevLibInternal.c             |  19 +
 .../X64/DxeSnpSystemRamValidate.c             |  40 ++
 .../X64/PeiDxeVirtualMemory.c                 | 167 +++++-
 .../X64/PeiSnpSystemRamValidate.c             | 126 +++++
 .../X64/SecSnpSystemRamValidate.c             |  36 ++
 .../X64/SnpPageStateChangeInternal.c          | 295 ++++++++++
 OvmfPkg/PlatformPei/AmdSev.c                  | 192 +++++++
 OvmfPkg/PlatformPei/MemDetect.c               |  21 +
 OvmfPkg/Sec/SecMain.c                         | 111 ++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  11 +-
 .../MpInitLib/Ia32/SevSnpRmpAdjustInternal.c  |  31 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 275 +++++++++-
 .../MpInitLib/X64/SevSnpRmpAdjustInternal.c   |  44 ++
 OvmfPkg/FvmainCompactScratchEnd.fdf.inc       |   5 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |  27 +
 .../Ia32/{PageTables64.asm => AmdSev.asm}     | 502 +++++++++++-------
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     | 404 +-------------
 OvmfPkg/ResetVector/ResetVector.nasmb         |   7 +
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |   1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  51 ++
 48 files changed, 2065 insertions(+), 630 deletions(-)
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c
 copy OvmfPkg/ResetVector/Ia32/{PageTables64.asm => AmdSev.asm} (57%)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 01/28] OvmfPkg/ResetVector: move SEV specific code in a separate file
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 02/28] OvmfPkg/ResetVector: add the macro to invoke MSR protocol based VMGEXIT Brijesh Singh
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The PageTables64.asm was created to provide routines to set the CR3
register for 64-bit paging. During the SEV support, it grew to include a
lot of the SEV stuff. Before adding more SEV features, let's move all
the SEV-specific routines into a separate file.

No functionality change intended.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../Ia32/{PageTables64.asm => AmdSev.asm}     | 140 -------
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     | 391 ------------------
 OvmfPkg/ResetVector/ResetVector.nasmb         |   1 +
 3 files changed, 1 insertion(+), 531 deletions(-)
 copy OvmfPkg/ResetVector/Ia32/{PageTables64.asm => AmdSev.asm} (71%)

diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
similarity index 71%
copy from OvmfPkg/ResetVector/Ia32/PageTables64.asm
copy to OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 5fae8986d9da..b32dd3b5d656 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -10,33 +10,6 @@
 
 BITS    32
 
-%define PAGE_PRESENT            0x01
-%define PAGE_READ_WRITE         0x02
-%define PAGE_USER_SUPERVISOR    0x04
-%define PAGE_WRITE_THROUGH      0x08
-%define PAGE_CACHE_DISABLE     0x010
-%define PAGE_ACCESSED          0x020
-%define PAGE_DIRTY             0x040
-%define PAGE_PAT               0x080
-%define PAGE_GLOBAL           0x0100
-%define PAGE_2M_MBO            0x080
-%define PAGE_2M_PAT          0x01000
-
-%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
-                          PAGE_DIRTY + \
-                          PAGE_READ_WRITE + \
-                          PAGE_PRESENT)
-
-%define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
-                          PAGE_ACCESSED + \
-                          PAGE_DIRTY + \
-                          PAGE_READ_WRITE + \
-                          PAGE_PRESENT)
-
-%define PAGE_PDP_ATTR (PAGE_ACCESSED + \
-                       PAGE_READ_WRITE + \
-                       PAGE_PRESENT)
-
 ;
 ; SEV-ES #VC exception handler support
 ;
@@ -213,119 +186,6 @@ IsSevEsEnabled:
 SevEsDisabled:
     OneTimeCallRet IsSevEsEnabled
 
-;
-; Modified:  EAX, EBX, ECX, EDX
-;
-SetCr3ForPageTables64:
-
-    OneTimeCall   CheckSevFeatures
-    xor     edx, edx
-    test    eax, eax
-    jz      SevNotActive
-
-    ; If SEV is enabled, C-bit is always above 31
-    sub     eax, 32
-    bts     edx, eax
-
-SevNotActive:
-
-    ;
-    ; For OVMF, build some initial page tables at
-    ; PcdOvmfSecPageTablesBase - (PcdOvmfSecPageTablesBase + 0x6000).
-    ;
-    ; This range should match with PcdOvmfSecPageTablesSize which is
-    ; declared in the FDF files.
-    ;
-    ; At the end of PEI, the pages tables will be rebuilt into a
-    ; more permanent location by DxeIpl.
-    ;
-
-    mov     ecx, 6 * 0x1000 / 4
-    xor     eax, eax
-clearPageTablesMemoryLoop:
-    mov     dword[ecx * 4 + PT_ADDR (0) - 4], eax
-    loop    clearPageTablesMemoryLoop
-
-    ;
-    ; Top level Page Directory Pointers (1 * 512GB entry)
-    ;
-    mov     dword[PT_ADDR (0)], PT_ADDR (0x1000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (4)], edx
-
-    ;
-    ; Next level Page Directory Pointers (4 * 1GB entries => 4GB)
-    ;
-    mov     dword[PT_ADDR (0x1000)], PT_ADDR (0x2000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x1004)], edx
-    mov     dword[PT_ADDR (0x1008)], PT_ADDR (0x3000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x100C)], edx
-    mov     dword[PT_ADDR (0x1010)], PT_ADDR (0x4000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x1014)], edx
-    mov     dword[PT_ADDR (0x1018)], PT_ADDR (0x5000) + PAGE_PDP_ATTR
-    mov     dword[PT_ADDR (0x101C)], edx
-
-    ;
-    ; Page Table Entries (2048 * 2MB entries => 4GB)
-    ;
-    mov     ecx, 0x800
-pageTableEntriesLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 21
-    add     eax, PAGE_2M_PDE_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000 - 8)], eax
-    mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
-    loop    pageTableEntriesLoop
-
-    OneTimeCall   IsSevEsEnabled
-    test    eax, eax
-    jz      SetCr3
-
-    ;
-    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
-    ; This requires the 2MB page for this range be broken down into 512 4KB
-    ; pages.  All will be marked encrypted, except for the GHCB.
-    ;
-    mov     ecx, (GHCB_BASE >> 21)
-    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
-
-    ;
-    ; Page Table Entries (512 * 4KB entries => 2MB)
-    ;
-    mov     ecx, 512
-pageTableEntries4kLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 12
-    add     eax, GHCB_BASE & 0xFFE0_0000
-    add     eax, PAGE_4K_PDE_ATTR
-    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
-    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
-    loop    pageTableEntries4kLoop
-
-    ;
-    ; Clear the encryption bit from the GHCB entry
-    ;
-    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
-    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
-
-    mov     ecx, GHCB_SIZE / 4
-    xor     eax, eax
-clearGhcbMemoryLoop:
-    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
-    loop    clearGhcbMemoryLoop
-
-SetCr3:
-    ;
-    ; Set CR3 now that the paging structures are available
-    ;
-    mov     eax, PT_ADDR (0)
-    mov     cr3, eax
-
-    OneTimeCallRet SetCr3ForPageTables64
-
-;
 ; Start of #VC exception handling routines
 ;
 
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9da..eacdb69ddb9f 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,182 +37,6 @@ BITS    32
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
 
-;
-; SEV-ES #VC exception handler support
-;
-; #VC handler local variable locations
-;
-%define VC_CPUID_RESULT_EAX         0
-%define VC_CPUID_RESULT_EBX         4
-%define VC_CPUID_RESULT_ECX         8
-%define VC_CPUID_RESULT_EDX        12
-%define VC_GHCB_MSR_EDX            16
-%define VC_GHCB_MSR_EAX            20
-%define VC_CPUID_REQUEST_REGISTER  24
-%define VC_CPUID_FUNCTION          28
-
-; #VC handler total local variable size
-;
-%define VC_VARIABLE_SIZE           32
-
-; #VC handler GHCB CPUID request/response protocol values
-;
-%define GHCB_CPUID_REQUEST          4
-%define GHCB_CPUID_RESPONSE         5
-%define GHCB_CPUID_REGISTER_SHIFT  30
-%define CPUID_INSN_LEN              2
-
-
-; Check if Secure Encrypted Virtualization (SEV) features are enabled.
-;
-; Register usage is tight in this routine, so multiple calls for the
-; same CPUID and MSR data are performed to keep things simple.
-;
-; Modified:  EAX, EBX, ECX, EDX, ESP
-;
-; If SEV is enabled then EAX will be at least 32.
-; If SEV is disabled then EAX will be zero.
-;
-CheckSevFeatures:
-    ; Set the first byte of the workarea to zero to communicate to the SEC
-    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
-    ; instruction will trigger a #VC exception where the first byte of the
-    ; workarea will be set to one or, if CPUID is not being intercepted,
-    ; the MSR check below will set the first byte of the workarea to one.
-    mov     byte[SEV_ES_WORK_AREA], 0
-
-    ;
-    ; Set up exception handlers to check for SEV-ES
-    ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
-    ;   stack usage)
-    ;   Establish exception handlers
-    ;
-    mov       esp, SEV_ES_VC_TOP_OF_STACK
-    mov       eax, ADDR_OF(Idtr)
-    lidt      [cs:eax]
-
-    ; Check if we have a valid (0x8000_001F) CPUID leaf
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x80000000
-    cpuid
-
-    ; This check should fail on Intel or Non SEV AMD CPUs. In future if
-    ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
-    ; same bit definition.
-    cmp       eax, 0x8000001f
-    jl        NoSev
-
-    ; Check for SEV memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 1
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 1
-    jnc       NoSev
-
-    ; Check if SEV memory encryption is enabled
-    ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 0
-    jnc       NoSev
-
-    ; Check for SEV-ES memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 3
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 3
-    jnc       GetSevEncBit
-
-    ; Check if SEV-ES is enabled
-    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 1
-    jnc       GetSevEncBit
-
-    ; Set the first byte of the workarea to one to communicate to the SEC
-    ; phase that SEV-ES is enabled.
-    mov       byte[SEV_ES_WORK_AREA], 1
-
-GetSevEncBit:
-    ; Get pte bit position to enable memory encryption
-    ; CPUID Fn8000_001F[EBX] - Bits 5:0
-    ;
-    and       ebx, 0x3f
-    mov       eax, ebx
-
-    ; The encryption bit position is always above 31
-    sub       ebx, 32
-    jns       SevSaveMask
-
-    ; Encryption bit was reported as 31 or below, enter a HLT loop
-SevEncBitLowHlt:
-    cli
-    hlt
-    jmp       SevEncBitLowHlt
-
-SevSaveMask:
-    xor       edx, edx
-    bts       edx, ebx
-
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK], 0
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
-    jmp       SevExit
-
-NoSev:
-    ;
-    ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
-    ;
-    cmp       byte[SEV_ES_WORK_AREA], 0
-    jz        NoSevPass
-
-    ;
-    ; A #VC was received, yet CPUID indicates no SEV-ES support, something
-    ; isn't right.
-    ;
-NoSevEsVcHlt:
-    cli
-    hlt
-    jmp       NoSevEsVcHlt
-
-NoSevPass:
-    xor       eax, eax
-
-SevExit:
-    ;
-    ; Clear exception handlers and stack
-    ;
-    push      eax
-    mov       eax, ADDR_OF(IdtrClear)
-    lidt      [cs:eax]
-    pop       eax
-    mov       esp, 0
-
-    OneTimeCallRet CheckSevFeatures
-
-; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
-; is enabled.
-;
-; Modified:  EAX
-;
-; If SEV-ES is enabled then EAX will be non-zero.
-; If SEV-ES is disabled then EAX will be zero.
-;
-IsSevEsEnabled:
-    xor       eax, eax
-
-    ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
-    ; SEV-ES is enabled.
-    cmp       byte[SEV_ES_WORK_AREA], 1
-    jne       SevEsDisabled
-
-    mov       eax, 1
-
-SevEsDisabled:
-    OneTimeCallRet IsSevEsEnabled
-
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
@@ -324,218 +148,3 @@ SetCr3:
     mov     cr3, eax
 
     OneTimeCallRet SetCr3ForPageTables64
-
-;
-; Start of #VC exception handling routines
-;
-
-SevEsIdtNotCpuid:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   1 - #VC was not for CPUID
-    ;
-    mov     eax, 1
-    jmp     SevEsIdtTerminate
-
-SevEsIdtNoCpuidResponse:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   2 - GHCB_CPUID_RESPONSE not received
-    ;
-    mov     eax, 2
-
-SevEsIdtTerminate:
-    ;
-    ; Use VMGEXIT to request termination. At this point the reason code is
-    ; located in EAX, so shift it left 16 bits to the proper location.
-    ;
-    ; EAX[11:0]  => 0x100 - request termination
-    ; EAX[15:12] => 0x1   - OVMF
-    ; EAX[23:16] => 0xXX  - REASON CODE
-    ;
-    shl     eax, 16
-    or      eax, 0x1100
-    xor     edx, edx
-    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
-
-    ;
-    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
-    ;
-SevEsIdtHlt:
-    hlt
-    jmp     SevEsIdtHlt
-    iret
-
-    ;
-    ; Total stack usage for the #VC handler is 44 bytes:
-    ;   - 12 bytes for the exception IRET (after popping error code)
-    ;   - 32 bytes for the local variables.
-    ;
-SevEsIdtVmmComm:
-    ;
-    ; If we're here, then we are an SEV-ES guest and this
-    ; was triggered by a CPUID instruction
-    ;
-    ; Set the first byte of the workarea to one to communicate that
-    ; a #VC was taken.
-    mov     byte[SEV_ES_WORK_AREA], 1
-
-    pop     ecx                     ; Error code
-    cmp     ecx, 0x72               ; Be sure it was CPUID
-    jne     SevEsIdtNotCpuid
-
-    ; Set up local variable room on the stack
-    ;   CPUID function         : + 28
-    ;   CPUID request register : + 24
-    ;   GHCB MSR (EAX)         : + 20
-    ;   GHCB MSR (EDX)         : + 16
-    ;   CPUID result (EDX)     : + 12
-    ;   CPUID result (ECX)     : + 8
-    ;   CPUID result (EBX)     : + 4
-    ;   CPUID result (EAX)     : + 0
-    sub     esp, VC_VARIABLE_SIZE
-
-    ; Save the CPUID function being requested
-    mov     [esp + VC_CPUID_FUNCTION], eax
-
-    ; The GHCB CPUID protocol uses the following mapping to request
-    ; a specific register:
-    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
-    ;
-    ; Set EAX as the first register to request. This will also be used as a
-    ; loop variable to request all register values (EAX to EDX).
-    xor     eax, eax
-    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
-
-    ; Save current GHCB MSR value
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     [esp + VC_GHCB_MSR_EAX], eax
-    mov     [esp + VC_GHCB_MSR_EDX], edx
-
-NextReg:
-    ;
-    ; Setup GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID function
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID request protocol
-    ;
-    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
-    cmp     eax, 4
-    jge     VmmDone
-
-    shl     eax, GHCB_CPUID_REGISTER_SHIFT
-    or      eax, GHCB_CPUID_REQUEST
-    mov     edx, [esp + VC_CPUID_FUNCTION]
-    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
-
-    ;
-    ; Read GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID register value
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID response protocol
-    ;
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     ecx, eax
-    and     ecx, 0xfff
-    cmp     ecx, GHCB_CPUID_RESPONSE
-    jne     SevEsIdtNoCpuidResponse
-
-    ; Save returned value
-    shr     eax, GHCB_CPUID_REGISTER_SHIFT
-    mov     [esp + eax * 4], edx
-
-    ; Next register
-    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
-
-    jmp     NextReg
-
-VmmDone:
-    ;
-    ; At this point we have all CPUID register values. Restore the GHCB MSR,
-    ; set the return register values and return.
-    ;
-    mov     eax, [esp + VC_GHCB_MSR_EAX]
-    mov     edx, [esp + VC_GHCB_MSR_EDX]
-    mov     ecx, 0xc0010130
-    wrmsr
-
-    mov     eax, [esp + VC_CPUID_RESULT_EAX]
-    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
-    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
-    mov     edx, [esp + VC_CPUID_RESULT_EDX]
-
-    add     esp, VC_VARIABLE_SIZE
-
-    ; Update the EIP value to skip over the now handled CPUID instruction
-    ; (the CPUID instruction has a length of 2)
-    add     word [esp], CPUID_INSN_LEN
-    iret
-
-ALIGN   2
-
-Idtr:
-    dw      IDT_END - IDT_BASE - 1  ; Limit
-    dd      ADDR_OF(IDT_BASE)       ; Base
-
-IdtrClear:
-    dw      0                       ; Limit
-    dd      0                       ; Base
-
-ALIGN   16
-
-;
-; The Interrupt Descriptor Table (IDT)
-;   This will be used to determine if SEV-ES is enabled.  Upon execution
-;   of the CPUID instruction, a VMM Communication Exception will occur.
-;   This will tell us if SEV-ES is enabled.  We can use the current value
-;   of the GHCB MSR to determine the SEV attributes.
-;
-IDT_BASE:
-;
-; Vectors 0 - 28 (No handlers)
-;
-%rep 29
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-;
-; Vector 29 (VMM Communication Exception)
-;
-    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
-;
-; Vectors 30 - 31 (No handlers)
-;
-%rep 2
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-IDT_END:
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 5fbacaed5f9d..8a3269cfc212 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -77,6 +77,7 @@
   %define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/Flat32ToFlat64.asm"
+%include "Ia32/AmdSev.asm"
 %include "Ia32/PageTables64.asm"
 %endif
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 02/28] OvmfPkg/ResetVector: add the macro to invoke MSR protocol based VMGEXIT
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 01/28] OvmfPkg/ResetVector: move SEV specific code in a separate file Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 03/28] OvmfPkg/ResetVector: add the macro to request guest termination Brijesh Singh
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The upcoming SEV-SNP support will need to make a few additional MSR
protocol based VMGEXIT's. Add a macro that wraps the common setup and
response validation logic in one place to keep the code readable.

While at it, define SEV_STATUS_MSR that will be used to get the SEV STATUS
MSR instead of open coding it.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia32/AmdSev.asm | 71 +++++++++++++++++++----------
 1 file changed, 47 insertions(+), 24 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index b32dd3b5d656..2c478cda314b 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -36,6 +36,44 @@ BITS    32
 %define CPUID_INSN_LEN              2
 
 
+%define SEV_GHCB_MSR                0xc0010130
+%define SEV_STATUS_MSR              0xc0010131
+
+; Macro is used to issue the MSR protocol based VMGEXIT. The caller is
+; responsible to populate values in the EDX:EAX registers. After the vmmcall
+; returns, it verifies that the response code matches with the expected
+; code. If it does not match then terminate the guest. The result of request
+; is returned in the EDX:EAX.
+;
+; args 1:Request code, 2: Response code
+%macro VmgExit 2
+    ;
+    ; Add request code:
+    ;   GHCB_MSR[11:0]  = Request code
+    or      eax, %1
+
+    mov     ecx, SEV_GHCB_MSR
+    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
+
+    mov     ecx, SEV_GHCB_MSR
+    rdmsr
+
+    ;
+    ; Verify the reponse code, if it does not match then request to terminate
+    ;   GHCB_MSR[11:0]  = Response code
+    mov     ecx, eax
+    and     ecx, 0xfff
+    cmp     ecx, %2
+    jne     SevEsUnexpectedRespTerminate
+%endmacro
+
 ; Check if Secure Encrypted Virtualization (SEV) features are enabled.
 ;
 ; Register usage is tight in this routine, so multiple calls for the
@@ -85,7 +123,7 @@ CheckSevFeatures:
 
     ; Check if SEV memory encryption is enabled
     ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
-    mov       ecx, 0xc0010131
+    mov       ecx, SEV_STATUS_MSR
     rdmsr
     bt        eax, 0
     jnc       NoSev
@@ -100,7 +138,7 @@ CheckSevFeatures:
 
     ; Check if SEV-ES is enabled
     ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
-    mov       ecx, 0xc0010131
+    mov       ecx, SEV_STATUS_MSR
     rdmsr
     bt        eax, 1
     jnc       GetSevEncBit
@@ -197,10 +235,10 @@ SevEsIdtNotCpuid:
     mov     eax, 1
     jmp     SevEsIdtTerminate
 
-SevEsIdtNoCpuidResponse:
+SevEsUnexpectedRespTerminate:
     ;
     ; Use VMGEXIT to request termination.
-    ;   2 - GHCB_CPUID_RESPONSE not received
+    ;   2 - Unexpected Response is received
     ;
     mov     eax, 2
 
@@ -216,7 +254,7 @@ SevEsIdtTerminate:
     shl     eax, 16
     or      eax, 0x1100
     xor     edx, edx
-    mov     ecx, 0xc0010130
+    mov     ecx, SEV_GHCB_MSR
     wrmsr
     ;
     ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
@@ -276,7 +314,7 @@ SevEsIdtVmmComm:
     mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
 
     ; Save current GHCB MSR value
-    mov     ecx, 0xc0010130
+    mov     ecx, SEV_GHCB_MSR
     rdmsr
     mov     [esp + VC_GHCB_MSR_EAX], eax
     mov     [esp + VC_GHCB_MSR_EDX], edx
@@ -293,31 +331,16 @@ NextReg:
     jge     VmmDone
 
     shl     eax, GHCB_CPUID_REGISTER_SHIFT
-    or      eax, GHCB_CPUID_REQUEST
     mov     edx, [esp + VC_CPUID_FUNCTION]
-    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
+    VmgExit GHCB_CPUID_REQUEST, GHCB_CPUID_RESPONSE
 
     ;
-    ; Read GHCB MSR
+    ; Response GHCB MSR
     ;   GHCB_MSR[63:32] = CPUID register value
     ;   GHCB_MSR[31:30] = CPUID register
     ;   GHCB_MSR[11:0]  = CPUID response protocol
     ;
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     ecx, eax
-    and     ecx, 0xfff
-    cmp     ecx, GHCB_CPUID_RESPONSE
-    jne     SevEsIdtNoCpuidResponse
 
     ; Save returned value
     shr     eax, GHCB_CPUID_REGISTER_SHIFT
@@ -335,7 +358,7 @@ VmmDone:
     ;
     mov     eax, [esp + VC_GHCB_MSR_EAX]
     mov     edx, [esp + VC_GHCB_MSR_EDX]
-    mov     ecx, 0xc0010130
+    mov     ecx, SEV_GHCB_MSR
     wrmsr
 
     mov     eax, [esp + VC_CPUID_RESULT_EAX]
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 03/28] OvmfPkg/ResetVector: add the macro to request guest termination
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 01/28] OvmfPkg/ResetVector: move SEV specific code in a separate file Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 02/28] OvmfPkg/ResetVector: add the macro to invoke MSR protocol based VMGEXIT Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 04/28] OvmfPkg: reserve SNP secrets page Brijesh Singh
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The upcoming SEV-SNP support will need to make a few additional guest
termination requests depending on the failure type. Let's move the logic
to request the guest termination into a macro to keep the code readable.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia32/AmdSev.asm | 87 +++++++++++++++--------------
 1 file changed, 45 insertions(+), 42 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 2c478cda314b..c4c00056f9f3 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -39,6 +39,13 @@ BITS    32
 %define SEV_GHCB_MSR                0xc0010130
 %define SEV_STATUS_MSR              0xc0010131
 
+; The #VC was not for CPUID
+%define TERM_VC_NOT_CPUID           1
+
+; The unexpected response code
+%define TERM_UNEXPECTED_RESP_CODE   2
+
+
 ; Macro is used to issue the MSR protocol based VMGEXIT. The caller is
 ; responsible to populate values in the EDX:EAX registers. After the vmmcall
 ; returns, it verifies that the response code matches with the expected
@@ -74,6 +81,43 @@ BITS    32
     jne     SevEsUnexpectedRespTerminate
 %endmacro
 
+; Macro to terminate the guest using the VMGEXIT.
+; arg 1: reason code
+%macro TerminateVmgExit 1
+    mov     eax, %1
+    ;
+    ; Use VMGEXIT to request termination. At this point the reason code is
+    ; located in EAX, so shift it left 16 bits to the proper location.
+    ;
+    ; EAX[11:0]  => 0x100 - request termination
+    ; EAX[15:12] => 0x1   - OVMF
+    ; EAX[23:16] => 0xXX  - REASON CODE
+    ;
+    shl     eax, 16
+    or      eax, 0x1100
+    xor     edx, edx
+    mov     ecx, SEV_GHCB_MSR
+    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
+
+    ;
+    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
+    ;
+%%TerminateHlt:
+    hlt
+    jmp     %%TerminateHlt
+%endmacro
+
+; Terminate the guest due to unexpected response code.
+SevEsUnexpectedRespTerminate:
+    TerminateVmgExit    TERM_UNEXPECTED_RESP_CODE
+
 ; Check if Secure Encrypted Virtualization (SEV) features are enabled.
 ;
 ; Register usage is tight in this routine, so multiple calls for the
@@ -228,48 +272,7 @@ SevEsDisabled:
 ;
 
 SevEsIdtNotCpuid:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   1 - #VC was not for CPUID
-    ;
-    mov     eax, 1
-    jmp     SevEsIdtTerminate
-
-SevEsUnexpectedRespTerminate:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   2 - Unexpected Response is received
-    ;
-    mov     eax, 2
-
-SevEsIdtTerminate:
-    ;
-    ; Use VMGEXIT to request termination. At this point the reason code is
-    ; located in EAX, so shift it left 16 bits to the proper location.
-    ;
-    ; EAX[11:0]  => 0x100 - request termination
-    ; EAX[15:12] => 0x1   - OVMF
-    ; EAX[23:16] => 0xXX  - REASON CODE
-    ;
-    shl     eax, 16
-    or      eax, 0x1100
-    xor     edx, edx
-    mov     ecx, SEV_GHCB_MSR
-    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
-
-    ;
-    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
-    ;
-SevEsIdtHlt:
-    hlt
-    jmp     SevEsIdtHlt
+    TerminateVmgExit TERM_VC_NOT_CPUID
     iret
 
     ;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 04/28] OvmfPkg: reserve SNP secrets page
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (2 preceding siblings ...)
  2021-06-30 12:52 ` [RFC PATCH v5 03/28] OvmfPkg/ResetVector: add the macro to request guest termination Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 05/28] OvmfPkg: reserve CPUID page for SEV-SNP Brijesh Singh
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

During the SNP guest launch sequence, a special secrets page needs to be
inserted by the VMM. The PSP will populate the page; it will contain the
VM Platform Communication Key (VMPCKs) used by the guest to send and
receive secure messages to the PSP.

The purpose of the secrets page in the SEV-SNP is different from the one
used in SEV guests. In SEV, the secrets page contains the guest owner's
private data after the remote attestation.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec    | 7 +++++++
 OvmfPkg/OvmfPkgX64.fdf | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 6ae733f6e39f..106a368ec975 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -321,6 +321,13 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase|0x0|UINT32|0x42
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize|0x0|UINT32|0x43
 
+  ## The base address and size of the SEV-SNP Secrets Area that contains
+  #  the VM platform communication key used to send and recieve the
+  #  messages to the PSP. If this is set in the .fdf, the platform
+  #  is responsible to reserve this area from DXE phase overwrites.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|0|UINT32|0x47
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize|0|UINT32|0x48
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 5fa8c0895808..902c6a4e9ea1 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -88,6 +88,9 @@ [FD.MEMFD]
 0x00C000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
 
+0x00D000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 05/28] OvmfPkg: reserve CPUID page for SEV-SNP
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (3 preceding siblings ...)
  2021-06-30 12:52 ` [RFC PATCH v5 04/28] OvmfPkg: reserve SNP secrets page Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:52 ` [RFC PATCH v5 06/28] OvmfPkg/ResetVector: introduce SEV-SNP boot block GUID Brijesh Singh
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Platform features and capabilities are traditionally discovered via the
CPUID instruction. Hypervisors typically trap and emulate the CPUID
instruction for a variety of reasons. There are some cases where incorrect
CPUID information can potentially lead to a security issue. The SEV-SNP
firmware provides a feature to filter the CPUID results through the PSP.
The filtered CPUID values are saved on a special page for the guest to
consume. Reserve a page in MEMFD that will contain the results of
filtered CPUID values.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec    | 6 ++++++
 OvmfPkg/OvmfPkgX64.fdf | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 106a368ec975..93f759534ade 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -328,6 +328,12 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|0|UINT32|0x47
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize|0|UINT32|0x48
 
+  ## The base address and size of the SEV-SNP CPUID Area that contains
+  #  the PSP filtered CPUID results. If this is set in the .fdf, the
+  #  platform is responsible to reserve this area from DXE phase overwrites.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase|0|UINT32|0x49
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize|0|UINT32|0x50
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 902c6a4e9ea1..3e257aaf72bd 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -91,6 +91,9 @@ [FD.MEMFD]
 0x00D000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
 
+0x00E000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 06/28] OvmfPkg/ResetVector: introduce SEV-SNP boot block GUID
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (4 preceding siblings ...)
  2021-06-30 12:52 ` [RFC PATCH v5 05/28] OvmfPkg: reserve CPUID page for SEV-SNP Brijesh Singh
@ 2021-06-30 12:52 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:52 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Introduce a new SEV-SNP boot-specific GUID block. The block is used to
communicate the secrets and cpuid memory area reserved by the guest BIOS.
When SEV-SNP is enabled, the hypervisor will locate the SEV-SNP boot
block to get the location of the Secrets and CPUID page and call the
PSP firmware command to populate those memory areas.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/ResetVector.inf          |  4 ++++
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 22 ++++++++++++++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb        |  4 ++++
 3 files changed, 30 insertions(+)

diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index dc38f68919cd..9a95d8687345 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -47,3 +47,7 @@ [Pcd]
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 9c0b5853a46f..ecf1dbcc2caf 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,28 @@ TIMES (15 - ((guidedStructureEnd - guidedStructureStart + 15) % 16)) DB 0
 ;
 guidedStructureStart:
 
+;
+; SEV-SNP boot support
+;
+; sevSnpBlock:
+;   For the initial boot of SEV-SNP guest, a CPUID and Secrets page must
+;   be reserved by the BIOS at a RAM area defined by SNP_CPUID_BASE and
+;   SNP_SECRETS_BASE. A hypervisor will locate this information using the
+;   SEV-SNP boot block GUID and provide the GPA to the PSP to populate
+;   the memory area with the required information..
+;
+; GUID (SEV-SNP boot block): bd39c0c2-2f8e-4243-83e8-1b74cebcb7d9
+;
+sevSnpBootBlockStart:
+    DD      SNP_SECRETS_BASE
+    DD      SNP_SECRETS_SIZE
+    DD      SNP_CPUID_BASE
+    DD      SNP_CPUID_SIZE
+    DW      sevSnpBootBlockEnd - sevSnpBootBlockStart
+    DB      0xC2, 0xC0, 0x39, 0xBD, 0x8e, 0x2F, 0x43, 0x42
+    DB      0x83, 0xE8, 0x1B, 0x74, 0xCE, 0xBC, 0xB7, 0xD9
+sevSnpBootBlockEnd:
+
 ;
 ; SEV Secret block
 ;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 8a3269cfc212..247f4eb0dc5e 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -89,5 +89,9 @@
   %define SEV_ES_AP_RESET_IP  FixedPcdGet32 (PcdSevEsWorkAreaBase)
   %define SEV_LAUNCH_SECRET_BASE  FixedPcdGet32 (PcdSevLaunchSecretBase)
   %define SEV_LAUNCH_SECRET_SIZE  FixedPcdGet32 (PcdSevLaunchSecretSize)
+  %define SNP_CPUID_BASE  FixedPcdGet32 (PcdOvmfSnpCpuidBase)
+  %define SNP_CPUID_SIZE  FixedPcdGet32 (PcdOvmfSnpCpuidSize)
+  %define SNP_SECRETS_BASE  FixedPcdGet32 (PcdOvmfSnpSecretsBase)
+  %define SNP_SECRETS_SIZE  FixedPcdGet32 (PcdOvmfSnpSecretsSize)
 %include "Ia16/ResetVectorVtf0.asm"
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (5 preceding siblings ...)
  2021-06-30 12:52 ` [RFC PATCH v5 06/28] OvmfPkg/ResetVector: introduce SEV-SNP boot block GUID Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-07-31  8:44   ` Erdem Aktas
  2021-06-30 12:53 ` [RFC PATCH v5 08/28] OvmfPkg/ResetVector: invalidate the GHCB page Brijesh Singh
                   ` (21 subsequent siblings)
  28 siblings, 1 reply; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

An SEV-SNP guest requires that private memory (aka pages mapped encrypted)
must be validated before being accessed.

The validation process consist of the following sequence:

1) Set the memory encryption attribute in the page table (aka C-bit).
   Note: If the processor is in non-PAE mode, then all the memory accesses
   are considered private.
2) Add the memory range as private in the RMP table. This can be performed
   using the Page State Change VMGEXIT defined in the GHCB specification.
3) Use the PVALIDATE instruction to set the Validated Bit in the RMP table.

During the guest creation time, the VMM encrypts the OVMF_CODE.fd using
the SEV-SNP firmware provided LAUNCH_UPDATE_DATA command. In addition to
encrypting the content, the command also validates the memory region.
This allows us to execute the code without going through the validation
sequence.

During execution, the reset vector need to access some data pages
(such as page tables, SevESWorkarea, Sec stack). The data pages are
accessed as private memory. The data pages are not part of the
OVMF_CODE.fd, so they were not validated during the guest creation.

There are two approaches we can take to validate the data pages before
the access:

a) Enhance the OVMF reset vector code to validate the pages as described
   above (go through step 2 - 3).
OR
b) Validate the pages during the guest creation time. The SEV firmware
   provides a command which can be used by the VMM to validate the pages
   without affecting the measurement of the launch.

Approach #b seems much simpler; it does not require any changes to the
OVMF reset vector code.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                          | 5 +++++
 OvmfPkg/OvmfPkgX64.fdf                       | 8 +++++++-
 OvmfPkg/ResetVector/ResetVector.inf          | 2 ++
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 5 +++++
 OvmfPkg/ResetVector/ResetVector.nasmb        | 2 ++
 5 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 93f759534ade..d0ec14ca2318 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -334,6 +334,11 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase|0|UINT32|0x49
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize|0|UINT32|0x50
 
+  ## The start and end of pre-validated memory region by the hypervisor
+  #  through the SEV-SNP firmware.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart|0x0|UINT32|0x51
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd|0x0|UINT32|0x52
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 3e257aaf72bd..6bce3369e10d 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -105,7 +105,13 @@ [FD.MEMFD]
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize
 FV = DXEFV
 
-################################################################################
+##########################################################################################
+#
+# The range of the pages pre-validated through the SEV-SNP firmware.
+#
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart = $(MEMFD_BASE_ADDRESS) + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd = $(MEMFD_BASE_ADDRESS) + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
+##########################################################################################
 
 [FV.SECFV]
 FvNameGuid         = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 9a95d8687345..32206855193f 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -51,3 +51,5 @@ [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index ecf1dbcc2caf..c5a062e69b26 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -57,9 +57,14 @@ guidedStructureStart:
 ;   SEV-SNP boot block GUID and provide the GPA to the PSP to populate
 ;   the memory area with the required information..
 ;
+;   In order to boot the SEV-SNP guest the hypervisor must pre-validated the
+;   memory range from SNP_HV_VALIDATED_START to SNP_HV_VALIDATED_END.
+;
 ; GUID (SEV-SNP boot block): bd39c0c2-2f8e-4243-83e8-1b74cebcb7d9
 ;
 sevSnpBootBlockStart:
+    DD      SNP_HV_VALIDATED_START
+    DD      SNP_HV_VALIDATED_END
     DD      SNP_SECRETS_BASE
     DD      SNP_SECRETS_SIZE
     DD      SNP_CPUID_BASE
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 247f4eb0dc5e..645e949845f9 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -93,5 +93,7 @@
   %define SNP_CPUID_SIZE  FixedPcdGet32 (PcdOvmfSnpCpuidSize)
   %define SNP_SECRETS_BASE  FixedPcdGet32 (PcdOvmfSnpSecretsBase)
   %define SNP_SECRETS_SIZE  FixedPcdGet32 (PcdOvmfSnpSecretsSize)
+  %define SNP_HV_VALIDATED_START FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedStart)
+  %define SNP_HV_VALIDATED_END FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedEnd)
 %include "Ia16/ResetVectorVtf0.asm"
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 08/28] OvmfPkg/ResetVector: invalidate the GHCB page
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (6 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 09/28] OvmfPkg/ResetVector: check the vmpl level Brijesh Singh
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The GHCB page is part of a pre-validated memory range specified through
the SnpBootBlock GUID. When SEV-SNP is active, the GHCB page is
pre-validated by the hyperivosr during the SNP guest creation. On boot,
the reset vector maps the GHCB page as un-encrypted in the initial page
table. Just clearing the encryption attribute from the page table is not
enough. To maintain the security guarantees, the page must be invalidated.

The page invalidation consists of two steps:

1. Use the PVALIDATE instruction to clear Validated Bit from the RMP table.
2. Use the Page State Change VMGEXIT to ask hypervisor to change the page
   state to shared in the RMP table.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia32/AmdSev.asm       | 125 ++++++++++++++++++++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm |  13 +++
 2 files changed, 138 insertions(+)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index c4c00056f9f3..b6f33d049a43 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -8,6 +8,8 @@
 ;
 ;------------------------------------------------------------------------------
 
+%include "Nasm.inc"
+
 BITS    32
 
 ;
@@ -45,6 +47,25 @@ BITS    32
 ; The unexpected response code
 %define TERM_UNEXPECTED_RESP_CODE   2
 
+; SNP page state change failure
+%define TERM_PAGE_STATE_CHANAGE     3
+
+; Hypervisor does not support SEV-SNP feature
+%define TERM_HV_UNSUPPORTED_FEATURE 4
+
+; GHCB SEV Information MSR protocol
+%define GHCB_SEV_INFORMATION_REQUEST        2
+%define GHCB_SEV_INFORMATION_RESPONSE       1
+
+; 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 Hypervisor features MSR protocol
+%define GHCB_HYPERVISOR_FEATURES_REQUEST    128
+%define GHCB_HYPERVISOR_FEATURES_RESPONSE   129
 
 ; Macro is used to issue the MSR protocol based VMGEXIT. The caller is
 ; responsible to populate values in the EDX:EAX registers. After the vmmcall
@@ -247,6 +268,110 @@ SevExit:
 
     OneTimeCallRet CheckSevFeatures
 
+; The version 2 of GHCB specification added the support to query the hypervisor
+; features. If the GHCB version is >=2 then read the hypervisor features and
+; verify that SEV-SNP feature is supported.
+;
+CheckSnpHypervisorFeatures:
+    ; Get the SEV Information
+    xor     eax, eax
+    xor     edx, edx
+
+    VmgExit GHCB_SEV_INFORMATION_REQUEST, GHCB_SEV_INFORMATION_RESPONSE
+
+    ;
+    ; SEV Information Response GHCB MSR
+    ;   GHCB_MSR[63:48] = Maximum protocol version
+    ;   GHCB_MSR[47:32] = Minimum protocol version
+    ;
+    shr     edx, 16
+    cmp     edx, 2
+    jl      SevSnpUnsupportedFeature
+
+    ; Get the hypervisor features
+    xor     eax, eax
+    xor     edx, edx
+
+    VmgExit GHCB_HYPERVISOR_FEATURES_REQUEST, GHCB_HYPERVISOR_FEATURES_RESPONSE
+
+    ;
+    ; Hypervisor features reponse
+    ;   GHCB_MSR[63:12] = Features bitmap
+    ;       BIT0        = SEV-SNP Supported
+    ;
+    shr     eax, 12
+    bt      eax, 0
+    jnc     SevSnpUnsupportedFeature
+
+CheckSnpHypervisorFeaturesDone:
+    OneTimeCallRet CheckSnpHypervisorFeatures
+
+; If its an SEV-SNP guest then use the page state change VMGEXIT to invalidate
+; the GHCB page.
+;
+; Modified:  EAX, EBX, ECX, EDX
+;
+InvalidateGHCBPage:
+    ; Check if SEV-SNP is enabled
+    ;  MSR_0xC0010131 - Bit 2 (SEV-SNP enabled)
+    mov       ecx, SEV_STATUS_MSR
+    rdmsr
+    bt        eax, 2
+    jnc       InvalidateGHCBPageDone
+
+    ; Verify that SEV-SNP feature is supported by the hypervisor.
+    OneTimeCall   CheckSnpHypervisorFeatures
+
+    ; Use PVALIDATE instruction to invalidate the page
+    mov     eax, GHCB_BASE
+    mov     ecx, 0
+    mov     edx, 0
+    PVALIDATE
+
+    ; Save the carry flag to be use later.
+    setc    dl
+
+    ; If PVALIDATE fail then abort the launch.
+    cmp     eax, 0
+    jne     SevSnpPageStateFailureTerminate
+
+    ; Check the carry flag to determine if RMP entry was updated.
+    cmp     dl, 0
+    jne     SevSnpPageStateFailureTerminate
+
+    ; 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
+    ;
+    mov     eax, (GHCB_BASE >> 12)
+    shl     eax, 12
+    mov     edx, (GHCB_PAGE_STATE_SHARED << 20)
+
+    VmgExit  GHCB_PAGE_STATE_CHANGE_REQUEST, GHCB_PAGE_STATE_CHANGE_RESPONSE
+
+    ;
+    ; Response GHCB MSR
+    ;   GHCB_MSR[63:12] = Error code
+    ;
+    cmp     edx, 0
+    jnz     SevSnpPageStateFailureTerminate
+
+InvalidateGHCBPageDone:
+    OneTimeCallRet InvalidateGHCBPage
+
+; Terminate the SEV-SNP guest due to the page state change failure
+SevSnpPageStateFailureTerminate:
+    TerminateVmgExit   TERM_PAGE_STATE_CHANAGE
+
+; Terminate the SEV-SNP guest because hypervisor does not support
+; the SEV-SNP feature
+SevSnpUnsupportedFeature:
+    TerminateVmgExit   TERM_HV_UNSUPPORTED_FEATURE
+
+
 ; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
 ; is enabled.
 ;
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index eacdb69ddb9f..f587ef912e4c 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -140,6 +140,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


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 09/28] OvmfPkg/ResetVector: check the vmpl level
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (7 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 08/28] OvmfPkg/ResetVector: invalidate the GHCB page Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 10/28] UefiCpuPkg: Define the SEV-SNP specific dynamic PCDs Brijesh Singh
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Virtual Machine Privilege Level (VMPL) is an optional feature in the
SEV-SNP architecture, which allows a guest VM to divide its address space
into four levels. The level can be used to provide the hardware isolated
abstraction layers with a VM. The VMPL0 is the highest privilege, and
VMPL3 is the least privilege. Certain operations must be done by the VMPL0
software, such as:

* Validate or invalidate memory range (PVALIDATE instruction)
* Allocate VMSA page (RMPADJUST instruction when VMSA=1)

The initial SEV-SNP support assumes that it's running on VMPL0. Let's add
a check to make sure that we are running at VMPL0 before continuing the
boot. There is no easy method to query the current VMPL level. One simple
approach is to call PVALIDATE instruction and if the instruction causes
a #GP then its SEV-SNP guest is not booted under VMPL0. See the AMD APL
volume 3 (PVALIDATE) for additional information on the PVALIDATE.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/ResetVector/Ia32/AmdSev.asm | 89 ++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index b6f33d049a43..a9101ca8b8b2 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -53,6 +53,12 @@ BITS    32
 ; Hypervisor does not support SEV-SNP feature
 %define TERM_HV_UNSUPPORTED_FEATURE 4
 
+; SEV-SNP guest is not launched at VMPL-0
+%define TERM_SNP_NOT_VMPL0          5
+
+; The #VC is not for PVALIDATE
+%define TERM_VC_NOT_PVALIDATE       6
+
 ; GHCB SEV Information MSR protocol
 %define GHCB_SEV_INFORMATION_REQUEST        2
 %define GHCB_SEV_INFORMATION_RESPONSE       1
@@ -139,6 +145,25 @@ BITS    32
 SevEsUnexpectedRespTerminate:
     TerminateVmgExit    TERM_UNEXPECTED_RESP_CODE
 
+; Check whether we're booted under the VMPL-0.
+;
+; There is no straightforward way to query the current VMPL level. The simplest
+; method is to use the PVALIDATE instruction to change the page state. If its
+; not a VMPL-0 guest then PVALIDATE will cause #GP.
+;
+CheckSnpVmpl0:
+    ; This routine is part of the ROM, and should have been validated by the SNP
+    ; guest launch sequence. So its safe to re-validate the page containing
+    ; this routine.
+    mov     eax, ADDR_OF(CheckSnpVmpl0)
+    mov     ecx, 0
+    mov     edx, 1
+    PVALIDATE
+
+    ; We will reach here only if we are running at VMPL-0.
+
+    OneTimeCallRet    CheckSnpVmpl0
+
 ; Check if Secure Encrypted Virtualization (SEV) features are enabled.
 ;
 ; Register usage is tight in this routine, so multiple calls for the
@@ -193,6 +218,17 @@ CheckSevFeatures:
     bt        eax, 0
     jnc       NoSev
 
+    ; Check if we're SEV-SNP guest and booted under VMPL-0.
+    ;
+    ; This check should happen here because the PVALIDATE instruction
+    ; used in the check will cause an exception. The IDT is active
+    ; during the CheckSevFeatures only.
+    ;
+    bt        eax, 2
+    jnc       SkipCheckSnpVmpl0
+    OneTimeCall     CheckSnpVmpl0
+
+SkipCheckSnpVmpl0:
     ; Check for SEV-ES memory encryption feature:
     ; CPUID  Fn8000_001F[EAX] - Bit 3
     ;   CPUID raises a #VC exception if running as an SEV-ES guest
@@ -393,6 +429,36 @@ IsSevEsEnabled:
 SevEsDisabled:
     OneTimeCallRet IsSevEsEnabled
 
+; Start handling of #GP exception handling routines
+;
+SevEsIdtNotPvalidate:
+    TerminateVmgExit TERM_VC_NOT_PVALIDATE
+    iret
+
+SevSnpGpException:
+    ;
+    ; If we're here, then we are an SEV-SNP guest and this
+    ; was triggered by a PVALIDATE instruction.
+    ;
+    ; Verify that its an PVALIDATE instruction
+    ; The exception stack looks like this:
+    ;     +---------+
+    ;     | ....    |
+    ;     | eip     |
+    ;     | err code|
+    ;     +---------+
+    pop     ebx
+    pop     ebx
+    mov     ecx, [ebx]
+    cmp     ecx, 0xff010ff2       ; Compare EIP with PVALIDATE menomics
+    jne     SevEsIdtNotPvalidate
+
+    ; The #GP was triggered by the PVALIDATE instruction, this will happen
+    ; only when we're not running at VMPL-0
+    ;
+    TerminateVmgExit TERM_SNP_NOT_VMPL0
+    iret
+
 ; Start of #VC exception handling routines
 ;
 
@@ -522,15 +588,34 @@ ALIGN   16
 ;
 IDT_BASE:
 ;
-; Vectors 0 - 28 (No handlers)
+; Vectors 0 - 12 (No handlers)
 ;
-%rep 29
+%rep 13
     dw      0                                    ; Offset low bits 15..0
     dw      0x10                                 ; Selector
     db      0                                    ; Reserved
     db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
     dw      0                                    ; Offset high bits 31..16
 %endrep
+;
+; Vector 13 (GP Exception)
+;
+    dw      (ADDR_OF(SevSnpGpException) & 0xffff)  ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      (ADDR_OF(SevSnpGpException) >> 16)   ; Offset high bits 31..16
+;
+; Vectors 14 - 28 (No handlers)
+;
+%rep 15
+    dw      0                                    ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      0                                    ; Offset high bits 31..16
+%endrep
+
 ;
 ; Vector 29 (VMM Communication Exception)
 ;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 10/28] UefiCpuPkg: Define the SEV-SNP specific dynamic PCDs
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (8 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 09/28] OvmfPkg/ResetVector: check the vmpl level Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 11/28] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Define the PCDs used by the MpInitLib while creating the AP when SEV-SNP
is active in the guest VM.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 62acb291f309..0ec25871a50f 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -396,5 +396,16 @@ [PcdsDynamic, PcdsDynamicEx]
   # @Prompt SEV-ES Status
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x60000016
 
+  ## This dynamic PCD indicates whether SEV-SNP is enabled
+  #   TRUE  - SEV-SNP is enabled
+  #   FALSE - SEV-SNP is not enabled
+  # @Prompt SEV-SNP Status
+  gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled|FALSE|BOOLEAN|0x60000017
+
+  ## This dynamic PCD contains the hypervisor features value obtained through the GHCB HYPERVISOR
+  #  features VMGEXIT defined in the version 2 of GHCB spec.
+  # @Prompt GHCB Hypervisor Features
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures|0x0|UINT64|0x60000018
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 11/28] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled()
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (9 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 10/28] UefiCpuPkg: Define the SEV-SNP specific dynamic PCDs Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 12/28] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Create a function that can be used to determine if VM is running as an
SEV-SNP guest.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Include/Library/MemEncryptSevLib.h    | 12 +++++++++
 .../DxeMemEncryptSevLibInternal.c             | 27 +++++++++++++++++++
 .../PeiMemEncryptSevLibInternal.c             | 27 +++++++++++++++++++
 .../SecMemEncryptSevLibInternal.c             | 19 +++++++++++++
 4 files changed, 85 insertions(+)

diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index 76d06c206c8b..2425d8ba0a36 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -66,6 +66,18 @@ typedef enum {
   MemEncryptSevAddressRangeError,
 } MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE;
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  );
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
index 2816f859a0c4..057129723824 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c
@@ -19,6 +19,7 @@
 
 STATIC BOOLEAN mSevStatus = FALSE;
 STATIC BOOLEAN mSevEsStatus = FALSE;
+STATIC BOOLEAN mSevSnpStatus = FALSE;
 STATIC BOOLEAN mSevStatusChecked = FALSE;
 
 STATIC UINT64  mSevEncryptionMask = 0;
@@ -82,11 +83,37 @@ InternalMemEncryptSevStatus (
     if (Msr.Bits.SevEsBit) {
       mSevEsStatus = TRUE;
     }
+
+    //
+    // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+    //
+    if (Msr.Bits.SevSnpBit) {
+      mSevSnpStatus = TRUE;
+    }
   }
 
   mSevStatusChecked = TRUE;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus ();
+  }
+
+  return mSevSnpStatus;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
index e2fd109d120f..b561f211f577 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c
@@ -19,6 +19,7 @@
 
 STATIC BOOLEAN mSevStatus = FALSE;
 STATIC BOOLEAN mSevEsStatus = FALSE;
+STATIC BOOLEAN mSevSnpStatus = FALSE;
 STATIC BOOLEAN mSevStatusChecked = FALSE;
 
 STATIC UINT64  mSevEncryptionMask = 0;
@@ -82,11 +83,37 @@ InternalMemEncryptSevStatus (
     if (Msr.Bits.SevEsBit) {
       mSevEsStatus = TRUE;
     }
+
+    //
+    // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+    //
+    if (Msr.Bits.SevSnpBit) {
+      mSevSnpStatus = TRUE;
+    }
   }
 
   mSevStatusChecked = TRUE;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus ();
+  }
+
+  return mSevSnpStatus;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
index 56d8f3f3183f..69852779e2ff 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c
@@ -62,6 +62,25 @@ InternalMemEncryptSevStatus (
   return ReadSevMsr ? AsmReadMsr32 (MSR_SEV_STATUS) : 0;
 }
 
+/**
+  Returns a boolean to indicate whether SEV-SNP is enabled.
+
+  @retval TRUE           SEV-SNP is enabled
+  @retval FALSE          SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+  VOID
+  )
+{
+  MSR_SEV_STATUS_REGISTER           Msr;
+
+  Msr.Uint32 = InternalMemEncryptSevStatus ();
+
+  return Msr.Bits.SevSnpBit ? TRUE : FALSE;
+}
+
 /**
   Returns a boolean to indicate whether SEV-ES is enabled.
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 12/28] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (10 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 11/28] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 13/28] OvmfPkg/PlatformPei: " Brijesh Singh
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The SEV-SNP guest requires that GHCB GPA must be registered before using.
See the GHCB specification section 2.3.2 for more details.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/Sec/SecMain.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 9db67e17b2aa..c10441ddf472 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -750,6 +750,79 @@ SevEsProtocolFailure (
   CpuDeadLoop ();
 }
 
+/**
+  Determine if SEV-SNP is active.
+
+  @retval TRUE   SEV-SNP is enabled
+  @retval FALSE  SEV-SNP is not enabled
+
+**/
+STATIC
+BOOLEAN
+SevSnpIsEnabled (
+  VOID
+  )
+{
+  MSR_SEV_STATUS_REGISTER           Msr;
+
+  //
+  // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.
+  //
+  Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
+
+  //
+  // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
+  //
+  if (Msr.Bits.SevSnpBit) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+STATIC
+VOID
+SevSnpGhcbRegister (
+  UINTN   Address
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
+  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
+
+  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
+
+  //
+  // Save the current MSR Value
+  //
+  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // Use the GHCB MSR Protocol to request to register the GPA.
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
+  Msr.GhcbGpaRegister.GuestFrameNumber = GuestFrameNumber;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // If hypervisor responded with a different GPA than requested then fail.
+  //
+  if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
+      (Msr.GhcbGpaRegister.GuestFrameNumber != GuestFrameNumber)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  //
+  // Restore the MSR
+  //
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
+}
+
 /**
   Validate the SEV-ES/GHCB protocol level.
 
@@ -791,6 +864,17 @@ SevEsProtocolCheck (
     SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
   }
 
+  //
+  // We cannot use the MemEncryptSevSnpIsEnabled () because the
+  // ProcessLibraryConstructorList () is not called yet.
+  //
+  if (SevSnpIsEnabled ()) {
+    //
+    // SEV-SNP guest requires that GHCB GPA must be registered before using it.
+    //
+    SevSnpGhcbRegister (FixedPcdGet32 (PcdOvmfSecGhcbBase));
+  }
+
   //
   // SEV-ES protocol checking succeeded, set the initial GHCB address
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 13/28] OvmfPkg/PlatformPei: register GHCB gpa for the SEV-SNP guest
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (11 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 12/28] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 14/28] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The SEV-SNP guest requires that GHCB GPA must be registered before using.
See the GHCB specification section 2.3.2 for more details.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 91 ++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index a8bf610022ba..de876fdb478e 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -19,9 +19,93 @@
 #include <PiPei.h>
 #include <Register/Amd/Msr.h>
 #include <Register/Intel/SmramSaveStateMap.h>
+#include <Library/VmgExitLib.h>
 
 #include "Platform.h"
 
+/**
+  Handle an SEV-SNP/GHCB protocol check failure.
+
+  Notify the hypervisor using the VMGEXIT instruction that the SEV-SNP guest
+  wishes to be terminated.
+
+  @param[in] ReasonCode  Reason code to provide to the hypervisor for the
+                         termination request.
+
+**/
+STATIC
+VOID
+SevEsProtocolFailure (
+  IN UINT8  ReasonCode
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+
+  //
+  // Use the GHCB MSR Protocol to request termination by the hypervisor
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
+  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
+  Msr.GhcbTerminate.ReasonCode = ReasonCode;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+/**
+
+  This function can be used to register the GHCB GPA.
+
+  @param[in]  Address           The physical address to be registered.
+
+**/
+STATIC
+VOID
+GhcbRegister (
+  IN  EFI_PHYSICAL_ADDRESS   Address
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  MSR_SEV_ES_GHCB_REGISTER  CurrentMsr;
+  EFI_PHYSICAL_ADDRESS      GuestFrameNumber;
+
+  GuestFrameNumber = Address >> EFI_PAGE_SHIFT;
+
+  //
+  // Save the current MSR Value
+  //
+  CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // Use the GHCB MSR Protocol to request to register the GPA.
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
+  Msr.GhcbGpaRegister.GuestFrameNumber = GuestFrameNumber;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+
+  //
+  // If hypervisor responded with a different GPA than requested then fail.
+  //
+  if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
+      (Msr.GhcbGpaRegister.GuestFrameNumber != GuestFrameNumber)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  //
+  // Restore the MSR
+  //
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
+}
+
 /**
 
   Initialize SEV-ES support if running as an SEV-ES guest.
@@ -109,6 +193,13 @@ AmdSevEsInitialize (
     "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
     (UINT64)GhcbBackupPageCount, GhcbBackupBase));
 
+  //
+  // SEV-SNP guest requires that GHCB GPA must be registered before using it.
+  //
+  if (MemEncryptSevSnpIsEnabled ()) {
+    GhcbRegister (GhcbBasePa);
+  }
+
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
 
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 14/28] OvmfPkg/AmdSevDxe: do not use extended PCI config space
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (12 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 13/28] OvmfPkg/PlatformPei: " Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 15/28] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Commit 85b8eac59b8c5bd9c7eb9afdb64357ce1aa2e803 added support to ensure
that MMIO is only performed against the un-encrypted memory. If MMIO
is performed against encrypted memory, a #GP is raised.

The AmdSevDxe uses the functions provided by the MemEncryptSevLib to
clear the memory encryption mask from the page table. If the
MemEncryptSevLib is extended to include VmgExitLib then depedency
chain will look like this:

OvmfPkg/AmdSevDxe/AmdSevDxe.inf
-----> MemEncryptSevLib                    class
-----> "OvmfPkg/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf"   instance
-----> VmgExitLib                          class
-----> "OvmfPkg/VmgExitLib"    instance
-----> LocalApicLib                        class
-----> "UefiCpuPkg/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf" instance
-----> TimerLib                            class
-----> "OvmfPkg/AcpiTimerLib/DxeAcpiTimerLib.inf"   instance
-----> PciLib                                           class
-----> "OvmfPkg/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf"    instance
-----> PciExpressLib                                          class
-----> "MdePkg/BasePciExpressLib/BasePciExpressLib.inf"  instance

The LocalApicLib provides a constructor that gets called before the
AmdSevDxe can clear the memory encryption mask from the MMIO regions.

When running under the Q35 machine type, the call chain looks like this:

AcpiTimerLibConstructor ()  [AcpiTimerLib]
  PciRead32 ()              [DxePciLibI440FxQ35]
   PciExpressRead32 ()      [PciExpressLib]

The PciExpressRead32 () reads the MMIO region. The MMIO regions are not
yet mapped un-encrypted, so the check introduced in the commit
85b8eac59b8c5bd9c7eb9afdb64357ce1aa2e803 raises a #GP.

The AmdSevDxe driver does not require the access to the extended PCI
config space. Accessing a normal PCI config space, via IO port should be
sufficent. Use the module-scope override to make the AmdSevDxe use the
BasePciLib instead of BasePciExpressLib so that PciRead32 () uses the
IO ports instead of the extended config space.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc | 5 ++++-
 OvmfPkg/Bhyve/BhyveX64.dsc   | 5 ++++-
 OvmfPkg/OvmfPkgIa32X64.dsc   | 5 ++++-
 OvmfPkg/OvmfPkgX64.dsc       | 5 ++++-
 OvmfPkg/OvmfXen.dsc          | 5 ++++-
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 1d487befae08..f1cf2e916a10 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -807,7 +807,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
   #
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index cbf896e89bd2..75d4b196057f 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -779,7 +779,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index b3662e17f256..783622c61ac5 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -960,7 +960,10 @@ [Components.X64]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 0a237a905866..f2b13f7228a1 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -958,7 +958,10 @@ [Components]
 !endif
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
 !if $(SMM_REQUIRE) == TRUE
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 3c1ca6bfd493..d9619ac5a050 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -725,7 +725,10 @@ [Components]
   }
 
   OvmfPkg/PlatformDxe/Platform.inf
-  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+  OvmfPkg/AmdSevDxe/AmdSevDxe.inf {
+    <LibraryClasses>
+    PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
   #
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 15/28] OvmfPkg/MemEncryptSevLib: add support to validate system RAM
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (13 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 14/28] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 16/28] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated " Brijesh Singh
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Many of the integrity guarantees of SEV-SNP are enforced through the
Reverse Map Table (RMP). Each RMP entry contains the GPA at which a
particular page of DRAM should be mapped. The guest can request the
hypervisor to add pages in the RMP table via the Page State Change VMGEXIT
defined in the GHCB specification section 2.5.1 and 4.1.6. Inside each RMP
entry is a Validated flag; this flag is automatically cleared to 0 by the
CPU hardware when a new RMP entry is created for a guest. Each VM page
can be either validated or invalidated, as indicated by the Validated
flag in the RMP entry. Memory access to a private page that is not
validated generates a #VC. A VM can use the PVALIDATE instruction to
validate the private page before using it.

During the guest creation, the boot ROM memory is pre-validated by the
AMD-SEV firmware. The MemEncryptSevSnpValidateSystemRam() can be called
during the SEC and PEI phase to validate the detected system RAM.

One of the fields in the Page State Change NAE is the RMP page size. The
page size input parameter indicates that either a 4KB or 2MB page should
be used while adding the RMP entry. During the validation, when possible,
the MemEncryptSevSnpValidateSystemRam() will use the 2MB entry. A
hypervisor backing the memory may choose to use the different page size
in the RMP entry. In those cases, the PVALIDATE instruction should return
SIZEMISMATCH. If a SIZEMISMATCH is detected, then validate all 512-pages
constituting a 2MB region.

Upon completion, the PVALIDATE instruction sets the rFLAGS.CF to 0 if
instruction changed the RMP entry and to 1 if the instruction did not
change the RMP entry. The rFlags.CF will be 1 only when a memory region
is already validated. We should not double validate a memory
as it could lead to a security compromise. If double validation is
detected, terminate the boot.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 .../DxeMemEncryptSevLib.inf                   |   3 +
 .../PeiMemEncryptSevLib.inf                   |   3 +
 .../SecMemEncryptSevLib.inf                   |   3 +
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |  14 +
 .../X64/SnpPageStateChange.h                  |  31 ++
 .../Ia32/MemEncryptSevLib.c                   |  17 +
 .../X64/DxeSnpSystemRamValidate.c             |  40 +++
 .../X64/PeiSnpSystemRamValidate.c             |  36 +++
 .../X64/SecSnpSystemRamValidate.c             |  36 +++
 .../X64/SnpPageStateChangeInternal.c          | 295 ++++++++++++++++++
 12 files changed, 480 insertions(+)
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index f53efeae7986..bdb35c20e17e 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -264,6 +264,7 @@ [LibraryClasses.common.SEC]
 !else
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
 !endif
+  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
 
 [LibraryClasses.common.PEI_CORE]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 783622c61ac5..882a96d8710a 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -268,6 +268,7 @@ [LibraryClasses.common.SEC]
 !else
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
 !endif
+  MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
 
 [LibraryClasses.common.PEI_CORE]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
index f2e162d68076..f613bb314f5f 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
@@ -34,8 +34,10 @@ [Sources]
   PeiDxeMemEncryptSevLibInternal.c
 
 [Sources.X64]
+  X64/DxeSnpSystemRamValidate.c
   X64/MemEncryptSevLib.c
   X64/PeiDxeVirtualMemory.c
+  X64/SnpPageStateChangeInternal.c
   X64/VirtualMemory.c
   X64/VirtualMemory.h
 
@@ -49,6 +51,7 @@ [LibraryClasses]
   DebugLib
   MemoryAllocationLib
   PcdLib
+  VmgExitLib
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 03a78c32df28..0402e49a1028 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -36,6 +36,8 @@ [Sources]
 [Sources.X64]
   X64/MemEncryptSevLib.c
   X64/PeiDxeVirtualMemory.c
+  X64/PeiSnpSystemRamValidate.c
+  X64/SnpPageStateChangeInternal.c
   X64/VirtualMemory.c
   X64/VirtualMemory.h
 
@@ -49,6 +51,7 @@ [LibraryClasses]
   DebugLib
   MemoryAllocationLib
   PcdLib
+  VmgExitLib
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
index 279c38bfbc2c..939af0a91ea4 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
@@ -35,6 +35,8 @@ [Sources]
 [Sources.X64]
   X64/MemEncryptSevLib.c
   X64/SecVirtualMemory.c
+  X64/SecSnpSystemRamValidate.c
+  X64/SnpPageStateChangeInternal.c
   X64/VirtualMemory.c
   X64/VirtualMemory.h
 
@@ -46,6 +48,7 @@ [LibraryClasses]
   CpuLib
   DebugLib
   PcdLib
+  VmgExitLib
 
 [FixedPcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index 2425d8ba0a36..dbfa526dd67a 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -234,4 +234,18 @@ MemEncryptSevClearMmioPageEncMask (
   IN UINTN                    NumPages
   );
 
+/**
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+  @param[in]  BaseAddress             Base address
+  @param[in]  NumPages                Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+  IN PHYSICAL_ADDRESS           BaseAddress,
+  IN UINTN                      NumPages
+  );
+
 #endif // _MEM_ENCRYPT_SEV_LIB_H_
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
new file mode 100644
index 000000000000..8bbdf06468b9
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h
@@ -0,0 +1,31 @@
+/** @file
+
+  SEV-SNP Page Validation functions.
+
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SNP_PAGE_STATE_INTERNAL_H_
+#define SNP_PAGE_STATE_INTERNAL_H_
+
+//
+// SEV-SNP Page states
+//
+typedef enum {
+  SevSnpPagePrivate,
+  SevSnpPageShared,
+
+} SEV_SNP_PAGE_STATE;
+
+VOID
+InternalSetPageState (
+  IN EFI_PHYSICAL_ADDRESS             BaseAddress,
+  IN UINTN                            NumPages,
+  IN SEV_SNP_PAGE_STATE               State,
+  IN BOOLEAN                          UseLargeEntry
+  );
+
+#endif
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
index be260e0d1014..df5e4d61513d 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
@@ -136,3 +136,20 @@ MemEncryptSevClearMmioPageEncMask (
   //
   return RETURN_UNSUPPORTED;
 }
+
+/**
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+  @param[in]  BaseAddress             Base address
+  @param[in]  NumPages                Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+  IN PHYSICAL_ADDRESS           BaseAddress,
+  IN UINTN                      NumPages
+  )
+{
+  ASSERT (FALSE);
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
new file mode 100644
index 000000000000..ad8d8b388dc8
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c
@@ -0,0 +1,40 @@
+/** @file
+
+  SEV-SNP Page Validation functions.
+
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemEncryptSevLib.h>
+
+#include "SnpPageStateChange.h"
+
+/**
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+  @param[in]  BaseAddress             Base address
+  @param[in]  NumPages                Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+  IN PHYSICAL_ADDRESS                   BaseAddress,
+  IN UINTN                              NumPages
+  )
+{
+  if (!MemEncryptSevSnpIsEnabled ()) {
+    return;
+  }
+
+  //
+  // All the pre-validation must be completed in the PEI phase.
+  //
+  ASSERT (FALSE);
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
new file mode 100644
index 000000000000..64aab7f45b6d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -0,0 +1,36 @@
+/** @file
+
+  SEV-SNP Page Validation functions.
+
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/MemEncryptSevLib.h>
+
+#include "SnpPageStateChange.h"
+
+/**
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+  @param[in]  BaseAddress             Base address
+  @param[in]  NumPages                Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+  IN PHYSICAL_ADDRESS                   BaseAddress,
+  IN UINTN                              NumPages
+  )
+{
+  if (!MemEncryptSevSnpIsEnabled ()) {
+    return;
+  }
+
+  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
new file mode 100644
index 000000000000..64aab7f45b6d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c
@@ -0,0 +1,36 @@
+/** @file
+
+  SEV-SNP Page Validation functions.
+
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/MemEncryptSevLib.h>
+
+#include "SnpPageStateChange.h"
+
+/**
+  Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+  @param[in]  BaseAddress             Base address
+  @param[in]  NumPages                Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+  IN PHYSICAL_ADDRESS                   BaseAddress,
+  IN UINTN                              NumPages
+  )
+{
+  if (!MemEncryptSevSnpIsEnabled ()) {
+    return;
+  }
+
+  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
new file mode 100644
index 000000000000..506df12d4e51
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c
@@ -0,0 +1,295 @@
+/** @file
+
+  SEV-SNP Page Validation functions.
+
+  Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemEncryptSevLib.h>
+#include <Library/DebugLib.h>
+#include <Library/VmgExitLib.h>
+
+#include <Register/Amd/Ghcb.h>
+#include <Register/Amd/Msr.h>
+
+#include "SnpPageStateChange.h"
+
+#define IS_ALIGNED(x, y)        ((((x) & (y - 1)) == 0))
+#define PAGES_PER_LARGE_ENTRY   512
+
+STATIC
+UINTN
+MemoryStateToGhcbOp (
+  IN SEV_SNP_PAGE_STATE   State
+  )
+{
+  UINTN Cmd;
+
+  switch (State) {
+    case SevSnpPageShared: Cmd = SNP_PAGE_STATE_SHARED; break;
+    case SevSnpPagePrivate: Cmd = SNP_PAGE_STATE_PRIVATE; break;
+    default: ASSERT(0);
+  }
+
+  return Cmd;
+}
+
+STATIC
+VOID
+SnpPageStateFailureTerminate (
+  VOID
+  )
+{
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+
+  //
+  // Use the GHCB MSR Protocol to request termination by the hypervisor
+  //
+  Msr.GhcbPhysicalAddress = 0;
+  Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
+  Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
+  Msr.GhcbTerminate.ReasonCode = GHCB_TERMINATE_GHCB_GENERAL;
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+  AsmVmgExit ();
+
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+/**
+ This function issues the PVALIDATE instruction to validate or invalidate the memory
+ range specified. If PVALIDATE returns size mismatch then it retry validating with
+ smaller page size.
+
+ */
+STATIC
+VOID
+PvalidateRange (
+  IN  SNP_PAGE_STATE_CHANGE_INFO    *Info,
+  IN  UINTN                         StartIndex,
+  IN  UINTN                         EndIndex,
+  IN  BOOLEAN                       Validate
+  )
+{
+  UINTN         Address, RmpPageSize, Ret, i;
+
+  for (; StartIndex <= EndIndex; StartIndex++) {
+    //
+    // Get the address and the page size from the Info.
+    //
+    Address = Info->Entry[StartIndex].GuestFrameNumber << EFI_PAGE_SHIFT;
+    RmpPageSize = Info->Entry[StartIndex].PageSize;
+
+    Ret = AsmPvalidate (RmpPageSize, Validate, Address);
+
+    //
+    // If we fail to validate due to size mismatch then try with the
+    // smaller page size. This senario will occur if the backing page in
+    // the RMP entry is 4K and we are validating it as a 2MB.
+    //
+    if ((Ret == PVALIDATE_RET_SIZE_MISMATCH) && (RmpPageSize == PvalidatePageSize2MB)) {
+      for (i = 0; i < PAGES_PER_LARGE_ENTRY; i++) {
+        Ret = AsmPvalidate (PvalidatePageSize4K, Validate, Address);
+        if (Ret) {
+          break;
+        }
+
+        Address = Address + EFI_PAGE_SIZE;
+      }
+    }
+
+    //
+    // If validation failed then do not continue.
+    //
+    if (Ret) {
+      DEBUG ((
+        DEBUG_ERROR, "%a:%a: Failed to %a address 0x%Lx Error code %d\n",
+        gEfiCallerBaseName,
+        __FUNCTION__,
+        Validate ? "Validate" : "Invalidate",
+        Address,
+        Ret
+        ));
+      SnpPageStateFailureTerminate ();
+    }
+  }
+}
+
+STATIC
+EFI_PHYSICAL_ADDRESS
+BuildPageStateBuffer (
+  IN EFI_PHYSICAL_ADDRESS           BaseAddress,
+  IN EFI_PHYSICAL_ADDRESS           EndAddress,
+  IN SEV_SNP_PAGE_STATE             State,
+  IN BOOLEAN                        UseLargeEntry,
+  IN SNP_PAGE_STATE_CHANGE_INFO     *Info
+  )
+{
+  EFI_PHYSICAL_ADDRESS      NextAddress;
+  UINTN                     i, RmpPageSize;
+
+  // Clear the page state structure
+  SetMem (Info, sizeof (*Info), 0);
+
+  i = 0;
+  NextAddress = EndAddress;
+
+  //
+  // Populate the page state entry structure
+  //
+  while ((BaseAddress < EndAddress) && (i < SNP_PAGE_STATE_MAX_ENTRY)) {
+    //
+    // Is this a 2MB aligned page? Check if we can use the Large RMP entry.
+    //
+    if (UseLargeEntry && IS_ALIGNED (BaseAddress, SIZE_2MB) &&
+      ((EndAddress - BaseAddress) >= SIZE_2MB)) {
+      RmpPageSize = PvalidatePageSize2MB;
+      NextAddress = BaseAddress + SIZE_2MB;
+    } else {
+      RmpPageSize = PvalidatePageSize4K;
+      NextAddress = BaseAddress + EFI_PAGE_SIZE;
+    }
+
+    Info->Entry[i].GuestFrameNumber = BaseAddress >> EFI_PAGE_SHIFT;
+    Info->Entry[i].PageSize = RmpPageSize;
+    Info->Entry[i].Operation = MemoryStateToGhcbOp (State);
+    Info->Entry[i].CurrentPage = 0;
+    Info->Header.EndEntry = i;
+
+    BaseAddress = NextAddress;
+    i++;
+  }
+
+  return NextAddress;
+}
+
+STATIC
+VOID
+PageStateChangeVmgExit (
+  IN GHCB                           *Ghcb,
+  IN SNP_PAGE_STATE_CHANGE_INFO     *Info
+  )
+{
+  EFI_STATUS                      Status;
+
+  //
+  // As per the GHCB specification, the hypervisor can resume the guest before
+  // processing all the entries. Checks whether all the entries are processed.
+  //
+  // The stragtegy here is to wait for the hypervisor to change the page
+  // state in the RMP table before guest access the memory pages. If the
+  // page state was not successful, then later memory access will result
+  // in the crash.
+  //
+  while (Info->Header.CurrentEntry <= Info->Header.EndEntry) {
+    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
+
+    Status = VmgExit (Ghcb, SVM_EXIT_SNP_PAGE_STATE_CHANGE, 0, 0);
+
+    //
+    // The Page State Change VMGEXIT can pass the failure through the
+    // ExitInfo2. Lets check both the return value as well as ExitInfo2.
+    //
+    if ((Status != 0) || (Ghcb->SaveArea.SwExitInfo2)) {
+      SnpPageStateFailureTerminate ();
+    }
+  }
+}
+
+/**
+ The function is used to set the page state when SEV-SNP is active. The page state
+ transition consist of changing the page ownership in the RMP table, and using the
+ PVALIDATE instruction to update the Validated bit in RMP table.
+
+ When the UseLargeEntry is set to TRUE, then function will try to use the large RMP
+ entry (whevever possible).
+ */
+VOID
+InternalSetPageState (
+  IN EFI_PHYSICAL_ADDRESS             BaseAddress,
+  IN UINTN                            NumPages,
+  IN SEV_SNP_PAGE_STATE               State,
+  IN BOOLEAN                          UseLargeEntry
+  )
+{
+  GHCB                            *Ghcb;
+  EFI_PHYSICAL_ADDRESS            NextAddress, EndAddress;
+  MSR_SEV_ES_GHCB_REGISTER        Msr;
+  BOOLEAN                         InterruptState;
+  SNP_PAGE_STATE_CHANGE_INFO      *Info;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
+
+  DEBUG ((
+    DEBUG_VERBOSE, "%a:%a Address 0x%Lx - 0x%Lx State = %a LargeEntry = %d\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    BaseAddress,
+    EndAddress,
+    State == SevSnpPageShared ? "Shared" : "Private",
+    UseLargeEntry
+    ));
+
+  while (BaseAddress < EndAddress) {
+    UINTN       CurrentEntry, EndEntry;
+
+    //
+    // Initialize the GHCB
+    //
+    VmgInit (Ghcb, &InterruptState);
+
+    //
+    // Build the page state structure
+    //
+    Info = (SNP_PAGE_STATE_CHANGE_INFO *) Ghcb->SharedBuffer;
+    NextAddress = BuildPageStateBuffer (BaseAddress,
+                                        EndAddress,
+                                        State,
+                                        UseLargeEntry,
+                                        Info
+                                       );
+
+    //
+    // Save the current and end entry from the page state structure. We need
+    // it later.
+    //
+    CurrentEntry = Info->Header.CurrentEntry;
+    EndEntry = Info->Header.EndEntry;
+
+    //
+    // If the caller requested to change the page state to shared then
+    // invalidate the pages before making the page shared in the RMP table.
+    //
+    if (State == SevSnpPageShared) {
+      PvalidateRange (Info, CurrentEntry, EndEntry, FALSE);
+    }
+
+    //
+    // Invoke the page state change VMGEXIT.
+    //
+    PageStateChangeVmgExit (Ghcb, Info);
+
+    //
+    // If the caller requested to change the page state to private then
+    // validate the pages after it has been added in the RMP table.
+    //
+    if (State == SevSnpPagePrivate) {
+      PvalidateRange (Info, CurrentEntry, EndEntry, TRUE);
+    }
+
+    VmgDone (Ghcb, InterruptState);
+
+    BaseAddress = NextAddress;
+  }
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 16/28] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated system RAM
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (14 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 15/28] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 17/28] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The MemEncryptSevSnpPreValidateSystemRam() is used for pre-validating the
system RAM. As the boot progress, each phase validates a fixed region of
the RAM. In the PEI phase, the PlatformPei detects all the available RAM
and calls to pre-validate the detected system RAM.

While validating the system RAM in PEI phase, we must skip previously
validated system RAM to avoid the double validation.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../PeiMemEncryptSevLib.inf                   |  2 +
 .../X64/PeiSnpSystemRamValidate.c             | 65 ++++++++++++++++++-
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 0402e49a1028..f4058911e7b6 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -58,3 +58,5 @@ [FeaturePcd]
 
 [FixedPcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 64aab7f45b6d..3e692a3b869d 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -14,6 +14,44 @@
 
 #include "SnpPageStateChange.h"
 
+typedef struct {
+  UINT64    StartAddress;
+  UINT64    EndAddress;
+} SNP_PRE_VALIDATED_RANGE;
+
+STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
+  // This range is pre-validated by the Hypervisor.
+  {
+    FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedStart),
+    FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedEnd)
+  }
+};
+
+STATIC
+BOOLEAN
+DetectPreValidatedOverLap (
+  IN    PHYSICAL_ADDRESS            StartAddress,
+  IN    PHYSICAL_ADDRESS            EndAddress,
+  OUT   SNP_PRE_VALIDATED_RANGE     *OverlapRange
+  )
+{
+  UINTN               i;
+
+  //
+  // Check if the specified address range exist in pre-validated array.
+  //
+  for (i = 0; i < ARRAY_SIZE (mPreValidatedRange); i++) {
+    if ((mPreValidatedRange[i].StartAddress < EndAddress) &&
+        (StartAddress < mPreValidatedRange[i].EndAddress)) {
+      OverlapRange->StartAddress = mPreValidatedRange[i].StartAddress;
+      OverlapRange->EndAddress = mPreValidatedRange[i].EndAddress;
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
 /**
   Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
 
@@ -28,9 +66,34 @@ MemEncryptSevSnpPreValidateSystemRam (
   IN UINTN                              NumPages
   )
 {
+  PHYSICAL_ADDRESS          EndAddress;
+  SNP_PRE_VALIDATED_RANGE   OverlapRange;
+
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
   }
 
-  InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+  EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
+
+  while (BaseAddress < EndAddress) {
+    //
+    // Check if the range overlaps with the pre-validated ranges.
+    //
+    if (DetectPreValidatedOverLap (BaseAddress, EndAddress, &OverlapRange)) {
+      // Validate the non-overlap regions.
+      if (BaseAddress < OverlapRange.StartAddress) {
+        NumPages = EFI_SIZE_TO_PAGES (OverlapRange.StartAddress - BaseAddress);
+
+        InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+      }
+
+      BaseAddress = OverlapRange.EndAddress;
+      continue;
+    }
+
+    // Validate the remaining pages.
+    NumPages = EFI_SIZE_TO_PAGES (EndAddress - BaseAddress);
+    InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
+    BaseAddress = EndAddress;
+  }
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 17/28] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (15 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 16/28] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated " Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 18/28] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The initial page built during the SEC phase is used by the
MemEncryptSevSnpValidateSystemRam() for the system RAM validation. The
page validation process requires using the PVALIDATE instruction;  the
instruction accepts a virtual address of the memory region that needs
to be validated. If hardware encounters a page table walk failure (due
to page-not-present) then it raises #GP.

The initial page table built in SEC phase address up to 4GB. Add an
internal function to extend the page table to cover > 4GB. The function
builds 1GB entries in the page table for access > 4GB. This will provide
the support to call PVALIDATE instruction for the virtual address >
4GB in PEI phase.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../BaseMemEncryptSevLib/X64/VirtualMemory.h  |  19 +++
 .../X64/PeiDxeVirtualMemory.c                 | 115 ++++++++++++++++++
 .../X64/PeiSnpSystemRamValidate.c             |  22 ++++
 3 files changed, 156 insertions(+)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
index 21bbbd1c4f9c..aefef68c30c0 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
@@ -143,4 +143,23 @@ InternalMemEncryptSevClearMmioPageEncMask (
   IN  PHYSICAL_ADDRESS        PhysicalAddress,
   IN  UINTN                   Length
   );
+
+/**
+  Create 1GB identity mapping for the specified virtual address range.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  VirtualAddress          Virtual address
+  @param[in]  Length                  Length of virtual address range
+
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalMemEncryptSevCreateIdentityMap1G (
+  IN    PHYSICAL_ADDRESS      Cr3BaseAddress,
+  IN    PHYSICAL_ADDRESS      PhysicalAddress,
+  IN    UINTN                 Length
+  );
 #endif
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index c696745f9d26..f146f6d61cc5 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -536,6 +536,121 @@ EnableReadOnlyPageWriteProtect (
   AsmWriteCr0 (AsmReadCr0() | BIT16);
 }
 
+RETURN_STATUS
+EFIAPI
+InternalMemEncryptSevCreateIdentityMap1G (
+  IN    PHYSICAL_ADDRESS      Cr3BaseAddress,
+  IN    PHYSICAL_ADDRESS      PhysicalAddress,
+  IN    UINTN                 Length
+  )
+{
+  PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+  PAGE_TABLE_1G_ENTRY            *PageDirectory1GEntry;
+  UINT64                         PgTableMask;
+  UINT64                         AddressEncMask;
+  BOOLEAN                        IsWpEnabled;
+  RETURN_STATUS                  Status;
+
+  //
+  // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
+  //
+  PageMapLevel4Entry = NULL;
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    Cr3BaseAddress,
+    PhysicalAddress,
+    (UINT64)Length
+    ));
+
+  if (Length == 0) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if we have a valid memory encryption mask
+  //
+  AddressEncMask = InternalGetMemEncryptionAddressMask ();
+  if (!AddressEncMask) {
+    return RETURN_ACCESS_DENIED;
+  }
+
+  PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+
+  //
+  // Make sure that the page table is changeable.
+  //
+  IsWpEnabled = IsReadOnlyPageWriteProtected ();
+  if (IsWpEnabled) {
+    DisableReadOnlyPageWriteProtect ();
+  }
+
+  Status = EFI_SUCCESS;
+
+  while (Length)
+  {
+    //
+    // If Cr3BaseAddress is not specified then read the current CR3
+    //
+    if (Cr3BaseAddress == 0) {
+      Cr3BaseAddress = AsmReadCr3();
+    }
+
+    PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
+    PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress);
+    if (!PageMapLevel4Entry->Bits.Present) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a:%a: bad PML4 for Physical=0x%Lx\n",
+        gEfiCallerBaseName,
+        __FUNCTION__,
+        PhysicalAddress
+        ));
+      Status = RETURN_NO_MAPPING;
+      goto Done;
+    }
+
+    PageDirectory1GEntry = (VOID *)(
+                             (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+                              12) & ~PgTableMask
+                             );
+    PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress);
+    if (!PageDirectory1GEntry->Bits.Present) {
+      PageDirectory1GEntry->Bits.Present = 1;
+      PageDirectory1GEntry->Bits.MustBe1 = 1;
+      PageDirectory1GEntry->Bits.MustBeZero = 0;
+      PageDirectory1GEntry->Bits.ReadWrite = 1;
+      PageDirectory1GEntry->Uint64 |= (UINT64)PhysicalAddress | AddressEncMask;
+    }
+
+    if (Length <= BIT30) {
+      Length = 0;
+    } else {
+      Length -= BIT30;
+    }
+
+    PhysicalAddress += BIT30;
+  }
+
+  //
+  // Flush TLB
+  //
+  CpuFlushTlb();
+
+Done:
+  //
+  // Restore page table write protection, if any.
+  //
+  if (IsWpEnabled) {
+    EnableReadOnlyPageWriteProtect ();
+  }
+
+  return Status;
+}
 
 /**
   This function either sets or clears memory encryption bit for the memory
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 3e692a3b869d..69ffb79633c4 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -10,9 +10,12 @@
 
 #include <Uefi/UefiBaseType.h>
 #include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
 #include <Library/MemEncryptSevLib.h>
 
 #include "SnpPageStateChange.h"
+#include "VirtualMemory.h"
 
 typedef struct {
   UINT64    StartAddress;
@@ -68,6 +71,7 @@ MemEncryptSevSnpPreValidateSystemRam (
 {
   PHYSICAL_ADDRESS          EndAddress;
   SNP_PRE_VALIDATED_RANGE   OverlapRange;
+  EFI_STATUS                Status;
 
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
@@ -75,6 +79,24 @@ MemEncryptSevSnpPreValidateSystemRam (
 
   EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
 
+  //
+  // The page table used in PEI can address up to 4GB memory. If we are asked to
+  // validate a range above the 4GB, then create an identity mapping so that the
+  // PVALIDATE instruction can execute correctly. If the page table entry is not
+  // present then PVALIDATE will #GP.
+  //
+  if (BaseAddress >= SIZE_4GB) {
+    Status = InternalMemEncryptSevCreateIdentityMap1G (
+                0,
+                BaseAddress,
+                EFI_PAGES_TO_SIZE (NumPages)
+                );
+    if (EFI_ERROR (Status)) {
+      ASSERT (FALSE);
+      CpuDeadLoop ();
+    }
+  }
+
   while (BaseAddress < EndAddress) {
     //
     // Check if the range overlaps with the pre-validated ranges.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 18/28] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (16 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 17/28] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 19/28] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The VMM launch sequence should have pre-validated all the data pages used
in the Reset vector. The range does not cover the data pages used during
the SEC phase (mainly PEI and DXE firmware volume decompression memory).

When SEV-SNP is active, the memory must be pre-validated before the access.
Add support to pre-validate the memory range from SnpSecPreValidatedStart
to SnpSecPreValidatedEnd. This should be sufficent to enter into the PEI
phase.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                           |  5 ++++
 .../PeiMemEncryptSevLib.inf                   |  2 ++
 OvmfPkg/Sec/SecMain.inf                       |  3 +++
 .../X64/PeiSnpSystemRamValidate.c             |  5 ++++
 OvmfPkg/Sec/SecMain.c                         | 27 +++++++++++++++++++
 OvmfPkg/FvmainCompactScratchEnd.fdf.inc       |  5 ++++
 6 files changed, 47 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index d0ec14ca2318..afc559d74335 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -339,6 +339,11 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart|0x0|UINT32|0x51
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd|0x0|UINT32|0x52
 
+  ## The range of memory that need to be pre-validated in the SEC phase
+  #  when SEV-SNP is active in the guest VM.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart|0|UINT32|0x53
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd|0|UINT32|0x54
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index f4058911e7b6..2b60920f4b25 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -58,5 +58,7 @@ [FeaturePcd]
 
 [FixedPcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedEnd
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpHypervisorPreValidatedStart
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 7f78dcee2772..8144b1d115cf 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -50,6 +50,7 @@ [LibraryClasses]
   PeCoffExtraActionLib
   ExtractGuidedSectionLib
   LocalApicLib
+  MemEncryptSevLib
   CpuExceptionHandlerLib
 
 [Ppis]
@@ -70,6 +71,8 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
index 69ffb79633c4..253d42073907 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
@@ -27,6 +27,11 @@ STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
   {
     FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedStart),
     FixedPcdGet32 (PcdOvmfSnpHypervisorPreValidatedEnd)
+  },
+  // This range is pre-validated by the Sec/SecMain.c
+  {
+    FixedPcdGet32 (PcdOvmfSnpSecPreValidatedStart),
+    FixedPcdGet32 (PcdOvmfSnpSecPreValidatedEnd)
   }
 };
 
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index c10441ddf472..f949a9b0349e 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -915,6 +915,26 @@ SevEsIsEnabled (
   return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled != 0));
 }
 
+/**
+ Pre-validate System RAM used for decompressing the PEI and DXE firmware volumes
+ when SEV-SNP is active. The PCDs SecPreValidatedStart and SecPreValidatedEnd are
+ set in OvmfPkg/FvmainCompactScratchEnd.fdf.inc.
+
+**/
+STATIC
+VOID
+SevSnpSecPreValidateSystemRam (
+  VOID
+  )
+{
+  PHYSICAL_ADDRESS        Start, End;
+
+  Start = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdOvmfSnpSecPreValidatedStart);
+  End = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdOvmfSnpSecPreValidatedEnd);
+
+  MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES (End - Start));
+}
+
 VOID
 EFIAPI
 SecCoreStartupWithStack (
@@ -1046,6 +1066,13 @@ SecCoreStartupWithStack (
   SecCoreData.BootFirmwareVolumeBase = BootFv;
   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
 
+  if (SevSnpIsEnabled ()) {
+    //
+    // Pre-validate the System RAM used in the SEC Phase
+    //
+    SevSnpSecPreValidateSystemRam ();
+  }
+
   //
   // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
   //
diff --git a/OvmfPkg/FvmainCompactScratchEnd.fdf.inc b/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
index 46f52583297c..b560fb0b8e4f 100644
--- a/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
+++ b/OvmfPkg/FvmainCompactScratchEnd.fdf.inc
@@ -63,3 +63,8 @@
 DEFINE DECOMP_SCRATCH_BASE           = (($(DECOMP_SCRATCH_BASE_UNALIGNED) + $(DECOMP_SCRATCH_BASE_ALIGNMENT)) & $(DECOMP_SCRATCH_BASE_MASK))
 
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd = $(DECOMP_SCRATCH_BASE) + $(DECOMP_SCRATCH_SIZE)
+
+#
+# The range of pages that should be pre-validated during the SEC phase when SEV-SNP is active in the guest VM.
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedStart = $(MEMFD_BASE_ADDRESS) + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecPreValidatedEnd = $(DECOMP_SCRATCH_BASE) + $(DECOMP_SCRATCH_SIZE)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 19/28] OvmfPkg/PlatformPei: validate the system RAM when SNP is active
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (17 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 18/28] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 20/28] OvmfPkg/PlatformPei: set the SEV-SNP enabled PCD Brijesh Singh
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

When SEV-SNP is active, a memory region mapped encrypted in the page
table must be validated before access. There are two approaches that
can be taken to validate the system RAM detected during the PEI phase:

1) Validate on-demand
OR
2) Validate before access

On-demand
=========
If memory is not validated before access, it will cause a #VC
exception with the page-not-validated error code. The VC exception
handler can perform the validation steps.

The pages that have been validated will need to be tracked to avoid
the double validation scenarios. The range of memory that has not
been validated will need to be communicated to the OS through the
recently introduced unaccepted memory type
https://github.com/microsoft/mu_basecore/pull/66, so that OS can
validate those ranges before using them.

Validate before access
======================
Since the PEI phase detects all the available system RAM, use the
MemEncryptSevSnpValidateSystemRam() function to pre-validate the
system RAM in the PEI phase.

For now, choose option 2 due to the dependency and the complexity
of the on-demand validation.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 42 ++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index de876fdb478e..391e7bbb7dbd 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -23,6 +23,40 @@
 
 #include "Platform.h"
 
+/**
+  Initialize SEV-SNP support if running as an SEV-SNP guest.
+
+**/
+STATIC
+VOID
+AmdSevSnpInitialize (
+  VOID
+  )
+{
+  EFI_PEI_HOB_POINTERS          Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
+
+  if (!MemEncryptSevSnpIsEnabled ()) {
+    return;
+  }
+
+  //
+  // Iterate through the system RAM and validate it.
+  //
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+    if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      ResourceHob = Hob.ResourceDescriptor;
+
+      if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+        MemEncryptSevSnpPreValidateSystemRam (
+          ResourceHob->PhysicalStart,
+          EFI_SIZE_TO_PAGES ((UINTN) ResourceHob->ResourceLength)
+          );
+      }
+    }
+  }
+}
+
 /**
   Handle an SEV-SNP/GHCB protocol check failure.
 
@@ -240,6 +274,14 @@ AmdSevInitialize (
     return;
   }
 
+  //
+  // Check and perform SEV-SNP initialization if required. This need to be
+  // done before the GHCB page is made shared in the AmdSevEsInitialize(). This
+  // is because the system RAM must be validated before it is made shared.
+  // The AmdSevSnpInitialize() validates the system RAM.
+  //
+  AmdSevSnpInitialize ();
+
   //
   // Set Memory Encryption Mask PCD
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 20/28] OvmfPkg/PlatformPei: set the SEV-SNP enabled PCD
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (18 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 19/28] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 21/28] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The MpInitLib uses the PcdSevSnpIsEnabled to determine whether the SEV-SNP
is active. If the SEV-SNP is active, then set the PCD to TRUE.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf | 1 +
 OvmfPkg/PlatformPei/AmdSev.c        | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 89d1f7636870..041b3262ff3b 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -106,6 +106,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
+  gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 391e7bbb7dbd..ec577ef3efcc 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -33,6 +33,7 @@ AmdSevSnpInitialize (
   VOID
   )
 {
+  RETURN_STATUS                 PcdStatus;
   EFI_PEI_HOB_POINTERS          Hob;
   EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
 
@@ -40,6 +41,9 @@ AmdSevSnpInitialize (
     return;
   }
 
+  PcdStatus = PcdSetBoolS (PcdSevSnpIsEnabled, TRUE);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
   //
   // Iterate through the system RAM and validate it.
   //
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 21/28] OvmfPkg/PlatformPei: set the Hypervisor Features PCD
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (19 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 20/28] OvmfPkg/PlatformPei: set the SEV-SNP enabled PCD Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 22/28] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Version 2 of the GHCB specification added the support to query the
hypervisor feature bitmap. The feature bitmap provide information
such as whether to use the AP create VmgExit or use the AP jump table
approach to create the APs. The MpInitLib will use the
PcdGhcbHypervisorFeatures to determine which method to use for creating
the AP.

Query the hypervisor feature and set the PCD accordingly.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  3 ++
 OvmfPkg/PlatformPei/AmdSev.c        | 55 +++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 041b3262ff3b..bd0ade9f33d7 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -62,6 +62,7 @@ [LibraryClasses]
   MtrrLib
   MemEncryptSevLib
   PcdLib
+  VmgExitLib
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
@@ -107,6 +108,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
   gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures
+
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index ec577ef3efcc..b488cd5aed9b 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -23,6 +23,12 @@
 
 #include "Platform.h"
 
+STATIC
+UINT64
+GetHypervisorFeature (
+  VOID
+  );
+
 /**
   Initialize SEV-SNP support if running as an SEV-SNP guest.
 
@@ -36,6 +42,7 @@ AmdSevSnpInitialize (
   RETURN_STATUS                 PcdStatus;
   EFI_PEI_HOB_POINTERS          Hob;
   EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
+  UINT64                        HvFeatures;
 
   if (!MemEncryptSevSnpIsEnabled ()) {
     return;
@@ -44,6 +51,15 @@ AmdSevSnpInitialize (
   PcdStatus = PcdSetBoolS (PcdSevSnpIsEnabled, TRUE);
   ASSERT_RETURN_ERROR (PcdStatus);
 
+  //
+  // Query the hypervisor feature using the VmgExit and set the value in the
+  // hypervisor features PCD.
+  //
+  HvFeatures = GetHypervisorFeature ();
+  PcdStatus = PcdSet64S (PcdGhcbHypervisorFeatures, HvFeatures);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+
   //
   // Iterate through the system RAM and validate it.
   //
@@ -94,6 +110,45 @@ SevEsProtocolFailure (
   CpuDeadLoop ();
 }
 
+/**
+ Get the hypervisor features bitmap
+
+**/
+STATIC
+UINT64
+GetHypervisorFeature (
+  VOID
+  )
+{
+  RETURN_STATUS                   Status;
+  GHCB                            *Ghcb;
+  MSR_SEV_ES_GHCB_REGISTER        Msr;
+  BOOLEAN                         InterruptState;
+  UINT64                          Features;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  //
+  // Initialize the GHCB
+  //
+  VmgInit (Ghcb, &InterruptState);
+
+  //
+  // Query the Hypervisor Features.
+  //
+  Status = VmgExit (Ghcb, SVM_EXIT_HYPERVISOR_FEATURES, 0, 0);
+  if ((Status != 0)) {
+    SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
+  }
+
+  Features = Ghcb->SaveArea.SwExitInfo2;
+
+  VmgDone (Ghcb, InterruptState);
+
+  return Features;
+}
+
 /**
 
   This function can be used to register the GHCB GPA.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 22/28] MdePkg/GHCB: increase the GHCB protocol max version
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (20 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 21/28] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 23/28] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Now that OvmfPkg supports version 2 of the GHCB specification, bump the
protocol version.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 MdePkg/Include/Register/Amd/Ghcb.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MdePkg/Include/Register/Amd/Ghcb.h b/MdePkg/Include/Register/Amd/Ghcb.h
index 8c5f46e4bb53..071aae0c9e09 100644
--- a/MdePkg/Include/Register/Amd/Ghcb.h
+++ b/MdePkg/Include/Register/Amd/Ghcb.h
@@ -24,7 +24,7 @@
 #define VC_EXCEPTION 29
 
 #define GHCB_VERSION_MIN     1
-#define GHCB_VERSION_MAX     1
+#define GHCB_VERSION_MAX     2
 
 #define GHCB_STANDARD_USAGE  0
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 23/28] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (21 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 22/28] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 24/28] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

An SEV-SNP guest requires that the physical address of the GHCB must
be registered with the hypervisor before using it. See the GHCB
specification section 2.3.2 for more details.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |  1 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |  1 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  2 +
 UefiCpuPkg/Library/MpInitLib/MpEqu.inc        |  1 +
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 51 +++++++++++++++++++
 6 files changed, 58 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..48d7dfa4450f 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -76,3 +76,4 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled                         ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..ab8279df596f 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -65,6 +65,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                      ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled                     ## CONSUMES
 
 [Ppis]
   gEdkiiPeiShadowMicrocodePpiGuid        ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index e88a5355c983..4abaa2243d0a 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -218,6 +218,7 @@ typedef struct {
   //
   BOOLEAN               Enable5LevelPaging;
   BOOLEAN               SevEsIsEnabled;
+  BOOLEAN               SevSnpIsEnabled;
   UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
@@ -287,6 +288,7 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        SevEsIsEnabled;
+  BOOLEAN                        SevSnpIsEnabled;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index b9a06747edbf..586cff2f6813 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1040,6 +1040,7 @@ FillExchangeInfoData (
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
   ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
+  ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
   ExchangeInfo->GhcbBase        = (UINTN) CpuMpData->GhcbBase;
 
   //
@@ -2033,6 +2034,7 @@ MpInitLibInitialize (
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+  CpuMpData->SevSnpIsEnabled = PcdGetBool (PcdSevSnpIsEnabled);
   CpuMpData->SevEsAPBuffer  = (UINTN) -1;
   CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
diff --git a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
index 2e9368a374a4..01668638f245 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -92,6 +92,7 @@ struc MP_CPU_EXCHANGE_INFO
   .ModeHighSegment:              CTYPE_UINT16 1
   .Enable5LevelPaging:           CTYPE_BOOLEAN 1
   .SevEsIsEnabled:               CTYPE_BOOLEAN 1
+  .SevSnpIsEnabled               CTYPE_BOOLEAN 1
   .GhcbBase:                     CTYPE_UINTN 1
 endstruc
 
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 50df802d1fca..19939c093d2e 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -194,9 +194,60 @@ LongModeStart:
     mov        rdx, rax
     shr        rdx, 32
     mov        rcx, 0xc0010130
+
+    ;
+    ; Register GHCB GPA when SEV-SNP is enabled
+    ;
+    lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
+    cmp        byte [edi], 1        ; SevSnpIsEnabled
+    jne        SetGhcbAddress
+
+    ; Save the rdi and rsi to used for later comparison
+    push       rdi
+    push       rsi
+    mov        edi, eax
+    mov        esi, edx
+    or         eax, 18              ; Ghcb registration request
+    wrmsr
+    rep vmmcall
+    rdmsr
+    mov        r12, rax
+    and        r12, 0fffh
+    cmp        r12, 19              ; Ghcb registration response
+    jne        GhcbGpaRegisterFailure
+
+    ; Verify that GPA is not changed
+    and        eax, 0fffff000h
+    cmp        edi, eax
+    jne        GhcbGpaRegisterFailure
+    cmp        esi, edx
+    jne        GhcbGpaRegisterFailure
+    pop        rsi
+    pop        rdi
+
+    ;
+    ; Program GHCB
+    ;
+SetGhcbAddress:
     wrmsr
     jmp        CProcedureInvoke
 
+    ;
+    ; Request the guest termination
+    ;
+GhcbGpaRegisterFailure:
+    xor        edx, edx
+    mov        eax, 256             ; GHCB terminate
+    wrmsr
+    rep vmmcall
+
+    ; We should not return from the above terminate request, but if we do
+    ; then enter into the hlt loop.
+DoHltLoop:
+    cli
+    hlt
+    jmp        DoHltLoop
+
 GetApicId:
     lea        edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
     cmp        byte [edi], 1        ; SevEsIsEnabled
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 24/28] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (22 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 23/28] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 25/28] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

The MemEncryptSev{Set,Clear}PageEncMask() functions are used to set or
clear the memory encryption attribute in the page table. When SEV-SNP
is active, we also need to change the page state in the RMP table so that
it is in sync with the memory encryption attribute change.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../X64/PeiDxeVirtualMemory.c                 | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index f146f6d61cc5..56db1e4b6ecf 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -17,6 +17,7 @@
 #include <Register/Cpuid.h>
 
 #include "VirtualMemory.h"
+#include "SnpPageStateChange.h"
 
 STATIC BOOLEAN mAddressEncMaskChecked = FALSE;
 STATIC UINT64  mAddressEncMask;
@@ -695,10 +696,12 @@ SetMemoryEncDec (
   PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
   PAGE_TABLE_1G_ENTRY            *PageDirectory1GEntry;
   PAGE_TABLE_ENTRY               *PageDirectory2MEntry;
+  PHYSICAL_ADDRESS               OrigPhysicalAddress;
   PAGE_TABLE_4K_ENTRY            *PageTableEntry;
   UINT64                         PgTableMask;
   UINT64                         AddressEncMask;
   BOOLEAN                        IsWpEnabled;
+  UINTN                          OrigLength;
   RETURN_STATUS                  Status;
 
   //
@@ -751,6 +754,22 @@ SetMemoryEncDec (
 
   Status = EFI_SUCCESS;
 
+  //
+  // To maintain the security gurantees we must set the page to shared in the RMP
+  // table before clearing the memory encryption mask from the current page table.
+  //
+  // The InternalSetPageState() is used for setting the page state in the RMP table.
+  //
+  if ((Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
+    InternalSetPageState (PhysicalAddress, EFI_SIZE_TO_PAGES (Length), SevSnpPageShared, FALSE);
+  }
+
+  //
+  // Save the specified length and physical address (we need it later).
+  //
+  OrigLength = Length;
+  OrigPhysicalAddress = PhysicalAddress;
+
   while (Length != 0)
   {
     //
@@ -923,6 +942,21 @@ SetMemoryEncDec (
   //
   CpuFlushTlb();
 
+  //
+  // SEV-SNP requires that all the private pages (i.e pages mapped encrypted) must be
+  // added in the RMP table before the access.
+  //
+  // The InternalSetPageState() is used for setting the page state in the RMP table.
+  //
+  if ((Mode == SetCBit) && MemEncryptSevSnpIsEnabled ()) {
+    InternalSetPageState (
+      OrigPhysicalAddress,
+      EFI_SIZE_TO_PAGES (OrigLength),
+      SevSnpPagePrivate,
+      FALSE
+      );
+  }
+
 Done:
   //
   // Restore page table write protection, if any.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 25/28] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (23 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 24/28] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 26/28] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

The SetMemoryEncDec() is used by the higher level routines to set or clear
the page encryption mask for system RAM and Mmio address. When SEV-SNP is
active, in addition to set/clear page mask it also updates the RMP table.
The RMP table updates are required for the system RAM address and not
the Mmio address.

Add a new parameter in SetMemoryEncDec() to tell whether the specified
address is Mmio. If its Mmio then skip the page state change in the RMP
table.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../X64/PeiDxeVirtualMemory.c                 | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index 56db1e4b6ecf..0bb86d768017 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -673,6 +673,7 @@ InternalMemEncryptSevCreateIdentityMap1G (
   @param[in]  Mode                    Set or Clear mode
   @param[in]  CacheFlush              Flush the caches before applying the
                                       encryption mask
+  @param[in]  Mmio                    The physical address specified is Mmio
 
   @retval RETURN_SUCCESS              The attributes were cleared for the
                                       memory region.
@@ -688,7 +689,8 @@ SetMemoryEncDec (
   IN    PHYSICAL_ADDRESS         PhysicalAddress,
   IN    UINTN                    Length,
   IN    MAP_RANGE_MODE           Mode,
-  IN    BOOLEAN                  CacheFlush
+  IN    BOOLEAN                  CacheFlush,
+  IN    BOOLEAN                  Mmio
   )
 {
   PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
@@ -711,14 +713,15 @@ SetMemoryEncDec (
 
   DEBUG ((
     DEBUG_VERBOSE,
-    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u\n",
+    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a CacheFlush=%u Mmio=%u\n",
     gEfiCallerBaseName,
     __FUNCTION__,
     Cr3BaseAddress,
     PhysicalAddress,
     (UINT64)Length,
     (Mode == SetCBit) ? "Encrypt" : "Decrypt",
-    (UINT32)CacheFlush
+    (UINT32)CacheFlush,
+    (UINT32)Mmio
     ));
 
   //
@@ -760,7 +763,7 @@ SetMemoryEncDec (
   //
   // The InternalSetPageState() is used for setting the page state in the RMP table.
   //
-  if ((Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
+  if (!Mmio && (Mode == ClearCBit) && MemEncryptSevSnpIsEnabled ()) {
     InternalSetPageState (PhysicalAddress, EFI_SIZE_TO_PAGES (Length), SevSnpPageShared, FALSE);
   }
 
@@ -998,7 +1001,8 @@ InternalMemEncryptSevSetMemoryDecrypted (
            PhysicalAddress,
            Length,
            ClearCBit,
-           TRUE
+           TRUE,
+           FALSE
            );
 }
 
@@ -1031,7 +1035,8 @@ InternalMemEncryptSevSetMemoryEncrypted (
            PhysicalAddress,
            Length,
            SetCBit,
-           TRUE
+           TRUE,
+           FALSE
            );
 }
 
@@ -1064,6 +1069,7 @@ InternalMemEncryptSevClearMmioPageEncMask (
            PhysicalAddress,
            Length,
            ClearCBit,
-           FALSE
+           FALSE,
+           TRUE
            );
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 26/28] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (24 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 25/28] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 27/28] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

From: Tom Lendacky <thomas.lendacky@amd.com>

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

Use the SEV-SNP AP Creation NAE event to create and launch APs under
SEV-SNP. This capability will be advertised in the SEV Hypervisor
Feature Support PCD (PcdSevEsHypervisorFeatures).

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   5 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  17 ++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  11 +-
 .../MpInitLib/Ia32/SevSnpRmpAdjustInternal.c  |  31 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 275 ++++++++++++++++--
 .../MpInitLib/X64/SevSnpRmpAdjustInternal.c   |  44 +++
 7 files changed, 361 insertions(+), 25 deletions(-)
 create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 48d7dfa4450f..b9ce05e81b54 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -23,9 +23,11 @@ [Defines]
 
 [Sources.IA32]
   Ia32/MpFuncs.nasm
+  Ia32/SevSnpRmpAdjustInternal.c
 
 [Sources.X64]
   X64/MpFuncs.nasm
+  X64/SevSnpRmpAdjustInternal.c
 
 [Sources.common]
   MpEqu.inc
@@ -72,6 +74,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                           ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                       ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds  ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures                  ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                          ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index ab8279df596f..35057ac07cbb 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -23,9 +23,11 @@ [Defines]
 
 [Sources.IA32]
   Ia32/MpFuncs.nasm
+  Ia32/SevSnpRmpAdjustInternal.c
 
 [Sources.X64]
   X64/MpFuncs.nasm
+  X64/SevSnpRmpAdjustInternal.c
 
 [Sources.common]
   MpEqu.inc
@@ -62,10 +64,11 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures              ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                      ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevSnpIsEnabled                     ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
 
 [Ppis]
   gEdkiiPeiShadowMicrocodePpiGuid        ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 4abaa2243d0a..bb463d59256e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -15,6 +15,7 @@
 
 #include <Register/Intel/Cpuid.h>
 #include <Register/Amd/Cpuid.h>
+#include <Register/Amd/Ghcb.h>
 #include <Register/Intel/Msr.h>
 #include <Register/Intel/LocalApic.h>
 #include <Register/Intel/Microcode.h>
@@ -146,6 +147,7 @@ typedef struct {
   UINT8                          PlatformId;
   UINT64                         MicrocodeEntryAddr;
   UINT32                         MicrocodeRevision;
+  SEV_ES_SAVE_AREA               *SevEsSaveArea;
 } CPU_AP_DATA;
 
 //
@@ -289,6 +291,7 @@ struct _CPU_MP_DATA {
 
   BOOLEAN                        SevEsIsEnabled;
   BOOLEAN                        SevSnpIsEnabled;
+  BOOLEAN                        UseSevEsAPMethod;
   UINTN                          SevEsAPBuffer;
   UINTN                          SevEsAPResetStackStart;
   CPU_MP_DATA                    *NewCpuMpData;
@@ -743,5 +746,19 @@ PlatformShadowMicrocode (
   IN OUT CPU_MP_DATA             *CpuMpData
   );
 
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  );
+
 #endif
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 93fc63bf93e3..15e797cd0990 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -93,7 +93,12 @@ GetWakeupBuffer (
   EFI_PHYSICAL_ADDRESS    StartAddress;
   EFI_MEMORY_TYPE         MemoryType;
 
-  if (PcdGetBool (PcdSevEsIsEnabled)) {
+  //
+  // An SEV-ES-only guest requires the memory to be reserved. SEV-SNP, which
+  // is also considered SEV-ES, uses a different AP startup method, though,
+  // which does not have the same requirement.
+  //
+  if (PcdGetBool (PcdSevEsIsEnabled) && !PcdGetBool (PcdSevSnpIsEnabled)) {
     MemoryType = EfiReservedMemoryType;
   } else {
     MemoryType = EfiBootServicesData;
@@ -373,7 +378,7 @@ RelocateApLoop (
   MpInitLibWhoAmI (&ProcessorNumber);
   CpuMpData    = GetCpuMpData ();
   MwaitSupport = IsMwaitSupport ();
-  if (CpuMpData->SevEsIsEnabled) {
+  if (CpuMpData->UseSevEsAPMethod) {
     StackStart = CpuMpData->SevEsAPResetStackStart;
   } else {
     StackStart = mReservedTopOfApStack;
@@ -422,7 +427,7 @@ MpInitChangeApLoopCallback (
     CpuPause ();
   }
 
-  if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
+  if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
     //
     // There are APs present. Re-use reserved memory area below 1MB from
     // WakeupBuffer as the area to be used for transitioning to 16-bit mode
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c b/UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
new file mode 100644
index 000000000000..5c9ee08b2117
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/SevSnpRmpAdjustInternal.c
@@ -0,0 +1,31 @@
+/** @file
+
+  RMPADJUST helper function.
+
+  Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  )
+{
+  //
+  // RMPADJUST is not supported in 32-bit mode
+  //
+  return RETURN_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 586cff2f6813..9a1119206d98 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -295,10 +295,10 @@ GetApLoopMode (
       ApLoopMode = ApInHltLoop;
     }
 
-    if (PcdGetBool (PcdSevEsIsEnabled)) {
+    if (PcdGetBool (PcdSevEsIsEnabled) && !PcdGetBool (PcdSevSnpIsEnabled)) {
       //
-      // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
-      // protocol for starting APs
+      // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
+      // mode in order to use the GHCB protocol for starting APs
       //
       ApLoopMode = ApInHltLoop;
     }
@@ -869,7 +869,7 @@ ApWakeupFunction (
       // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
       // performs another INIT-SIPI-SIPI sequence.
       //
-      if (!CpuMpData->SevEsIsEnabled) {
+      if (!CpuMpData->UseSevEsAPMethod) {
         InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
       }
     }
@@ -883,7 +883,7 @@ ApWakeupFunction (
       //
       while (TRUE) {
         DisableInterrupts ();
-        if (CpuMpData->SevEsIsEnabled) {
+        if (CpuMpData->UseSevEsAPMethod) {
           MSR_SEV_ES_GHCB_REGISTER  Msr;
           GHCB                      *Ghcb;
           UINT64                    Status;
@@ -1196,9 +1196,11 @@ AllocateResetVector (
                                     );
     //
     // The AP reset stack is only used by SEV-ES guests. Do not allocate it
-    // if SEV-ES is not enabled.
+    // if SEV-ES is not enabled. An SEV-SNP guest is also considered
+    // an SEV-ES guest, but uses a different method of AP startup, eliminating
+    // the need for the allocation.
     //
-    if (PcdGetBool (PcdSevEsIsEnabled)) {
+    if (PcdGetBool (PcdSevEsIsEnabled) && !PcdGetBool (PcdSevSnpIsEnabled)) {
       //
       // Stack location is based on ProcessorNumber, so use the total number
       // of processors for calculating the total stack area.
@@ -1248,7 +1250,7 @@ FreeResetVector (
   // perform the restore as this will overwrite memory which has data
   // needed by SEV-ES.
   //
-  if (!CpuMpData->SevEsIsEnabled) {
+  if (!CpuMpData->UseSevEsAPMethod) {
     RestoreWakeupBuffer (CpuMpData);
   }
 }
@@ -1265,7 +1267,7 @@ AllocateSevEsAPMemory (
 {
   if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
     CpuMpData->SevEsAPBuffer =
-      CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
+      CpuMpData->UseSevEsAPMethod ? GetSevEsAPMemory () : 0;
   }
 }
 
@@ -1318,6 +1320,222 @@ SetSevEsJumpTable (
   JmpFar->Segment = (UINT16) (SipiVector >> 4);
 }
 
+/**
+  Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  CpuData          Pointer to CPU AP Data
+  @param[in]  ApicId           APIC ID of the vCPU
+**/
+STATIC
+VOID
+SevSnpCreateSaveArea (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN CPU_AP_DATA               *CpuData,
+  UINT32                       ApicId
+  )
+{
+  SEV_ES_SAVE_AREA          *SaveArea;
+  IA32_CR0                  ApCr0;
+  IA32_CR0                  ResetCr0;
+  IA32_CR4                  ApCr4;
+  IA32_CR4                  ResetCr4;
+  UINTN                     StartIp;
+  UINT8                     SipiVector;
+  UINT32                    RmpAdjustStatus;
+  UINT64                    VmgExitStatus;
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  GHCB                      *Ghcb;
+  BOOLEAN                   InterruptState;
+  UINT64                    ExitInfo1;
+  UINT64                    ExitInfo2;
+
+  //
+  // Allocate a single page for the SEV-ES Save Area and initialize it.
+  //
+  SaveArea = AllocateReservedPages (1);
+  if (!SaveArea) {
+    return;
+  }
+  ZeroMem (SaveArea, EFI_PAGE_SIZE);
+
+  //
+  // Propogate the CR0.NW and CR0.CD setting to the AP
+  //
+  ResetCr0.UintN = 0x00000010;
+  ApCr0.UintN = CpuData->VolatileRegisters.Cr0;
+  if (ApCr0.Bits.NW) {
+    ResetCr0.Bits.NW = 1;
+  }
+  if (ApCr0.Bits.CD) {
+    ResetCr0.Bits.CD = 1;
+  }
+
+  //
+  // Propagate the CR4.MCE setting to the AP
+  //
+  ResetCr4.UintN = 0;
+  ApCr4.UintN = CpuData->VolatileRegisters.Cr4;
+  if (ApCr4.Bits.MCE) {
+    ResetCr4.Bits.MCE = 1;
+  }
+
+  //
+  // Convert the start IP into a SIPI Vector
+  //
+  StartIp = CpuMpData->MpCpuExchangeInfo->BufferStart;
+  SipiVector = (UINT8) (StartIp >> 12);
+
+  //
+  // Set the CS:RIP value based on the start IP
+  //
+  SaveArea->Cs.Base = SipiVector << 12;
+  SaveArea->Cs.Selector = SipiVector << 8;
+  SaveArea->Cs.Limit = 0xFFFF;
+  SaveArea->Cs.Attributes.Bits.Present = 1;
+  SaveArea->Cs.Attributes.Bits.Sbit = 1;
+  SaveArea->Cs.Attributes.Bits.Type = SEV_ES_RESET_CODE_SEGMENT_TYPE;
+  SaveArea->Rip = StartIp & 0xFFF;
+
+  //
+  // Set the remaining values as defined in APM for INIT
+  //
+  SaveArea->Ds.Limit = 0xFFFF;
+  SaveArea->Ds.Attributes.Bits.Present = 1;
+  SaveArea->Ds.Attributes.Bits.Sbit = 1;
+  SaveArea->Ds.Attributes.Bits.Type = SEV_ES_RESET_DATA_SEGMENT_TYPE;
+  SaveArea->Es = SaveArea->Ds;
+  SaveArea->Fs = SaveArea->Ds;
+  SaveArea->Gs = SaveArea->Ds;
+  SaveArea->Ss = SaveArea->Ds;
+
+  SaveArea->Gdtr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Attributes.Bits.Present = 1;
+  SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_LDT_TYPE;
+  SaveArea->Idtr.Limit = 0xFFFF;
+  SaveArea->Tr.Limit = 0xFFFF;
+  SaveArea->Ldtr.Attributes.Bits.Present = 1;
+  SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_TSS_TYPE;
+
+  SaveArea->Efer   = 0x1000;
+  SaveArea->Cr4    = ResetCr4.UintN;
+  SaveArea->Cr0    = ResetCr0.UintN;
+  SaveArea->Dr7    = 0x0400;
+  SaveArea->Dr6    = 0xFFFF0FF0;
+  SaveArea->Rflags = 0x0002;
+  SaveArea->GPat   = 0x0007040600070406ULL;
+  SaveArea->XCr0   = 0x0001;
+  SaveArea->Mxcsr  = 0x1F80;
+  SaveArea->X87Ftw = 0x5555;
+  SaveArea->X87Fcw = 0x0040;
+
+  //
+  // Set the SEV-SNP specific fields for the save area:
+  //   VMPL - always VMPL0
+  //   SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits
+  //
+  SaveArea->Vmpl        = 0;
+  SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
+
+  //
+  // To turn the page into a recognized VMSA page, issue RMPADJUST:
+  //   Target VMPL but numerically higher than current VMPL
+  //   Target PermissionMask is not used
+  //
+  RmpAdjustStatus = SevSnpRmpAdjust (
+                      (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
+                      TRUE
+                      );
+  ASSERT (RmpAdjustStatus == 0);
+
+  ExitInfo1 = (UINT64) ApicId << 32;
+  ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;
+  ExitInfo2 = (UINT64) (UINTN) SaveArea;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  VmgInit (Ghcb, &InterruptState);
+  Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
+  VmgSetOffsetValid (Ghcb, GhcbRax);
+  VmgExitStatus = VmgExit (
+                    Ghcb,
+                    SVM_EXIT_SNP_AP_CREATION,
+                    ExitInfo1,
+                    ExitInfo2
+                    );
+  VmgDone (Ghcb, InterruptState);
+
+  ASSERT (VmgExitStatus == 0);
+  if (VmgExitStatus != 0) {
+    RmpAdjustStatus = SevSnpRmpAdjust (
+                        (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
+                        FALSE
+                        );
+    if (RmpAdjustStatus == 0) {
+      FreePages (SaveArea, 1);
+    } else {
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
+    }
+
+    SaveArea = NULL;
+  }
+
+  if (CpuData->SevEsSaveArea) {
+    RmpAdjustStatus = SevSnpRmpAdjust (
+                        (EFI_PHYSICAL_ADDRESS) (UINTN) CpuData->SevEsSaveArea,
+                        FALSE
+                        );
+    if (RmpAdjustStatus == 0) {
+      FreePages (CpuData->SevEsSaveArea, 1);
+    } else {
+      DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
+    }
+  }
+
+  CpuData->SevEsSaveArea = SaveArea;
+}
+
+/**
+  Create SEV-SNP APs.
+
+  @param[in]  CpuMpData        Pointer to CPU MP Data
+  @param[in]  ProcessorNumber  The handle number of specified processor
+                               (-1 for all APs)
+**/
+STATIC
+VOID
+SevSnpCreateAP (
+  IN CPU_MP_DATA               *CpuMpData,
+  IN INTN                      ProcessorNumber
+  )
+{
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+  CPU_AP_DATA      *CpuData;
+  UINTN            Index;
+  UINT32           ApicId;
+
+  ASSERT (CpuMpData->MpCpuExchangeInfo->BufferStart < 0x100000);
+
+  CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+
+  if (ProcessorNumber < 0) {
+    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+      if (Index != CpuMpData->BspNumber) {
+        CpuData = &CpuMpData->CpuData[Index];
+        ApicId = CpuInfoInHob[Index].ApicId,
+        SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
+      }
+    }
+  } else {
+    Index = (UINTN) ProcessorNumber;
+    CpuData = &CpuMpData->CpuData[Index];
+    ApicId = CpuInfoInHob[ProcessorNumber].ApicId,
+    SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
+  }
+}
+
 /**
   This function will be called by BSP to wakeup AP.
 
@@ -1349,7 +1567,7 @@ WakeUpAP (
   ResetVectorRequired = FALSE;
 
   if (CpuMpData->WakeUpByInitSipiSipi ||
-      CpuMpData->InitFlag   != ApInitDone) {
+      CpuMpData->InitFlag != ApInitDone) {
     ResetVectorRequired = TRUE;
     AllocateResetVector (CpuMpData);
     AllocateSevEsAPMemory (CpuMpData);
@@ -1390,7 +1608,7 @@ WakeUpAP (
     }
     if (ResetVectorRequired) {
       //
-      // For SEV-ES, the initial AP boot address will be defined by
+      // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
       // from the original INIT-SIPI-SIPI.
       //
@@ -1400,8 +1618,14 @@ WakeUpAP (
 
       //
       // Wakeup all APs
+      //   Must use the INIT-SIPI-SIPI method for initial configuration in
+      //   order to obtain the APIC ID.
       //
-      SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+      if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) {
+        SevSnpCreateAP (CpuMpData, -1);
+      } else {
+        SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+      }
     }
     if (CpuMpData->InitFlag == ApInitConfig) {
       if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
@@ -1491,7 +1715,7 @@ WakeUpAP (
       CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
 
       //
-      // For SEV-ES, the initial AP boot address will be defined by
+      // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
       // from the original INIT-SIPI-SIPI.
       //
@@ -1499,10 +1723,14 @@ WakeUpAP (
         SetSevEsJumpTable (ExchangeInfo->BufferStart);
       }
 
-      SendInitSipiSipi (
-        CpuInfoInHob[ProcessorNumber].ApicId,
-        (UINT32) ExchangeInfo->BufferStart
-        );
+      if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) {
+        SevSnpCreateAP (CpuMpData, (INTN) ProcessorNumber);
+      } else {
+        SendInitSipiSipi (
+          CpuInfoInHob[ProcessorNumber].ApicId,
+          (UINT32) ExchangeInfo->BufferStart
+          );
+      }
     }
     //
     // Wait specified AP waken up
@@ -2033,10 +2261,15 @@ MpInitLibInitialize (
   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
   InitializeSpinLock(&CpuMpData->MpLock);
-  CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
-  CpuMpData->SevSnpIsEnabled = PcdGetBool (PcdSevSnpIsEnabled);
-  CpuMpData->SevEsAPBuffer  = (UINTN) -1;
-  CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
+  CpuMpData->SevEsIsEnabled   = PcdGetBool (PcdSevEsIsEnabled);
+  CpuMpData->SevSnpIsEnabled  = PcdGetBool (PcdSevSnpIsEnabled);
+  CpuMpData->SevEsAPBuffer    = (UINTN) -1;
+  CpuMpData->GhcbBase         = PcdGet64 (PcdGhcbBase);
+  CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;
+
+  if (CpuMpData->SevSnpIsEnabled) {
+    ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);
+  }
 
   //
   // Make sure no memory usage outside of the allocated buffer.
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c b/UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c
new file mode 100644
index 000000000000..3048742facb5
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/SevSnpRmpAdjustInternal.c
@@ -0,0 +1,44 @@
+/** @file
+
+  RMPADJUST helper function.
+
+  Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+  Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
+
+  @param[in]  PageAddress
+  @param[in]  VmsaPage
+
+  @return  RMPADJUST return value
+**/
+UINT32
+SevSnpRmpAdjust (
+  IN  EFI_PHYSICAL_ADDRESS  PageAddress,
+  IN  BOOLEAN               VmsaPage
+  )
+{
+  UINT64  Rdx;
+
+  //
+  // The RMPADJUST instruction is used to set or clear the VMSA bit for a
+  // page. The VMSA change is only made when running at VMPL0 and is ignored
+  // otherwise. If too low a target VMPL is specified, the instruction can
+  // succeed without changing the VMSA bit when not running at VMPL0. Using a
+  // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if
+  // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately
+  // when no error is returned.
+  //
+  Rdx = 1;
+  if (VmsaPage) {
+    Rdx |= RMPADJUST_VMSA_PAGE_BIT;
+  }
+
+  return AsmRmpAdjust ((UINT64) PageAddress, 0, Rdx);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 27/28] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (25 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 26/28] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-06-30 12:53 ` [RFC PATCH v5 28/28] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
  2021-08-27  7:33 ` [edk2-devel] [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Gerd Hoffmann
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

When SEV-SNP is active, the CPUID and Secrets memory range contains the
information that is used during the VM boot. The content need to be persist
across the kexec boot. Mark the memory range as Reserved in the EFI map
so that guest OS or firmware does not use the range as a system RAM.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  4 ++++
 OvmfPkg/PlatformPei/MemDetect.c     | 21 +++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index bd0ade9f33d7..f22a60e7db0e 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -122,6 +122,10 @@ [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 2deec128f464..04e0c4e19f97 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -817,6 +817,27 @@ InitializeRamRegions (
 {
   QemuInitializeRam ();
 
+  if (MemEncryptSevSnpIsEnabled ()) {
+    //
+    // If SEV-SNP is enabled, reserve the Secrets and CPUID memory area.
+    //
+    // This memory range is given to the PSP by the hypervisor to populate
+    // the information used during the SNP VM boots, and it need to persist
+    // across the kexec boots. Mark it as EfiReservedMemoryType so that
+    // the guest firmware and OS does not use it as a system memory.
+    //
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSnpSecretsBase),
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfSnpSecretsSize),
+      EfiReservedMemoryType
+      );
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSnpCpuidBase),
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfSnpCpuidSize),
+      EfiReservedMemoryType
+      );
+  }
+
   if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
     //
     // This is the memory range that will be used for PEI on S3 resume
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC PATCH v5 28/28] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (26 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 27/28] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
@ 2021-06-30 12:53 ` Brijesh Singh
  2021-08-27  7:33 ` [edk2-devel] [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Gerd Hoffmann
  28 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-06-30 12:53 UTC (permalink / raw)
  To: devel
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth, Brijesh Singh

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

Now that both the secrets and cpuid pages are reserved in the HOB,
extract the location details through fixed PCD and make it available
to the guest OS through the configuration table.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/OvmfPkg.dec                           |  1 +
 OvmfPkg/AmdSevDxe/AmdSevDxe.inf               |  7 ++++++
 .../Guid/ConfidentialComputingSecret.h        | 18 +++++++++++++++
 OvmfPkg/AmdSevDxe/AmdSevDxe.c                 | 23 +++++++++++++++++++
 4 files changed, 49 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index afc559d74335..42ad88fc5622 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -122,6 +122,7 @@ [Guids]
   gQemuKernelLoaderFsMediaGuid          = {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
   gGrubFileGuid                         = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
   gConfidentialComputingSecretGuid      = {0xadf956ad, 0xe98c, 0x484c, {0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47}}
+  gConfidentialComputingBlobGuid        = {0x067b1f5f, 0xcf26, 0x44c5, {0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42}}
 
 [Ppis]
   # PPI whose presence in the PPI database signals that the TPM base address
diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
index 0676fcc5b6a4..ee1f8e4ff09a 100644
--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
+++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf
@@ -42,6 +42,13 @@ [FeaturePcd]
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpCpuidSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
+[Guids]
+  gConfidentialComputingBlobGuid
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
diff --git a/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h b/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
index 7026fc5b089f..aa1a3b015437 100644
--- a/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
+++ b/OvmfPkg/Include/Guid/ConfidentialComputingSecret.h
@@ -18,11 +18,29 @@
     { 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47 }, \
   }
 
+#define CONFIDENTIAL_COMPUTING_BLOB_GUID                \
+  { 0x067b1f5f,                                         \
+    0xcf26,                                             \
+    0x44c5,                                             \
+    { 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42 }, \
+  }
+
 typedef struct {
   UINT64 Base;
   UINT64 Size;
 } CONFIDENTIAL_COMPUTING_SECRET_LOCATION;
 
+typedef struct {
+  UINT32  Header;
+  UINT16  Version;
+  UINT16  Reserved1;
+  UINT64  SecretsPhysicalAddress;
+  UINT32  SecretsSize;
+  UINT64  CpuidPhysicalAddress;
+  UINT32  CpuidLSize;
+} CONFIDENTIAL_COMPUTING_BLOB_LOCATION;
+
 extern EFI_GUID gConfidentialComputingSecretGuid;
+extern EFI_GUID gConfidentialComputingBlobGuid;
 
 #endif // SEV_LAUNCH_SECRET_H_
diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.c b/OvmfPkg/AmdSevDxe/AmdSevDxe.c
index c66c4e9b9272..c59cc28cf6f5 100644
--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.c
+++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.c
@@ -17,8 +17,20 @@
 #include <Library/DxeServicesTableLib.h>
 #include <Library/MemEncryptSevLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Guid/ConfidentialComputingSecret.h>
 #include <Library/PcdLib.h>
 
+STATIC CONFIDENTIAL_COMPUTING_BLOB_LOCATION mSnpBootDxeTable = {
+  SIGNATURE_32('A','M','D','E'),
+  1,
+  0,
+  (UINT64)(UINTN) FixedPcdGet32 (PcdOvmfSnpSecretsBase),
+  FixedPcdGet32 (PcdOvmfSnpSecretsSize),
+  (UINT64)(UINTN) FixedPcdGet32 (PcdOvmfSnpCpuidBase),
+  FixedPcdGet32 (PcdOvmfSnpCpuidSize),
+};
+
 EFI_STATUS
 EFIAPI
 AmdSevDxeEntryPoint (
@@ -130,5 +142,16 @@ AmdSevDxeEntryPoint (
     }
   }
 
+  //
+  // If its SEV-SNP active guest then install the CONFIDENTIAL_COMPUTING_BLOB.
+  // It contains the location for both the Secrets and CPUID page.
+  //
+  if (MemEncryptSevSnpIsEnabled ()) {
+    return gBS->InstallConfigurationTable (
+                  &gConfidentialComputingBlobGuid,
+                  &mSnpBootDxeTable
+                  );
+  }
+
   return EFI_SUCCESS;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-06-30 12:53 ` [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
@ 2021-07-31  8:44   ` Erdem Aktas
  2021-08-03 15:10     ` Brijesh Singh
  0 siblings, 1 reply; 32+ messages in thread
From: Erdem Aktas @ 2021-07-31  8:44 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: devel, James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky,
	Jordan Justen, Ard Biesheuvel, Laszlo Ersek, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth

On Wed, Jun 30, 2021 at 5:54 AM Brijesh Singh <brijesh.singh@amd.com> wrote:
>
> a) Enhance the OVMF reset vector code to validate the pages as described
>    above (go through step 2 - 3).
> OR
> b) Validate the pages during the guest creation time. The SEV firmware
>    provides a command which can be used by the VMM to validate the pages
>    without affecting the measurement of the launch.

Are you referring to the PAGE_TYPE_UNMEASURED? Does it not affect the
measurement , PAGE_INFO will be still measured, right?

> Approach #b seems much simpler; it does not require any changes to the
> OVMF reset vector code.

I am worried about verifying the measurement. I understand the secret
page and cpuid page being part of measurement because both of them are
mentioned in the AMD SNP SPEC but now we are introducing a new
parameters (all the 4KB page addresses between SNP_HV_VALIDATED_START
and SNP_HV_VALIDATED_END) that VM owner needs to know to calculate the
measurement and verify the attestation.

Sorry if I am overthinking or missing something here.

-Erdem

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase
  2021-07-31  8:44   ` Erdem Aktas
@ 2021-08-03 15:10     ` Brijesh Singh
  0 siblings, 0 replies; 32+ messages in thread
From: Brijesh Singh @ 2021-08-03 15:10 UTC (permalink / raw)
  To: Erdem Aktas
  Cc: brijesh.singh, devel, James Bottomley, Min Xu, Jiewen Yao,
	Tom Lendacky, Jordan Justen, Ard Biesheuvel, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth



On 7/31/21 3:44 AM, Erdem Aktas wrote:
> On Wed, Jun 30, 2021 at 5:54 AM Brijesh Singh <brijesh.singh@amd.com> wrote:
>>
>> a) Enhance the OVMF reset vector code to validate the pages as described
>>     above (go through step 2 - 3).
>> OR
>> b) Validate the pages during the guest creation time. The SEV firmware
>>     provides a command which can be used by the VMM to validate the pages
>>     without affecting the measurement of the launch.
> 
> Are you referring to the PAGE_TYPE_UNMEASURED? Does it not affect the
> measurement , PAGE_INFO will be still measured, right?

Yes. The unmeasured here means the contents of the page is not measured 
but the PAGE_INFO is measured for all the pages added before the VM launch.

> 
>> Approach #b seems much simpler; it does not require any changes to the
>> OVMF reset vector code.
> 
> I am worried about verifying the measurement. I understand the secret
> page and cpuid page being part of measurement because both of them are
> mentioned in the AMD SNP SPEC but now we are introducing a new
> parameters (all the 4KB page addresses between SNP_HV_VALIDATED_START
> and SNP_HV_VALIDATED_END) that VM owner needs to know to calculate the
> measurement and verify the attestation.
> 

The page info of both the secrets and cpuid page also need to be 
measured. In order to calculate the expected measurement, a caller need 
to know the page_info for the secrets and cpuid. To get the page_info 
for the CPUID and Secrets they must read the OVMF reset GUID. While at 
it, they can also get the the range of the unmeasured pages. I don't see 
that being a big issue. Having said so, as I described in the patch, its 
not only option. It was easier for implementation without compromising 
the security.


> Sorry if I am overthinking or missing something here.
> 
> -Erdem
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support
  2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
                   ` (27 preceding siblings ...)
  2021-06-30 12:53 ` [RFC PATCH v5 28/28] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
@ 2021-08-27  7:33 ` Gerd Hoffmann
  28 siblings, 0 replies; 32+ messages in thread
From: Gerd Hoffmann @ 2021-08-27  7:33 UTC (permalink / raw)
  To: devel, brijesh.singh
  Cc: James Bottomley, Min Xu, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Laszlo Ersek, Erdem Aktas, Eric Dong, Ray Ni,
	Rahul Kumar, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Michael Roth

  Hi,

[ /me reading through a bunch of old threads .... ]

> Many of the integrity guarantees of SEV-SNP are enforced through a new
> structure called the Reverse Map Table (RMP). Adding a new page to SEV-SNP
> VM requires a 2-step process. First, the hypervisor assigns a page to the
> guest using the new RMPUPDATE instruction. This transitions the page to
> guest-invalid. Second, the guest validates the page using the new PVALIDATE
> instruction.

Intel TDX names this "accepting pages", but it is basically the same
concept, correct?

If so I see opportunities to share code here.  The problem of tracking
which pages are validated/accepted and which are not should be the same
for both TDX and SEV-SNP.  The overall workflow (which phase
validates/accepts which pages etc.) should be identical too.

> At this time we only support the pre-validation. OVMF detects all the available
> system RAM in the PEI phase. When SEV-SNP is enabled, the memory is validated
> before it is made available to the EDK2 core.

How do you detect memory?  Intel wants pass a hob with a memory map (and
possibly more config info) to the early boot code, and I'm wondering why
TDX needs that while SEV-SNP apparently doesn't (at least I havn't
noticed anything similar while going over the patches quickly).

thanks,
  Gerd


^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2021-08-27  7:33 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-06-30 12:52 [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 01/28] OvmfPkg/ResetVector: move SEV specific code in a separate file Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 02/28] OvmfPkg/ResetVector: add the macro to invoke MSR protocol based VMGEXIT Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 03/28] OvmfPkg/ResetVector: add the macro to request guest termination Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 04/28] OvmfPkg: reserve SNP secrets page Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 05/28] OvmfPkg: reserve CPUID page for SEV-SNP Brijesh Singh
2021-06-30 12:52 ` [RFC PATCH v5 06/28] OvmfPkg/ResetVector: introduce SEV-SNP boot block GUID Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 07/28] OvmfPkg/ResetVector: pre-validate the data pages used in SEC phase Brijesh Singh
2021-07-31  8:44   ` Erdem Aktas
2021-08-03 15:10     ` Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 08/28] OvmfPkg/ResetVector: invalidate the GHCB page Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 09/28] OvmfPkg/ResetVector: check the vmpl level Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 10/28] UefiCpuPkg: Define the SEV-SNP specific dynamic PCDs Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 11/28] OvmfPkg/MemEncryptSevLib: add MemEncryptSevSnpEnabled() Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 12/28] OvmfPkg/SecMain: register GHCB gpa for the SEV-SNP guest Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 13/28] OvmfPkg/PlatformPei: " Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 14/28] OvmfPkg/AmdSevDxe: do not use extended PCI config space Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 15/28] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 16/28] OvmfPkg/BaseMemEncryptSevLib: skip the pre-validated " Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 17/28] OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 18/28] OvmfPkg/SecMain: pre-validate the memory used for decompressing Fv Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 19/28] OvmfPkg/PlatformPei: validate the system RAM when SNP is active Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 20/28] OvmfPkg/PlatformPei: set the SEV-SNP enabled PCD Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 21/28] OvmfPkg/PlatformPei: set the Hypervisor Features PCD Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 22/28] MdePkg/GHCB: increase the GHCB protocol max version Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 23/28] UefiCpuPkg/MpLib: add support to register GHCB GPA when SEV-SNP is enabled Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 24/28] OvmfPkg/MemEncryptSevLib: change the page state in the RMP table Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 25/28] OvmfPkg/MemEncryptSevLib: skip page state change for Mmio address Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 26/28] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 27/28] OvmfPkg/PlatformPei: mark cpuid and secrets memory reserved in EFI map Brijesh Singh
2021-06-30 12:53 ` [RFC PATCH v5 28/28] OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table Brijesh Singh
2021-08-27  7:33 ` [edk2-devel] [RFC PATCH v5 00/28] Add AMD Secure Nested Paging (SEV-SNP) support Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox