public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [RFC PATCH 00/28] SEV-ES guest support
@ 2019-08-19 21:35 thomas.lendacky
  2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
                   ` (28 more replies)
  0 siblings, 29 replies; 46+ messages in thread
From: thomas.lendacky @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

This patch series provides support for running EDK2/OVMF under SEV-ES.

Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
SEV support to protect the guest register state from the hypervisor. See
"AMD64 Architecture Programmer's Manual Volume 2: System Programming",
section "15.35 Encrypted State (SEV-ES)" [1].

In order to allow a hypervisor to perform functions on behalf of a guest,
there is architectural support for notifying a guest's operating system
when certain types of VMEXITs are about to occur. This allows the guest to
selectively share information with the hypervisor to satisfy the requested
function. The notification is performed using a new exception, the VMM
Communication exception (#VC). The information is shared through the
Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
The GHCB format and the protocol for using it is documented in "SEV-ES
Guest-Hypervisor Communication Block Standardization" [2].

The main areas of the EDK2 code that are updated to support SEV-ES are
around the exception handling support and the AP boot support.

Exception support is required starting in Sec, continuing through Pei
and into Dxe in order to handle #VC exceptions that are generated.  Each
AP requires it's own GHCB page as well as a page to hold values specific
to that AP.

AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
is typically used to boot the APs. However, the hypervisor is not allowed
to update the guest registers. The GHCB document [2] talks about how SMP
booting under SEV-ES is performed.

Since the GHCB page must be a shared (unencrypted) page, the processor
must be running in long mode in order for the guest and hypervisor to
communicate with each other. As a result, SEV-ES is only supported under
the X64 architecture.

[1] https://www.amd.com/system/files/TechDocs/24593.pdf
[2] https://developer.amd.com/wp-content/resources/56421.pdf
[3] https://github.com/AMDESE/ovmf/tree/sev-es-v6

Tom Lendacky (28):
  OvmfPkg/Sec: Enable cache early to speed up booting
  OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  OvmfPkg: Create a GHCB page for use during Sec phase
  OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  OvmfPkg: A per-CPU variable area for #VC usage
  OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  MdePkg/BaseLib: Implement the VMGEXIT support
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling
    support for Sec phase
  UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling
    support for Pei/Dxe phases
  UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if
    SEV-ES is active
  UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES
  UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support
    SEV-ES

 OvmfPkg/OvmfPkg.dec                           |    5 +
 UefiCpuPkg/UefiCpuPkg.dec                     |    7 +
 OvmfPkg/OvmfPkgIa32.dsc                       |    1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |    1 +
 OvmfPkg/OvmfPkgX64.dsc                        |    6 +
 OvmfPkg/OvmfPkgX64.fdf                        |    9 +-
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    3 +
 MdePkg/Library/BaseLib/BaseLib.inf            |    2 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |    5 +
 OvmfPkg/ResetVector/ResetVector.inf           |    4 +
 OvmfPkg/Sec/SecMain.inf                       |    1 +
 .../DxeCpuExceptionHandlerLib.inf             |    4 +
 .../PeiCpuExceptionHandlerLib.inf             |    4 +
 .../SecPeiCpuExceptionHandlerLib.inf          |    4 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    4 +-
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    2 +
 .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
 MdePkg/Include/Library/BaseLib.h              |   30 +
 MdePkg/Include/Protocol/Cpu.h                 |    6 +
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
 UefiCpuPkg/CpuDxe/CpuDxe.h                    |   14 +
 UefiCpuPkg/CpuDxe/CpuGdt.h                    |    2 +-
 UefiCpuPkg/Include/Library/MpInitLib.h        |   17 +
 UefiCpuPkg/Include/Register/Amd/Fam17Msr.h    |   28 +
 UefiCpuPkg/Include/Register/Amd/Ghcb.h        |  197 +++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
 .../CpuExceptionCommon.h                      |    2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |   73 +-
 MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c       |    5 +
 .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |    6 +-
 .../Core/DxeIplPeim/X64/DxeLoadFunc.c         |   11 +-
 .../Core/DxeIplPeim/X64/VirtualMemory.c       |   49 +-
 MdePkg/Library/BaseLib/Ia32/GccInline.c       |   17 +
 MdePkg/Library/BaseLib/X64/GccInline.c        |   45 +
 .../MemEncryptSevLibInternal.c                |   78 +-
 .../BaseMemEncryptSevLib/X64/VirtualMemory.c  |   33 +-
 OvmfPkg/PlatformPei/AmdSev.c                  |   83 ++
 OvmfPkg/Sec/SecMain.c                         |   34 +-
 UefiCpuPkg/CpuDxe/CpuDxe.c                    |   10 +
 UefiCpuPkg/CpuDxe/CpuGdt.c                    |   10 +-
 .../CpuExceptionCommon.c                      |    2 +-
 .../Ia32/AMDSevVcCommon.c                     |   13 +
 .../PeiDxeAMDSevVcHandler.c                   |   22 +
 .../PeiDxeSmmCpuException.c                   |   16 +
 .../SecAMDSevVcHandler.c                      |   45 +
 .../SecPeiCpuException.c                      |   16 +
 .../X64/AMDSevVcCommon.c                      | 1192 +++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  124 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  255 +++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   16 +
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
 MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   38 +
 MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   39 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   85 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  210 ++-
 OvmfPkg/ResetVector/ResetVector.nasmb         |    3 +-
 .../X64/ExceptionHandlerAsm.nasm              |   15 +
 UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    4 +-
 .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
 UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  367 ++++-
 .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
 62 files changed, 3239 insertions(+), 108 deletions(-)
 create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
 create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
 create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm
 create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm

-- 
2.17.1


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

* [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-21 14:21   ` [edk2-devel] " Laszlo Ersek
  2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
                   ` (27 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Currently, the OVMF code relies on the hypervisor to enable the cache
support on the processor in order to improve the boot speed. However,
with SEV-ES, the hypervisor is not allowed to change the CR0 register
to enable caching.

Update the OVMF Sec support to enable caching in order to improve the
boot speed.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Sec/SecMain.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 3914355cd17b..2448be0cd408 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -739,6 +739,11 @@ SecCoreStartupWithStack (
 
   ProcessLibraryConstructorList (NULL, NULL);
 
+  //
+  // Enable caching
+  //
+  AsmEnableCache ();
+
   DEBUG ((EFI_D_INFO,
     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
     (UINT32)(UINTN)BootFv,
-- 
2.17.1


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

* [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
  2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

When running as an SEV-ES guest in 32-bit mode, it is not possible to
perform a CPUID instruction because it will require communicating with
the hypervisor using the GHCB.  However, writes to the GHCB when in
32-bit mode will be will be encrypted and thus not able to be read
by the hypervisor.

To get around this, add an IDT entry for the #VC exception.  The #VC
handler will use the GHCB CPUID request/response protocol to obtain
the requested CPUID function values and provide these to the guest.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/ResetVector/ResetVector.inf       |   2 +
 OvmfPkg/ResetVector/Ia32/PageTables64.asm | 173 ++++++++++++++++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb     |   1 +
 3 files changed, 176 insertions(+)

diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index b0ddfa5832a2..960b47cd0797 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -35,3 +35,5 @@ [BuildOptions]
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index abad009f20f5..c6071fe934de 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,6 +37,15 @@ BITS    32
 ; If SEV is disabled then EAX will be zero.
 ;
 CheckSevFeature:
+    ;
+    ; Set up exception handlers to check for SEV-ES
+    ;   Load temporary RAM stack based on PCDs
+    ;   Establish exception handlers
+    ;
+    mov       esp, SEV_TOP_OF_STACK
+    mov       eax, ADDR_OF(idtr)
+    lidt      [cs:eax]
+
     ; Check if we have a valid (0x8000_001F) CPUID leaf
     mov       eax, 0x80000000
     cpuid
@@ -73,6 +82,15 @@ NoSev:
     xor       eax, eax
 
 SevExit:
+    ;
+    ; Clear exception handlers and stack
+    ;
+    push      eax
+    mov       eax, ADDR_OF(idtr_clear)
+    lidt      [cs:eax]
+    pop       eax
+    mov       esp, 0
+
     OneTimeCallRet CheckSevFeature
 
 ;
@@ -146,3 +164,158 @@ pageTableEntriesLoop:
     mov     cr3, eax
 
     OneTimeCallRet SetCr3ForPageTables64
+
+SevEsIdtCommon:
+    hlt
+    jmp     SevEsIdtCommon
+    iret
+
+SevEsIdtVmmComm:
+    ;
+    ; If we're here, then we are an SEV-ES guest and this
+    ; was triggered by a CPUID instruction
+    ;
+    pop     ecx                     ; Error code
+    cmp     ecx, 0x72               ; Be sure it was CPUID
+    jne     SevEsIdtCommon
+
+    ;
+    ; Set up local variable room on the stack
+    ;   CPUID function      : + 28
+    ;   CPUID 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, 32
+
+    ; Save CPUID function and initial register request
+    mov     [esp + 28], eax
+    xor     eax, eax
+    mov     [esp + 24], eax
+
+    ; Save current GHCB MSR value
+    mov     ecx, 0xc0010130
+    rdmsr
+    mov     [esp + 20], eax
+    mov     [esp + 16], 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 + 24]
+    cmp     eax, 4
+    jge     VmmDone
+
+    shl     eax, 30
+    or      eax, 0x004
+    mov     edx, [esp + 28]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    ; Issue VMGEXIT (rep; vmmcall)
+    db      0xf3
+    db      0x0f
+    db      0x01
+    db      0xd9
+
+    ;
+    ; 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, 0x005
+    jne     SevEsIdtCommon
+
+    ; Save returned value
+    shr     eax, 30
+    and     eax, 0x3
+    shl     eax, 2
+    mov     ecx, esp
+    add     ecx, eax
+    mov     [ecx], edx
+
+    ; Next register
+    inc     word [esp + 24]
+
+    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 + 20]
+    mov     edx, [esp + 16]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    mov     eax, [esp + 0]
+    mov     ebx, [esp + 4]
+    mov     ecx, [esp + 8]
+    mov     edx, [esp + 12]
+
+    add     esp, 32
+    add     word [esp], 2           ; Skip over the CPUID instruction
+    iret
+
+ALIGN   2
+
+idtr:
+    dw      IDT_END - IDT_BASE - 1  ; Limit
+    dd      ADDR_OF(IDT_BASE)       ; Base
+
+idtr_clear:
+    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
+;
+%rep 29
+    dw      (ADDR_OF(SevEsIdtCommon) & 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(SevEsIdtCommon) >> 16)      ; 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
+;
+%rep 2
+    dw      (ADDR_OF(SevEsIdtCommon) & 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(SevEsIdtCommon) >> 16)      ; Offset high bits 31..16
+%endrep
+IDT_END:
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 75cfe16654b1..3b213cd05ab2 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -55,6 +55,7 @@
 
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 %include "Ia32/Flat32ToFlat64.asm"
+  %define SEV_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/PageTables64.asm"
 %endif
 
-- 
2.17.1


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

* [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
  2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
  2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

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

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Include/Library/MemEncryptSevLib.h    | 12 +++
 .../MemEncryptSevLibInternal.c                | 77 ++++++++++++-------
 2 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index 64dd6977b0f8..a50a0de9c870 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -13,6 +13,18 @@
 
 #include <Base.h>
 
+/**
+  Returns a boolean to indicate whether SEV-ES is enabled
+
+  @retval TRUE           SEV-ES is enabled
+  @retval FALSE          SEV-ES is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsIsEnabled (
+  VOID
+  );
+
 /**
   Returns a boolean to indicate whether SEV is enabled
 
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
index 96a66e373f11..9c1d68e017fe 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
@@ -20,19 +20,17 @@
 #include <Uefi/UefiBaseType.h>
 
 STATIC BOOLEAN mSevStatus = FALSE;
+STATIC BOOLEAN mSevEsStatus = FALSE;
 STATIC BOOLEAN mSevStatusChecked = FALSE;
 
 /**
 
-  Returns a boolean to indicate whether SEV is enabled
-
-  @retval TRUE           SEV is enabled
-  @retval FALSE          SEV is not enabled
+  Reads and sets the status of SEV features
   **/
 STATIC
-BOOLEAN
+VOID
 EFIAPI
-InternalMemEncryptSevIsEnabled (
+InternalMemEncryptSevStatus (
   VOID
   )
 {
@@ -56,32 +54,57 @@ InternalMemEncryptSevIsEnabled (
       //
       Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
       if (Msr.Bits.SevBit) {
-        return TRUE;
+        mSevStatus = TRUE;
+      }
+
+      if (Eax.Bits.SevEsBit) {
+        //
+        // Check MSR_0xC0010131 Bit 1 (Sev-Es Enabled)
+        //
+        if (Msr.Bits.SevEsBit) {
+          mSevEsStatus = TRUE;
+        }
       }
     }
   }
 
-  return FALSE;
-}
-
-/**
-  Returns a boolean to indicate whether SEV is enabled
-
-  @retval TRUE           SEV is enabled
-  @retval FALSE          SEV is not enabled
-**/
-BOOLEAN
-EFIAPI
-MemEncryptSevIsEnabled (
-  VOID
-  )
-{
-  if (mSevStatusChecked) {
-    return mSevStatus;
-  }
-
-  mSevStatus = InternalMemEncryptSevIsEnabled();
   mSevStatusChecked = TRUE;
+}
+
+/**
+  Returns a boolean to indicate whether SEV-ES is enabled
+
+  @retval TRUE           SEV-ES is enabled
+  @retval FALSE          SEV-ES is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus();
+  }
+
+  return mSevEsStatus;
+}
+
+/**
+  Returns a boolean to indicate whether SEV is enabled
+
+  @retval TRUE           SEV is enabled
+  @retval FALSE          SEV is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevIsEnabled (
+  VOID
+  )
+{
+  if (!mSevStatusChecked) {
+    InternalMemEncryptSevStatus();
+  }
 
   return mSevStatus;
 }
-- 
2.17.1


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

* [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (2 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-21 14:25   ` [edk2-devel] " Laszlo Ersek
  2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
                   ` (24 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

A GHCB page is needed during the Sec phase, so this new page must be
created.  Since the GHCB must be marked as an un-encrypted, or shared,
page, an additional pagetable page is required so break down the 2MB
region where the GHCB page lives into 4K pagetable entries.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkg.dec                        |  5 +++
 OvmfPkg/OvmfPkgX64.fdf                     | 11 ++++---
 OvmfPkg/PlatformPei/PlatformPei.inf        |  2 ++
 OvmfPkg/ResetVector/ResetVector.inf        |  2 ++
 UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm  | 37 +++++++++++++++++++++-
 OvmfPkg/ResetVector/ResetVector.nasmb      |  2 +-
 7 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 9640360f6245..2ead9a944af4 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
   #  The value should be a multiple of 4KB.
   gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
 
+  ## Specify the GHCB base address and size.
+  #  The value should be a multiple of 4KB for each.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 74407072563b..2a2427092382 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -67,13 +67,16 @@ [FD.MEMFD]
 BlockSize     = 0x10000
 NumBlocks     = 0xC0
 
-0x000000|0x006000
+0x000000|0x007000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
 
-0x006000|0x001000
-gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
-
 0x007000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+
+0x008000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+0x009000|0x001000
 gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
 
 0x010000|0x010000
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index d9fd9c8f05b3..aed1f64b7c93 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -72,6 +72,8 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 960b47cd0797..d66f4dc29737 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -37,3 +37,5 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
index 37b935dcdb30..55a5723e164e 100644
--- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
+++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
@@ -17,6 +17,34 @@
 #ifndef __FAM17_MSR_H__
 #define __FAM17_MSR_H__
 
+/**
+  Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
+
+**/
+#define MSR_SEV_ES_GHCB                    0xc0010130
+
+/**
+  MSR information returned for #MSR_SEV_ES_GHCB
+**/
+typedef union {
+  struct {
+    UINT32  GhcbNegotiateBit:1;
+
+    UINT32  Reserved:31;
+  } Bits;
+
+  struct {
+    UINT8   Reserved[3];
+    UINT8   SevEncryptionBitPos;
+    UINT16  SevEsProtocolMin;
+    UINT16  SevEsProtocolMax;
+  } GhcbProtocol;
+
+  VOID    *Ghcb;
+
+  UINT64  GhcbPhysicalAddress;
+} MSR_SEV_ES_GHCB_REGISTER;
+
 /**
   Secure Encrypted Virtualization (SEV) status register
 
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index c6071fe934de..fd4d5b1d8661 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -21,6 +21,11 @@ BITS    32
 %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 + \
@@ -120,7 +125,7 @@ SevNotActive:
     ; more permanent location by DxeIpl.
     ;
 
-    mov     ecx, 6 * 0x1000 / 4
+    mov     ecx, 7 * 0x1000 / 4
     xor     eax, eax
 clearPageTablesMemoryLoop:
     mov     dword[ecx * 4 + PT_ADDR (0) - 4], eax
@@ -157,6 +162,36 @@ pageTableEntriesLoop:
     mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
     loop    pageTableEntriesLoop
 
+    ;
+    ; The GHCB will live at 0x807000 (just after the page tables)
+    ; and needs to be un-encrypted.  This requires the 2MB page
+    ; (index 4 in the first 1GB page) for this range be broken down
+    ; into 512 4KB pages.  All will be marked as encrypted, except
+    ; for the GHCB.
+    ;
+    mov     ecx, 4
+    mov     eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
+
+    mov     ecx, 512
+pageTableEntries4kLoop:
+    mov     eax, ecx
+    dec     eax
+    shl     eax, 12
+    add     eax, 0x800000
+    add     eax, PAGE_4K_PDE_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
+    mov     [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
+    loop    pageTableEntries4kLoop
+
+    ;
+    ; Clear the encryption bit from the GHCB entry (index 7 in the
+    ; new PTE table - (0x807000 - 0x800000) >> 12).
+    ;
+    mov     ecx, 7
+    xor     edx, edx
+    mov     [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
+
     ;
     ; Set CR3 now that the paging structures are available
     ;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 3b213cd05ab2..56d9b86ed943 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -49,7 +49,7 @@
 %ifdef ARCH_X64
   #include <AutoGen.h>
 
-  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
+  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
     %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
   %endif
 
-- 
2.17.1


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

* [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (3 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-21 14:31   ` [edk2-devel] " Laszlo Ersek
  2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
                   ` (23 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Allocate memory for the GHCB pages during SEV initialization for use
during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
pages, modify CreateIdentityMappingPageTables() so that pagetable entries
are created without the encryption bit set.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
 OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
 .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
 .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
 .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
 .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
 .../MemEncryptSevLibInternal.c                |  1 -
 .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
 OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
 11 files changed, 164 insertions(+), 23 deletions(-)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 6ddf0cd22466..4d5a2593cf13 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
   # @ValidRange  0x80000001 | 0 - 1
   gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
 
+  ## Contains the GHCB page allocation information.<BR><BR>
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index dda8dac18441..d6fc7cdf7da8 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -569,6 +569,10 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set GHCB base address for SEV-ES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index abc3217b0179..b994398633e3 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
 
 [Packages.ARM, Packages.AARCH64]
   ArmPkg/ArmPkg.dec
@@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase                                 ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize                                 ## CONSUMES
 
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index aed1f64b7c93..f53195e6dda5 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -102,6 +102,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
index 2d0493f109e8..6b7c38a441d6 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
@@ -201,6 +201,8 @@ EnableExecuteDisableBit (
   @param[in, out] PageEntry2M           Pointer to 2M page entry.
   @param[in]      StackBase             Stack base address.
   @param[in]      StackSize             Stack size.
+  @param[in]      GhcbBase              GHCB page area base address.
+  @param[in]      GhcbSize              GHCB page area size.
 
 **/
 VOID
@@ -208,7 +210,9 @@ Split2MPageTo4K (
   IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
   IN OUT UINT64                         *PageEntry2M,
   IN EFI_PHYSICAL_ADDRESS               StackBase,
-  IN UINTN                              StackSize
+  IN UINTN                              StackSize,
+  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
+  IN UINTN                              GhcbSize
   );
 
 /**
@@ -217,6 +221,8 @@ Split2MPageTo4K (
 
   @param[in] StackBase  Stack base address.
   @param[in] StackSize  Stack size.
+  @param[in] GhcbBase   GHCB page area base address.
+  @param[in] GhcbSize   GHCB page area size.
 
   @return The address of 4 level page map.
 
@@ -224,7 +230,9 @@ Split2MPageTo4K (
 UINTN
 CreateIdentityMappingPageTables (
   IN EFI_PHYSICAL_ADDRESS   StackBase,
-  IN UINTN                  StackSize
+  IN UINTN                  StackSize,
+  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
+  IN UINTN                  GhcbkSize
   );
 
 
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index 172d7cd1c60c..630a3503f6ba 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
         //
         // Need to split this 2M page that covers stack range.
         //
-        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
       } else {
         //
         // Fill in the Page Directory entries
@@ -278,7 +278,7 @@ HandOffToDxeCore (
     //
     // Create page table and save PageMapLevel4 to CR3
     //
-    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
+    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
 
     //
     // End of PEI phase signal
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
index 2867610bff4d..77da20e5c5c5 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
@@ -35,6 +35,8 @@ HandOffToDxeCore (
   UINT32                          Index;
   EFI_VECTOR_HANDOFF_INFO         *VectorInfo;
   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
+  VOID                            *GhcbBase;
+  UINTN                           GhcbSize;
 
   if (IsNullDetectionEnabled ()) {
     ClearFirst4KPage (HobList.Raw);
@@ -77,12 +79,19 @@ HandOffToDxeCore (
   TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
   TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
 
+  //
+  // Get the address and size of the GHCB pages
+  //
+  GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
+  GhcbSize = PcdGet64 (PcdGhcbSize);
+
   PageTables = 0;
   if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
     //
     // Create page table and save PageMapLevel4 to CR3
     //
-    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
+    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
+                                                  (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
   } else {
     //
     // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index edc38e4525c4..b3c3c3276e6a 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -180,6 +180,8 @@ EnableExecuteDisableBit (
   @param Size         Size of the given physical memory.
   @param StackBase    Base address of stack.
   @param StackSize    Size of stack.
+  @param GhcbBase     Base address of GHCB pages.
+  @param GhcbSize     Size of GHCB area.
 
   @retval TRUE      Page table should be split.
   @retval FALSE     Page table should not be split.
@@ -189,7 +191,9 @@ ToSplitPageTable (
   IN EFI_PHYSICAL_ADDRESS               Address,
   IN UINTN                              Size,
   IN EFI_PHYSICAL_ADDRESS               StackBase,
-  IN UINTN                              StackSize
+  IN UINTN                              StackSize,
+  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
+  IN UINTN                              GhcbSize
   )
 {
   if (IsNullDetectionEnabled () && Address == 0) {
@@ -208,6 +212,12 @@ ToSplitPageTable (
     }
   }
 
+  if (GhcbBase) {
+    if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
+      return TRUE;
+    }
+  }
+
   return FALSE;
 }
 /**
@@ -321,6 +331,8 @@ AllocatePageTableMemory (
   @param[in, out] PageEntry2M           Pointer to 2M page entry.
   @param[in]      StackBase             Stack base address.
   @param[in]      StackSize             Stack size.
+  @param[in]      GhcbBase              GHCB page area base address.
+  @param[in]      GhcbSize              GHCB page area size.
 
 **/
 VOID
@@ -328,7 +340,9 @@ Split2MPageTo4K (
   IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
   IN OUT UINT64                         *PageEntry2M,
   IN EFI_PHYSICAL_ADDRESS               StackBase,
-  IN UINTN                              StackSize
+  IN UINTN                              StackSize,
+  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
+  IN UINTN                              GhcbSize
   )
 {
   EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
@@ -354,7 +368,12 @@ Split2MPageTo4K (
     //
     // Fill in the Page Table entries
     //
-    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
+    if (!GhcbBase
+        || (PhysicalAddress4K < GhcbBase)
+        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
+      PageTableEntry->Uint64 |= AddressEncMask;
+    }
     PageTableEntry->Bits.ReadWrite = 1;
 
     if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
@@ -382,6 +401,8 @@ Split2MPageTo4K (
   @param[in, out] PageEntry1G           Pointer to 1G page entry.
   @param[in]      StackBase             Stack base address.
   @param[in]      StackSize             Stack size.
+  @param[in]      GhcbBase              GHCB page area base address.
+  @param[in]      GhcbSize              GHCB page area size.
 
 **/
 VOID
@@ -389,7 +410,9 @@ Split1GPageTo2M (
   IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
   IN OUT UINT64                         *PageEntry1G,
   IN EFI_PHYSICAL_ADDRESS               StackBase,
-  IN UINTN                              StackSize
+  IN UINTN                              StackSize,
+  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
+  IN UINTN                              GhcbSize
   )
 {
   EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
@@ -412,11 +435,11 @@ Split1GPageTo2M (
 
   PhysicalAddress2M = PhysicalAddress;
   for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
-    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
+    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
       //
       // Need to split this 2M page that covers NULL or stack range.
       //
-      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
     } else {
       //
       // Fill in the Page Directory entries
@@ -615,6 +638,8 @@ EnablePageTableProtection (
 
   @param[in] StackBase  Stack base address.
   @param[in] StackSize  Stack size.
+  @param[in] GhcbBase   GHCB base address.
+  @param[in] GhcbSize   GHCB size.
 
   @return The address of 4 level page map.
 
@@ -622,7 +647,9 @@ EnablePageTableProtection (
 UINTN
 CreateIdentityMappingPageTables (
   IN EFI_PHYSICAL_ADDRESS   StackBase,
-  IN UINTN                  StackSize
+  IN UINTN                  StackSize,
+  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
+  IN UINTN                  GhcbSize
   )
 {
   UINT32                                        RegEax;
@@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
       PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
 
       for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
-        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
-          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
+        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
+          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
         } else {
           //
           // Fill in the Page Directory entries
@@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
         PageDirectoryPointerEntry->Bits.Present = 1;
 
         for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
-          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
+          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
             //
             // Need to split this 2M page that covers NULL or stack range.
             //
-            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
+            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
           } else {
             //
             // Fill in the Page Directory entries
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
index 9c1d68e017fe..1dce01dd7546 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
@@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
   return mSevStatus;
 }
 
-
 /**
   Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
   Save State Map.
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
index 5e110c84ff81..3a4f223f8a86 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
@@ -183,6 +183,8 @@ AllocatePageTableMemory (
   @param[in, out] PageEntry2M           Pointer to 2M page entry.
   @param[in]      StackBase             Stack base address.
   @param[in]      StackSize             Stack size.
+  @param[in]      GhcbBase              GHCB page area base address.
+  @param[in]      GhcbSize              GHCB page area size.
 
 **/
 STATIC
@@ -191,7 +193,9 @@ Split2MPageTo4K (
   IN        PHYSICAL_ADDRESS               PhysicalAddress,
   IN  OUT   UINT64                        *PageEntry2M,
   IN        PHYSICAL_ADDRESS               StackBase,
-  IN        UINTN                          StackSize
+  IN        UINTN                          StackSize,
+  IN        PHYSICAL_ADDRESS               GhcbBase,
+  IN        UINTN                          GhcbSize
   )
 {
   PHYSICAL_ADDRESS                  PhysicalAddress4K;
@@ -217,7 +221,12 @@ Split2MPageTo4K (
     //
     // Fill in the Page Table entries
     //
-    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
+    if (!GhcbBase
+        || (PhysicalAddress4K < GhcbBase)
+        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
+      PageTableEntry->Uint64 |= AddressEncMask;
+    }
     PageTableEntry->Bits.ReadWrite = 1;
     PageTableEntry->Bits.Present = 1;
     if ((PhysicalAddress4K >= StackBase) &&
@@ -417,6 +426,8 @@ EnablePageTableProtection (
   @param[in, out] PageEntry1G           Pointer to 1G page entry.
   @param[in]      StackBase             Stack base address.
   @param[in]      StackSize             Stack size.
+  @param[in]      GhcbBase              GHCB page area base address.
+  @param[in]      GhcbSize              GHCB page area size.
 
 **/
 STATIC
@@ -425,7 +436,9 @@ Split1GPageTo2M (
   IN          PHYSICAL_ADDRESS               PhysicalAddress,
   IN  OUT     UINT64                         *PageEntry1G,
   IN          PHYSICAL_ADDRESS               StackBase,
-  IN          UINTN                          StackSize
+  IN          UINTN                          StackSize,
+  IN          PHYSICAL_ADDRESS               GhcbBase,
+  IN          UINTN                          GhcbSize
   )
 {
   PHYSICAL_ADDRESS                  PhysicalAddress2M;
@@ -450,8 +463,10 @@ Split1GPageTo2M (
        (IndexOfPageDirectoryEntries++,
         PageDirectoryEntry++,
         PhysicalAddress2M += SIZE_2MB)) {
-    if ((PhysicalAddress2M < StackBase + StackSize) &&
-        ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
+    if (((PhysicalAddress2M < StackBase + StackSize) &&
+         ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
+        ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
+         ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
       //
       // Need to split this 2M page that covers stack range.
       //
@@ -459,7 +474,9 @@ Split1GPageTo2M (
         PhysicalAddress2M,
         (UINT64 *)PageDirectoryEntry,
         StackBase,
-        StackSize
+        StackSize,
+        GhcbBase,
+        GhcbSize
         );
     } else {
       //
@@ -714,6 +731,8 @@ SetMemoryEncDec (
           (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
           (UINT64 *)PageDirectory1GEntry,
           0,
+          0,
+          0,
           0
           );
         continue;
@@ -768,6 +787,8 @@ SetMemoryEncDec (
             (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
             (UINT64 *)PageDirectory2MEntry,
             0,
+            0,
+            0,
             0
             );
           continue;
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 2ae8126ccf8a..84896d4681f9 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -16,9 +16,68 @@
 #include <PiPei.h>
 #include <Register/Amd/Cpuid.h>
 #include <Register/Cpuid.h>
+#include <Register/Amd/Msr.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
 
 #include "Platform.h"
 
+/**
+
+  Initialize SEV-ES support if running an SEV-ES guest.
+
+  **/
+STATIC
+VOID
+AmdSevEsInitialize (
+  VOID
+  )
+{
+  VOID              *GhcbBase;
+  PHYSICAL_ADDRESS  GhcbBasePa;
+  UINTN             GhcbPageCount;
+  RETURN_STATUS     DecryptStatus, PcdStatus;
+
+  if (!MemEncryptSevEsIsEnabled ()) {
+    return;
+  }
+
+  GhcbPageCount = mMaxCpuCount;
+
+  //
+  // Allocate GHCB pages.
+  //
+  GhcbBase = AllocatePages (GhcbPageCount);
+  ASSERT (GhcbBase);
+
+  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
+
+  DecryptStatus = MemEncryptSevClearPageEncMask (
+    0,
+    GhcbBasePa,
+    GhcbPageCount,
+    TRUE
+    );
+  ASSERT_RETURN_ERROR (DecryptStatus);
+
+  BuildMemoryAllocationHob (
+    GhcbBasePa,
+    EFI_PAGES_TO_SIZE (GhcbPageCount),
+    EfiBootServicesData
+    );
+
+  SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
+
+  PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
+
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
+}
+
 /**
 
   Function checks if SEV support is available, if present then it sets
@@ -89,4 +148,9 @@ AmdSevInitialize (
       EfiBootServicesData                // MemoryType
       );
   }
+
+  //
+  // Check and perform SEV-ES initialization if required.
+  //
+  AmdSevEsInitialize ();
 }
-- 
2.17.1


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

* [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (4 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

A per-CPU implementation for holding values specific to a CPU when
running as an SEV-ES guest, specifically to hold the Debug Register
value. Allocate an extra page immediately after the GHCB page for each
AP.

Using the page after the GHCB ensures that it is unique per AP. But,
it also ends up being marked shared/unencrypted when it doesn't need to
be. It is possible, during PEI, to mark only the GHCB pages as shared,
but DXE is not as easy. There needs to be a way to change the pagetables
created for DXE using CreateIdentityMappingPageTables() before switching
to them.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgX64.fdf       | 8 ++++----
 OvmfPkg/PlatformPei/AmdSev.c | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 2a2427092382..3ba3d7384745 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -70,13 +70,13 @@ [FD.MEMFD]
 0x000000|0x007000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
 
-0x007000|0x001000
+0x007000|0x002000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
 
-0x008000|0x001000
-gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
-
 0x009000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+0x00A000|0x001000
 gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
 
 0x010000|0x010000
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 84896d4681f9..87ac842a1590 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -42,7 +42,7 @@ AmdSevEsInitialize (
     return;
   }
 
-  GhcbPageCount = mMaxCpuCount;
+  GhcbPageCount = mMaxCpuCount * 2;
 
   //
   // Allocate GHCB pages.
-- 
2.17.1


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

* [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (5 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-21 15:44   ` [edk2-devel] " Laszlo Ersek
  2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
                   ` (21 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

The SEV support will clear the C-bit from non-RAM areas.  The early GDT
lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
will be read as un-encrypted even though it is encrypted. This will result
in a failure to be able to handle the exception.

Move the GDT into RAM so it can be accessed without error when running as
an SEV-ES guest.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 87ac842a1590..5f4983fd36d8 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -37,6 +37,8 @@ AmdSevEsInitialize (
   PHYSICAL_ADDRESS  GhcbBasePa;
   UINTN             GhcbPageCount;
   RETURN_STATUS     DecryptStatus, PcdStatus;
+  IA32_DESCRIPTOR   Gdtr;
+  VOID              *Gdt;
 
   if (!MemEncryptSevEsIsEnabled ()) {
     return;
@@ -76,6 +78,20 @@ AmdSevEsInitialize (
   DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
 
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
+
+  //
+  // The SEV support will clear the C-bit from the non-RAM areas. Since
+  // the GDT initially lives in that area and it will be read when a #VC
+  // exception happens, it needs to be moved to RAM for an SEV-ES guest.
+  //
+  AsmReadGdtr (&Gdtr);
+
+  Gdt = AllocatePool (Gdtr.Limit + 1);
+  ASSERT (Gdt);
+
+  CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
+  Gdtr.Base = (UINTN) Gdt;
+  AsmWriteGdtr (&Gdtr);
 }
 
 /**
-- 
2.17.1


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

* [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (6 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:47   ` Ni, Ray
  2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
                   ` (20 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

VMGEXIT is a new instruction used for Hypervisor/Guest communication when
running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
to occur, resulting in a #VMEXIT with an exit code value of 0x403.

To support VMGEXIT, define the VMGEXIT assember routine to issue the
instruction (rep; vmmcall), the GHCB structure and some helper functions
for communicating register information to and from the hypervisor and the
guest.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Library/BaseLib/BaseLib.inf      |   1 +
 MdePkg/Include/Library/BaseLib.h        |  14 ++
 UefiCpuPkg/Include/Register/Amd/Ghcb.h  | 197 ++++++++++++++++++++++++
 MdePkg/Library/BaseLib/X64/GccInline.c  |  17 ++
 MdePkg/Library/BaseLib/X64/VmgExit.nasm |  38 +++++
 5 files changed, 267 insertions(+)
 create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
 create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm

diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 3586beb0ab5c..a41401340f95 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -286,6 +286,7 @@ [Sources.X64]
   X64/ReadCr2.nasm| MSFT
   X64/ReadCr0.nasm| MSFT
   X64/ReadEflags.nasm| MSFT
+  X64/VmgExit.nasm | MSFT
 
 
   X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 2a75bc023f56..80bd5cf57a72 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7880,6 +7880,20 @@ AsmLfence (
   VOID
   );
 
+/**
+  Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
+
+  Executes a VMGEXIT instruction. This function is only available on IA-32 and
+  x64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+  VOID
+  );
+
+
 /**
   Patch the immediate operand of an IA32 or X64 instruction such that the byte,
   word, dword or qword operand is encoded at the end of the instruction's
diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
new file mode 100644
index 000000000000..e9fd116fac25
--- /dev/null
+++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
@@ -0,0 +1,197 @@
+
+#ifndef __GHCB_H__
+#define __GHCB_H__
+
+#include <Protocol/DebugSupport.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#define UD_EXCEPTION  6
+#define GP_EXCEPTION 13
+
+#define GHCB_VERSION_MIN     1
+#define GHCB_VERSION_MAX     1
+
+#define GHCB_STANDARD_USAGE  0
+
+typedef enum {
+  SvmExitDr7Read       = 0x27,
+  SvmExitDr7Write      = 0x37,
+  SvmExitRdtsc         = 0x6E,
+  SvmExitRdpmc,
+  SvmExitCpuid         = 0x72,
+  SvmExitInvd          = 0x76,
+  SvmExitIoioProt      = 0x7B,
+  SvmExitMsr,
+  SvmExitVmmCall       = 0x81,
+  SvmExitRdtscp        = 0x87,
+  SvmExitWbinvd        = 0x89,
+  SvmExitMonitor,
+  SvmExitMwait,
+  SvmExitNpf           = 0x400,
+
+  // VMG special exits
+  SvmExitMmioRead      = 0x80000001,
+  SvmExitMmioWrite,
+  SvmExitNmiComplete,
+  SvmExitApResetHold,
+
+  SvmExitUnsupported   = 0x8000FFFF,
+} SVM_EXITCODE;
+
+typedef enum {
+  GhcbCpl              = 25,
+  GhcbRflags           = 46,
+  GhcbRip,
+  GhcbRsp              = 59,
+  GhcbRax              = 63,
+  GhcbRcx              = 97,
+  GhcbRdx,
+  GhcbRbx,
+  GhcbRbp              = 101,
+  GhcbRsi,
+  GhcbRdi,
+  GhcbR8,
+  GhcbR9,
+  GhcbR10,
+  GhcbR11,
+  GhcbR12,
+  GhcbR13,
+  GhcbR14,
+  GhcbR15,
+  GhcbXCr0             = 125,
+} GHCB_REGISTER;
+
+typedef struct {
+  UINT8                  Reserved1[203];
+  UINT8                  Cpl;
+  UINT8                  Reserved2[148];
+  UINT64                 Dr7;
+  UINT8                  Reserved3[144];
+  UINT64                 Rax;
+  UINT8                  Reserved4[264];
+  UINT64                 Rcx;
+  UINT64                 Rdx;
+  UINT64                 Rbx;
+  UINT8                  Reserved5[112];
+  UINT64                 SwExitCode;
+  UINT64                 SwExitInfo1;
+  UINT64                 SwExitInfo2;
+  UINT64                 SwScratch;
+  UINT8                  Reserved6[56];
+  UINT64                 XCr0;
+  UINT8                  ValidBitmap[16];
+  UINT64                 X87StateGpa;
+  UINT8                  Reserved7[1016];
+} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
+
+typedef struct {
+  GHCB_SAVE_AREA         SaveArea;
+  UINT8                  SharedBuffer[2032];
+  UINT8                  Reserved1[10];
+  UINT16                 ProtocolVersion;
+  UINT32                 GhcbUsage;
+} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
+
+typedef union {
+  struct {
+    UINT32  Lower32Bits;
+    UINT32  Upper32Bits;
+  } Elements;
+
+  UINT64    Uint64;
+} GHCB_EXIT_INFO;
+
+static inline
+BOOLEAN
+GhcbIsRegValid(
+  GHCB                   *Ghcb,
+  GHCB_REGISTER          Reg
+  )
+{
+  UINT32  RegIndex = Reg / 8;
+  UINT32  RegBit   = Reg & 0x07;
+
+  return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
+}
+
+static inline
+VOID
+GhcbSetRegValid(
+  GHCB                   *Ghcb,
+  GHCB_REGISTER          Reg
+  )
+{
+  UINT32  RegIndex = Reg / 8;
+  UINT32  RegBit   = Reg & 0x07;
+
+  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
+}
+
+static inline
+VOID
+VmgException(
+  UINTN                  Exception
+  )
+{
+  switch (Exception) {
+  case UD_EXCEPTION:
+  case GP_EXCEPTION:
+    break;
+  default:
+    ASSERT (0);
+  }
+}
+
+static inline
+UINTN
+VmgExit(
+  GHCB                   *Ghcb,
+  UINT64                 ExitCode,
+  UINT64                 ExitInfo1,
+  UINT64                 ExitInfo2
+  )
+{
+  GHCB_EXIT_INFO   ExitInfo;
+  UINTN            Reason, Action;
+
+  Ghcb->SaveArea.SwExitCode = ExitCode;
+  Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
+  Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
+  AsmVmgExit ();
+
+  if (!Ghcb->SaveArea.SwExitInfo1) {
+    return 0;
+  }
+
+  ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
+  Reason = ExitInfo.Elements.Upper32Bits;
+  Action = ExitInfo.Elements.Lower32Bits;
+  switch (Action) {
+  case 1:
+    VmgException (Reason);
+    break;
+  default:
+    ASSERT (0);
+  }
+
+  return Reason;
+}
+
+static inline
+VOID
+VmgInit(
+  GHCB                   *Ghcb
+  )
+{
+  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
+}
+
+static inline
+VOID
+VmgDone(
+  GHCB                   *Ghcb
+  )
+{
+}
+#endif
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 154ce1f57e92..17539caa0798 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
 }
 
 
+/**
+  Executes a VMGEXIT instruction.
+
+  Executes a VMGEXIT instruction. This function is only available on IA-32 and
+  X64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+  VOID
+  )
+{
+  __asm__ __volatile__ ("rep; vmmcall":::"memory");
+}
+
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
new file mode 100644
index 000000000000..b673bb94b60d
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
@@ -0,0 +1,38 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution.  The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+;   VmgExit.Asm
+;
+; Abstract:
+;
+;   AsmVmgExit function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    DEFAULT REL
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmVmgExit (
+;   VOID
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExit)
+ASM_PFX(AsmVmgExit):
+    rep; vmmcall
+    ret
+
-- 
2.17.1


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

* [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (7 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Add base support to handle #VC exceptions.  This includes a stub routine
to invoke when a #VC exception occurs and special checks in the common
exception handlers to invoke the #VC exception handler routine.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../DxeCpuExceptionHandlerLib.inf                |  2 ++
 .../PeiCpuExceptionHandlerLib.inf                |  2 ++
 .../SecPeiCpuExceptionHandlerLib.inf             |  2 ++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h      | 12 ++++++++++++
 .../CpuExceptionHandlerLib/CpuExceptionCommon.h  |  2 ++
 .../CpuExceptionHandlerLib/CpuExceptionCommon.c  |  2 +-
 .../PeiDxeAMDSevVcHandler.c                      | 11 +++++++++++
 .../PeiDxeSmmCpuException.c                      | 16 ++++++++++++++++
 .../CpuExceptionHandlerLib/SecAMDSevVcHandler.c  | 11 +++++++++++
 .../CpuExceptionHandlerLib/SecPeiCpuException.c  | 16 ++++++++++++++++
 10 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index e41383573043..331ae7334c45 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -37,6 +37,8 @@ [Sources.common]
   CpuExceptionCommon.c
   PeiDxeSmmCpuException.c
   DxeException.c
+  PeiDxeAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index f31423ac0f91..89b5d496e56f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -37,6 +37,8 @@ [Sources.common]
   CpuExceptionCommon.c
   PeiCpuException.c
   PeiDxeSmmCpuException.c
+  PeiDxeAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 6d25cafe2ca3..5e5ab6244b11 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -36,6 +36,8 @@ [Sources.common]
   CpuExceptionCommon.h
   CpuExceptionCommon.c
   SecPeiCpuException.c
+  SecAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
new file mode 100644
index 000000000000..ee52f3b5220d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -0,0 +1,12 @@
+
+#ifndef _AMD_SEV_VC_COMMON_H_
+#define _AMD_SEV_VC_COMMON_H_
+
+#include <Protocol/DebugSupport.h>
+
+UINTN
+DoVcException(
+  EFI_SYSTEM_CONTEXT  Context
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 805dd9cbb4ff..0f274e7ea328 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -24,6 +24,8 @@
 #define  CPU_INTERRUPT_NUM         256
 #define  HOOKAFTER_STUB_SIZE        16
 
+#define  VC_EXCEPTION               29
+
 //
 // Exception Error Code of Page-Fault Exception
 //
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index 8adbd43fefb4..39e4dd9e9417 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -14,7 +14,7 @@
 //
 // 1 means an error code will be pushed, otherwise 0
 //
-CONST UINT32 mErrorCodeFlag = 0x00227d00;
+CONST UINT32 mErrorCodeFlag = 0x20227d00;
 
 //
 // Define the maximum message length
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
new file mode 100644
index 000000000000..1e027b3f2964
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -0,0 +1,11 @@
+
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcException(
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  return 0;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 72c2aeca4c13..0c248e7eb904 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -7,6 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
 #include <Library/DebugLib.h>
 
 /**
@@ -86,6 +87,21 @@ CommonExceptionHandlerWorker (
     break;
   }
 
+  if (ExceptionType == VC_EXCEPTION) {
+    UINTN  Status;
+    //
+    // #VC must be handled for an SEV-ES guest
+    //
+    Status = DoVcException(SystemContext);
+    if (Status) {
+      // Exception not handled - Status contains the desired exception now
+      ExceptionType = Status;
+    } else {
+      // Exception handled
+      return;
+    }
+  }
+
   if (ExternalInterruptHandler != NULL &&
       ExternalInterruptHandler[ExceptionType] != NULL) {
     (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
new file mode 100644
index 000000000000..1e027b3f2964
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -0,0 +1,11 @@
+
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcException(
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  return 0;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index 20148db74cf8..998a90ba61a6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include <PiPei.h>
 #include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
 
 CONST UINTN    mDoFarReturnFlag  = 0;
 
@@ -24,6 +25,21 @@ CommonExceptionHandler (
   IN EFI_SYSTEM_CONTEXT   SystemContext
   )
 {
+  if (ExceptionType == VC_EXCEPTION) {
+    UINTN  Status;
+    //
+    // #VC must be handled for an SEV-ES guest
+    //
+    Status = DoVcException(SystemContext);
+    if (Status) {
+      // Exception not handled - Status contains the desired exception now
+      ExceptionType = Status;
+    } else {
+      // Exception handled
+      return;
+    }
+  }
+
   //
   // Initialize the serial port before dumping.
   //
-- 
2.17.1


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

* [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (8 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
@ 2019-08-19 21:35 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:35 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

An SEV-ES guest will generate a #VC exception when it encounters a
non-automatic exit (NAE) event. It is expected that the #VC exception
handler will communicate with the hypervisor using the GHCB to handle
the NAE event.

NAE events can occur during the Sec phase, so initialize exception
handling early in the OVMF Sec support. Add to the basic #VC exception
handler to set the GHCB MSR to a pre-allocated GHCB and call a common
#VC handler.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Sec/SecMain.inf                       |  1 +
 .../SecPeiCpuExceptionHandlerLib.inf          |  2 ++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |  7 ++++
 MdePkg/Library/BaseLib/Ia32/GccInline.c       | 17 +++++++++
 OvmfPkg/Sec/SecMain.c                         | 29 ++++++++-------
 .../Ia32/AMDSevVcCommon.c                     | 13 +++++++
 .../SecAMDSevVcHandler.c                      | 36 ++++++++++++++++++-
 .../X64/AMDSevVcCommon.c                      | 27 ++++++++++++++
 8 files changed, 118 insertions(+), 14 deletions(-)
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c

diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 63ba4cb555fb..7f53845f5436 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -50,6 +50,7 @@ [LibraryClasses]
   PeCoffExtraActionLib
   ExtractGuidedSectionLib
   LocalApicLib
+  CpuExceptionHandlerLib
 
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 5e5ab6244b11..1b3605af5ca4 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
   Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/AMDSevVcCommon.c
 
 [Sources.X64]
   X64/ExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/AMDSevVcCommon.c
 
 [Sources.common]
   CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
index ee52f3b5220d..94f9e6e5122d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -3,10 +3,17 @@
 #define _AMD_SEV_VC_COMMON_H_
 
 #include <Protocol/DebugSupport.h>
+#include <Register/Amd/Ghcb.h>
 
 UINTN
 DoVcException(
   EFI_SYSTEM_CONTEXT  Context
   );
 
+UINTN
+DoVcCommon(
+  GHCB                *Ghcb,
+  EFI_SYSTEM_CONTEXT  Context
+  );
+
 #endif
diff --git a/MdePkg/Library/BaseLib/Ia32/GccInline.c b/MdePkg/Library/BaseLib/Ia32/GccInline.c
index 5287200f8754..55d2e12bcdc9 100644
--- a/MdePkg/Library/BaseLib/Ia32/GccInline.c
+++ b/MdePkg/Library/BaseLib/Ia32/GccInline.c
@@ -1763,3 +1763,20 @@ AsmFlushCacheLine (
 }
 
 
+/**
+  Executes a VMGEXIT instruction.
+
+  Executes a VMGEXIT instruction. This function is only available on IA-32 and
+  X64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+  VOID
+  )
+{
+  __asm__ __volatile__ ("rep; vmmcall":::"memory");
+}
+
+
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 2448be0cd408..021c1bd30711 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -24,6 +24,7 @@
 #include <Library/PeCoffExtraActionLib.h>
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
 
 #include <Ppi/TemporaryRamSupport.h>
 
@@ -737,6 +738,21 @@ SecCoreStartupWithStack (
     Table[Index] = 0;
   }
 
+  //
+  // Initialize IDT
+  //
+  IdtTableInStack.PeiService = NULL;
+  for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
+    CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
+  }
+
+  IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
+  IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
+
+  AsmWriteIdtr (&IdtDescriptor);
+
+  InitializeCpuExceptionHandlers (NULL);
+
   ProcessLibraryConstructorList (NULL, NULL);
 
   //
@@ -756,19 +772,6 @@ SecCoreStartupWithStack (
   //
   InitializeFloatingPointUnits ();
 
-  //
-  // Initialize IDT
-  //  
-  IdtTableInStack.PeiService = NULL;
-  for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
-    CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
-  }
-
-  IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
-  IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
-
-  AsmWriteIdtr (&IdtDescriptor);
-
 #if defined (MDE_CPU_X64)
   //
   // ASSERT that the Page Tables were set by the reset vector code to
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
new file mode 100644
index 000000000000..1b0c44bd6a61
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
@@ -0,0 +1,13 @@
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcCommon (
+  GHCB                *Ghcb,
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  return GP_EXCEPTION;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
index 1e027b3f2964..a32025d3481b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -1,11 +1,45 @@
 
+#include <Library/BaseLib.h>
+#include <Register/Amd/Msr.h>
 #include "CpuExceptionCommon.h"
 #include "AMDSevVcCommon.h"
 
+
+#define GHCB_INIT 0x807000
+
 UINTN
 DoVcException(
   EFI_SYSTEM_CONTEXT  Context
   )
 {
-  return 0;
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  GHCB                      *Ghcb;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  if (Msr.Bits.GhcbNegotiateBit) {
+    if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
+      ASSERT (0);
+      return GP_EXCEPTION;
+    }
+
+    if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
+        (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {
+      ASSERT (0);
+      return GP_EXCEPTION;
+    }
+
+    Msr.GhcbPhysicalAddress = GHCB_INIT;
+    AsmWriteMsr64(MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
+
+    Ghcb = Msr.Ghcb;
+    SetMem (Ghcb, sizeof (*Ghcb), 0);
+
+    /* Set the version to the maximum that can be supported */
+    Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
+    Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
+  }
+
+  return DoVcCommon(Ghcb, Context);
 }
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
new file mode 100644
index 000000000000..18e462ce80a2
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -0,0 +1,27 @@
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcCommon (
+  GHCB                *Ghcb,
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  EFI_SYSTEM_CONTEXT_X64  *Regs = Context.SystemContextX64;
+  UINTN                   ExitCode;
+  UINTN                   Status;
+
+  VmgInit (Ghcb);
+
+  ExitCode = Regs->ExceptionData;
+  switch (ExitCode) {
+  default:
+    Status = VmgExit (Ghcb, SvmExitUnsupported, ExitCode, 0);
+  }
+
+  VmgDone (Ghcb);
+
+  return Status;
+}
-- 
2.17.1


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

* [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (9 preceding siblings ...)
  2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a IOIO_PROT intercept generates a #VC exception. VMGEXIT
must be used to allow the hypervisor to handle this intercept.

Add support to construct the required GHCB values to support a IOIO_PROT
NAE event.  Parse the instruction that generated the #VC exception,
setting the required register values in the GHCB and creating the proper
SW_EXITINFO1 value in the GHCB.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 425 +++++++++++++++++-
 1 file changed, 420 insertions(+), 5 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 18e462ce80a2..3b69aca48055 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -3,25 +3,440 @@
 #include <Library/DebugLib.h>
 #include "AMDSevVcCommon.h"
 
+typedef enum {
+  LongMode64Bit        = 0,
+  LongModeCompat32Bit,
+  LongModeCompat16Bit,
+} SEV_ES_INSTRUCTION_MODE;
+
+typedef enum {
+  Size8Bits            = 0,
+  Size16Bits,
+  Size32Bits,
+  Size64Bits,
+} SEV_ES_INSTRUCTION_SIZE;
+
+typedef enum {
+  SegmentEs            = 0,
+  SegmentCs,
+  SegmentSs,
+  SegmentDs,
+  SegmentFs,
+  SegmentGs,
+} SEV_ES_INSTRUCTION_SEGMENT;
+
+typedef enum {
+  RepNone              = 0,
+  RepZ,
+  RepNZ,
+} SEV_ES_INSTRUCTION_REP;
+
+typedef union {
+  struct {
+    UINT8  B:1;
+    UINT8  X:1;
+    UINT8  R:1;
+    UINT8  W:1;
+    UINT8  REX:4;
+  } Bits;
+
+  UINT8  Uint8;
+} SEV_ES_INSTRUCTION_REX_PREFIX;
+
+typedef union {
+  struct {
+    UINT8  Rm:3;
+    UINT8  Reg:3;
+    UINT8  Mod:2;
+  } Bits;
+
+  UINT8  Uint8;
+} SEV_ES_INSTRUCTION_MODRM;
+
+typedef union {
+  struct {
+    UINT8  Base:3;
+    UINT8  Index:3;
+    UINT8  Scale:2;
+  } Bits;
+
+  UINT8  Uint8;
+} SEV_ES_INSTRUCTION_SIB;
+
+typedef struct {
+  struct {
+    UINT8  Rm;
+    UINT8  Reg;
+    UINT8  Mod;
+  } ModRm;
+
+  struct {
+    UINT8  Base;
+    UINT8  Index;
+    UINT8  Scale;
+  } Sib;
+
+  UINTN  RegData;
+  UINTN  RmData;
+} SEV_ES_INSTRUCTION_OPCODE_EXT;
+
+typedef struct {
+  GHCB                           *Ghcb;
+
+  SEV_ES_INSTRUCTION_MODE        Mode;
+  SEV_ES_INSTRUCTION_SIZE        DataSize;
+  SEV_ES_INSTRUCTION_SIZE        AddrSize;
+  BOOLEAN                        SegmentSpecified;
+  SEV_ES_INSTRUCTION_SEGMENT     Segment;
+  SEV_ES_INSTRUCTION_REP         RepMode;
+
+  UINT8                          *Begin;
+  UINT8                          *End;
+
+  UINT8                          *Prefixes;
+  UINT8                          *OpCodes;
+  UINT8                          *Displacement;
+  UINT8                          *Immediate;
+
+  SEV_ES_INSTRUCTION_REX_PREFIX  RexPrefix;
+
+  BOOLEAN                        ModRmPresent;
+  SEV_ES_INSTRUCTION_MODRM       ModRm;
+
+  BOOLEAN                        SibPresent;
+  SEV_ES_INSTRUCTION_SIB         Sib;
+
+  UINT8                          PrefixSize;
+  UINT8                          OpCodeSize;
+  UINT8                          DisplacementSize;
+  UINT8                          ImmediateSize;
+
+  SEV_ES_INSTRUCTION_OPCODE_EXT  Ext;
+} SEV_ES_INSTRUCTION_DATA;
+
+typedef
+UINTN
+(*NAE_EXIT) (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  );
+
+STATIC
+VOID
+DecodePrefixes (
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_MODE  Mode;
+  SEV_ES_INSTRUCTION_SIZE  ModeDataSize;
+  SEV_ES_INSTRUCTION_SIZE  ModeAddrSize;
+  UINT8                    *Byte;
+
+  /*TODO: Determine current mode - 64-bit for now */
+  Mode = LongMode64Bit;
+  ModeDataSize = Size32Bits;
+  ModeAddrSize = Size64Bits;
+
+  InstructionData->Mode = Mode;
+  InstructionData->DataSize = ModeDataSize;
+  InstructionData->AddrSize = ModeAddrSize;
+
+  InstructionData->Prefixes = InstructionData->Begin;
+
+  Byte = InstructionData->Prefixes;
+  for ( ; ; Byte++, InstructionData->PrefixSize++) {
+    switch (*Byte) {
+    case 0x26:
+    case 0x2E:
+    case 0x36:
+    case 0x3E:
+      if (Mode != LongMode64Bit) {
+        InstructionData->SegmentSpecified = TRUE;
+        InstructionData->Segment = (*Byte >> 3) & 3;
+      }
+      break;
+
+    case 0x40 ... 0x4F:
+      InstructionData->RexPrefix.Uint8 = *Byte;
+      if (*Byte & 0x08)
+        InstructionData->DataSize = Size64Bits;
+      break;
+
+    case 0x64:
+      InstructionData->SegmentSpecified = TRUE;
+      InstructionData->Segment = *Byte & 7;
+      break;
+
+    case 0x66:
+      if (!InstructionData->RexPrefix.Uint8) {
+        InstructionData->DataSize =
+          (Mode == LongMode64Bit)       ? Size16Bits :
+          (Mode == LongModeCompat32Bit) ? Size16Bits :
+          (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
+      }
+      break;
+
+    case 0x67:
+      InstructionData->AddrSize =
+        (Mode == LongMode64Bit)       ? Size32Bits :
+        (Mode == LongModeCompat32Bit) ? Size16Bits :
+        (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
+      break;
+
+    case 0xF0:
+      break;
+
+    case 0xF2:
+      InstructionData->RepMode = RepZ;
+      break;
+
+    case 0xF3:
+      InstructionData->RepMode = RepNZ;
+      break;
+
+    default:
+      InstructionData->OpCodes = Byte;
+      InstructionData->OpCodeSize = (*Byte == 0x0F) ? 2 : 1;
+
+      InstructionData->End = Byte + InstructionData->OpCodeSize;
+      InstructionData->Displacement = InstructionData->End;
+      InstructionData->Immediate = InstructionData->End;
+      return;
+    }
+  }
+}
+
+STATIC
+UINT64
+InstructionLength (
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  return (UINT64) (InstructionData->End - InstructionData->Begin);
+}
+
+STATIC
+VOID
+InitInstructionData (
+  SEV_ES_INSTRUCTION_DATA  *InstructionData,
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs
+  )
+{
+  SetMem (InstructionData, sizeof (*InstructionData), 0);
+  InstructionData->Ghcb = Ghcb;
+  InstructionData->Begin = (UINT8 *) Regs->Rip;
+  InstructionData->End = (UINT8 *) Regs->Rip;
+
+  DecodePrefixes (Regs, InstructionData);
+}
+
+STATIC
+UINTN
+UnsupportedExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN  Status;
+
+  Status = VmgExit (Ghcb, SvmExitUnsupported, Regs->ExceptionData, 0);
+  ASSERT (0);
+
+  return Status;
+}
+
+#define IOIO_TYPE_STR  (1 << 2)
+#define IOIO_TYPE_IN   1
+#define IOIO_TYPE_INS  (IOIO_TYPE_IN | IOIO_TYPE_STR)
+#define IOIO_TYPE_OUT  0
+#define IOIO_TYPE_OUTS (IOIO_TYPE_OUT | IOIO_TYPE_STR)
+
+#define IOIO_REP       (1 << 3)
+
+#define IOIO_ADDR_64   (1 << 9)
+#define IOIO_ADDR_32   (1 << 8)
+#define IOIO_ADDR_16   (1 << 7)
+
+#define IOIO_DATA_32   (1 << 6)
+#define IOIO_DATA_16   (1 << 5)
+#define IOIO_DATA_8    (1 << 4)
+
+#define IOIO_SEG_ES    (0 << 10)
+#define IOIO_SEG_DS    (3 << 10)
+
+STATIC
+UINT64
+IoioExitInfo (
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINT64  ExitInfo = 0;
+
+  switch (*(InstructionData->OpCodes)) {
+  case 0xE4: /* IN AL, imm8 */
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
+    break;
+  case 0xE5: /* IN AX, imm8 / IN EAX, imm8 */
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
+    break;
+
+  case 0xEC: /* IN AL, DX */
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+  case 0xED: /* IN AX, DX / IN EAX, DX */
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  case 0xE6: /* OUT imm8, AL */
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
+    break;
+  case 0xE7: /* OUT imm8, AX / OUT imm8, EAX */
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
+    break;
+
+  case 0xEE: /* OUT DX, AL */
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+  case 0xEF: /* OUT DX, AX / OUT DX, EAX */
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  default:
+    return 0;
+  }
+
+  switch (InstructionData->AddrSize) {
+  case Size16Bits:
+    ExitInfo |= IOIO_ADDR_16;
+    break;
+
+  case Size32Bits:
+    ExitInfo |= IOIO_ADDR_32;
+    break;
+
+  case Size64Bits:
+    ExitInfo |= IOIO_ADDR_64;
+    break;
+
+  default:
+    break;
+  }
+
+  if (InstructionData->RepMode) {
+    ExitInfo |= IOIO_REP;
+  }
+
+  return ExitInfo;
+}
+
+STATIC
+UINTN
+IoioExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINT64  ExitInfo1;
+  UINTN   Status;
+
+  ExitInfo1 = IoioExitInfo (Regs, InstructionData);
+  if (!ExitInfo1) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+    ASSERT (0);
+  }
+
+  if (!(ExitInfo1 & IOIO_TYPE_IN)) {
+    Ghcb->SaveArea.Rax = Regs->Rax;
+    GhcbSetRegValid (Ghcb, GhcbRax);
+  }
+
+  //FIXME: This is likely needed for the merging cases (size<32 bits)
+  //       Pass in zero and perform merge here (only for non-string)
+  Ghcb->SaveArea.Rax = Regs->Rax;
+  GhcbSetRegValid (Ghcb, GhcbRax);
+
+  Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (ExitInfo1 & IOIO_TYPE_IN) {
+    if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+      VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+      ASSERT (0);
+    }
+    Regs->Rax = Ghcb->SaveArea.Rax;
+  }
+
+  return 0;
+}
+
 UINTN
 DoVcCommon (
   GHCB                *Ghcb,
   EFI_SYSTEM_CONTEXT  Context
   )
 {
-  EFI_SYSTEM_CONTEXT_X64  *Regs = Context.SystemContextX64;
-  UINTN                   ExitCode;
-  UINTN                   Status;
+  EFI_SYSTEM_CONTEXT_X64   *Regs = Context.SystemContextX64;
+  SEV_ES_INSTRUCTION_DATA  InstructionData;
+  NAE_EXIT                 NaeExit;
+  UINTN                    ExitCode;
+  UINTN                    Status;
 
   VmgInit (Ghcb);
 
   ExitCode = Regs->ExceptionData;
   switch (ExitCode) {
+  case SvmExitIoioProt:
+    NaeExit = IoioExit;
+    break;
+
   default:
-    Status = VmgExit (Ghcb, SvmExitUnsupported, ExitCode, 0);
+    NaeExit = UnsupportedExit;
+  }
+
+  InitInstructionData (&InstructionData, Ghcb, Regs);
+
+  Status = NaeExit (Ghcb, Regs, &InstructionData);
+  if (!Status) {
+    Regs->Rip += InstructionLength(&InstructionData);
   }
 
   VmgDone (Ghcb);
 
-  return Status;
+  return 0;
 }
-- 
2.17.1


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

* [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (10 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Add support to the #VC exception handler to handle string IO. This
requires expanding the IO instruction parsing to recognize string based
IO instructions as well as preparing an un-encrypted buffer to be used
to transfer (either to or from the guest) the string contents for the IO
operation. The SW_EXITINFO2 and SW_SCRATCH fields of the GHCB are set
appropriately for the operation. Multiple VMGEXIT invocations may be
needed to complete the string IO operation.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 92 ++++++++++++++++---
 1 file changed, 80 insertions(+), 12 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 3b69aca48055..2bc156840e74 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -278,6 +278,34 @@ IoioExitInfo (
   UINT64  ExitInfo = 0;
 
   switch (*(InstructionData->OpCodes)) {
+  case 0x6C: /* INSB / INS mem8, DX */
+    ExitInfo |= IOIO_TYPE_INS;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= IOIO_SEG_ES;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+  case 0x6D: /* INSW / INS mem16, DX / INSD / INS mem32, DX */
+    ExitInfo |= IOIO_TYPE_INS;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= IOIO_SEG_ES;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  case 0x6E: /* OUTSB / OUTS DX, mem8 */
+    ExitInfo |= IOIO_TYPE_OUTS;
+    ExitInfo |= IOIO_DATA_8;
+    ExitInfo |= IOIO_SEG_DS;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+  case 0x6F: /* OUTSW / OUTS DX, mem16 / OUTSD / OUTS DX, mem32 */
+    ExitInfo |= IOIO_TYPE_OUTS;
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+    ExitInfo |= IOIO_SEG_DS;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
   case 0xE4: /* IN AL, imm8 */
     InstructionData->ImmediateSize = 1;
     InstructionData->End++;
@@ -370,8 +398,9 @@ IoioExit (
   SEV_ES_INSTRUCTION_DATA  *InstructionData
   )
 {
-  UINT64  ExitInfo1;
-  UINTN   Status;
+  UINT64   ExitInfo1, ExitInfo2;
+  UINTN    Status;
+  BOOLEAN  String;
 
   ExitInfo1 = IoioExitInfo (Regs, InstructionData);
   if (!ExitInfo1) {
@@ -389,17 +418,56 @@ IoioExit (
   Ghcb->SaveArea.Rax = Regs->Rax;
   GhcbSetRegValid (Ghcb, GhcbRax);
 
-  Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
-  if (Status) {
-    return Status;
-  }
-
-  if (ExitInfo1 & IOIO_TYPE_IN) {
-    if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
-      VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
-      ASSERT (0);
+  String = (ExitInfo1 & IOIO_TYPE_STR) ? TRUE : FALSE;
+  if (String) {
+    UINTN  IoBytes, VmgExitBytes;
+    UINTN  GhcbCount, OpCount;
+
+    Status = 0;
+
+    IoBytes = (ExitInfo1 >> 4) & 0x7;
+    GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
+
+    OpCount = (ExitInfo1 & IOIO_REP) ? Regs->Rcx : 1;
+    while (OpCount) {
+      ExitInfo2 = MIN (OpCount, GhcbCount);
+      VmgExitBytes = ExitInfo2 * IoBytes;
+
+      if (!(ExitInfo1 & IOIO_TYPE_IN)) {
+        CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);
+        Regs->Rsi += VmgExitBytes;
+      }
+
+      Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+      Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, ExitInfo2);
+      if (Status) {
+        return Status;
+      }
+
+      if (ExitInfo1 & IOIO_TYPE_IN) {
+        CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
+        Regs->Rdi += VmgExitBytes;
+      }
+
+      if (ExitInfo1 & IOIO_REP) {
+        Regs->Rcx -= ExitInfo2;
+      }
+
+      OpCount -= ExitInfo2;
+    }
+  } else {
+    Status = VmgExit (Ghcb, SvmExitIoioProt, ExitInfo1, 0);
+    if (Status) {
+      return Status;
+    }
+
+    if (ExitInfo1 & IOIO_TYPE_IN) {
+      if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+        VmgExit (Ghcb, SvmExitUnsupported, SvmExitIoioProt, 0);
+        ASSERT (0);
+      }
+      Regs->Rax = Ghcb->SaveArea.Rax;
     }
-    Regs->Rax = Ghcb->SaveArea.Rax;
   }
 
   return 0;
-- 
2.17.1


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

* [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (11 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a CPUID intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Add support to construct the required GHCB values to support a CPUID NAE
event. Additionally, CPUID 0x0000_000d requires XCR0 to be supplied in
the GHCB, so add support to issue the XGETBV instruction.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Library/BaseLib/BaseLib.inf            |  1 +
 MdePkg/Include/Library/BaseLib.h              | 16 +++++++
 MdePkg/Library/BaseLib/X64/GccInline.c        | 28 ++++++++++++
 .../X64/AMDSevVcCommon.c                      | 45 +++++++++++++++++++
 MdePkg/Library/BaseLib/X64/XGetBv.nasm        | 39 ++++++++++++++++
 5 files changed, 129 insertions(+)
 create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm

diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index a41401340f95..7c1c077c63a9 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -287,6 +287,7 @@ [Sources.X64]
   X64/ReadCr0.nasm| MSFT
   X64/ReadEflags.nasm| MSFT
   X64/VmgExit.nasm | MSFT
+  X64/XGetBv.nasm | MSFT
 
 
   X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 80bd5cf57a72..ae16fa6f1c52 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7893,6 +7893,22 @@ AsmVmgExit (
   VOID
   );
 
+/**
+  Executes a XGETBV instruction
+
+  Executes a XGETBV instruction. This function is only available on IA-32 and
+  x64.
+
+  @param[in] Index        Extended control register index
+
+  @retval                 The current value of the extended control register
+**/
+UINT64
+EFIAPI
+AsmXGetBv (
+  IN UINT32 Index
+  );
+
 
 /**
   Patch the immediate operand of an IA32 or X64 instruction such that the byte,
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 17539caa0798..46aa96d67ab9 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1814,4 +1814,32 @@ AsmVmgExit (
   __asm__ __volatile__ ("rep; vmmcall":::"memory");
 }
 
+/**
+  Executes a XGETBV instruction
+
+  Executes a XGETBV instruction. This function is only available on IA-32 and
+  x64.
+
+  @param[in] Index        Extended control register index
+
+  @retval                 The current value of the extended control register
+**/
+UINT64
+EFIAPI
+AsmXGetBv (
+  IN UINT32 Index
+  )
+{
+  UINT32 LowData;
+  UINT32 HighData;
+
+  __asm__ __volatile__ (
+    "xgetbv"
+    : "=a" (LowData),   // %0
+      "=d" (HighData)   // %1
+    : "c"  (Index)      // %2
+    );
+
+  return (((UINT64)HighData) << 32) | LowData;
+}
 
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 2bc156840e74..66cd0f9eb196 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -3,6 +3,8 @@
 #include <Library/DebugLib.h>
 #include "AMDSevVcCommon.h"
 
+#define CR4_OSXSAVE (1 << 18)
+
 typedef enum {
   LongMode64Bit        = 0,
   LongModeCompat32Bit,
@@ -473,6 +475,45 @@ IoioExit (
   return 0;
 }
 
+STATIC
+UINTN
+CpuidExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN  Status;
+
+  Ghcb->SaveArea.Rax = Regs->Rax;
+  GhcbSetRegValid (Ghcb, GhcbRax);
+  Ghcb->SaveArea.Rcx = Regs->Rcx;
+  GhcbSetRegValid (Ghcb, GhcbRcx);
+  if (Regs->Rax == 0x0000000d) {
+    Ghcb->SaveArea.XCr0 = (AsmReadCr4 () & CR4_OSXSAVE) ? AsmXGetBv (0) : 1;
+    GhcbSetRegValid (Ghcb, GhcbXCr0);
+  }
+
+  Status = VmgExit (Ghcb, SvmExitCpuid, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+      !GhcbIsRegValid (Ghcb, GhcbRbx) ||
+      !GhcbIsRegValid (Ghcb, GhcbRcx) ||
+      !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitCpuid, 0);
+    ASSERT (0);
+  }
+  Regs->Rax = Ghcb->SaveArea.Rax;
+  Regs->Rbx = Ghcb->SaveArea.Rbx;
+  Regs->Rcx = Ghcb->SaveArea.Rcx;
+  Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+  return 0;
+}
+
 UINTN
 DoVcCommon (
   GHCB                *Ghcb,
@@ -489,6 +530,10 @@ DoVcCommon (
 
   ExitCode = Regs->ExceptionData;
   switch (ExitCode) {
+  case SvmExitCpuid:
+    NaeExit = CpuidExit;
+    break;
+
   case SvmExitIoioProt:
     NaeExit = IoioExit;
     break;
diff --git a/MdePkg/Library/BaseLib/X64/XGetBv.nasm b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
new file mode 100644
index 000000000000..83c10b40e369
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
@@ -0,0 +1,39 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution.  The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+;   XGetBv.Asm
+;
+; Abstract:
+;
+;   AsmXgetBv function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    DEFAULT REL
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmXGetBv (
+;   IN UINT32 Index
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmXGetBv)
+ASM_PFX(AsmXGetBv):
+    xgetbv
+    shl     rdx, 0x20
+    or      rax, rdx
+    ret
-- 
2.17.1


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

* [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (12 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a MSR_PROT intercept generates a #VC exception. VMGEXIT must
be used to allow the hypervisor to handle this intercept.

Add support to construct the required GHCB values to support an MSR_PROT
NAE event. Parse the instruction that generated the #VC exception to
determine whether it is RDMSR or WRMSR, setting the required register
register values in the GHCB and creating the proper SW_EXIT_INFO1 value in
the GHCB.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 66cd0f9eb196..2b25919ea496 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -251,6 +251,54 @@ UnsupportedExit (
   return Status;
 }
 
+STATIC
+UINTN
+MsrExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINT64  ExitInfo1;
+  UINTN   Status;
+
+  ExitInfo1 = 0;
+
+  switch (*(InstructionData->OpCodes + 1)) {
+  case 0x30: // WRMSR
+    ExitInfo1 = 1;
+    Ghcb->SaveArea.Rax = Regs->Rax;
+    GhcbSetRegValid (Ghcb, GhcbRax);
+    Ghcb->SaveArea.Rdx = Regs->Rdx;
+    GhcbSetRegValid (Ghcb, GhcbRdx);
+    /* Fallthrough */
+  case 0x32: // RDMSR
+    Ghcb->SaveArea.Rcx = Regs->Rcx;
+    GhcbSetRegValid (Ghcb, GhcbRcx);
+    break;
+  default:
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitMsr, 0);
+    ASSERT (0);
+  }
+
+  Status = VmgExit (Ghcb, SvmExitMsr, ExitInfo1, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!ExitInfo1) {
+    if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+        !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+      VmgExit (Ghcb, SvmExitUnsupported, SvmExitMsr, 0);
+      ASSERT (0);
+    }
+    Regs->Rax = Ghcb->SaveArea.Rax;
+    Regs->Rdx = Ghcb->SaveArea.Rdx;
+  }
+
+  return 0;
+}
+
 #define IOIO_TYPE_STR  (1 << 2)
 #define IOIO_TYPE_IN   1
 #define IOIO_TYPE_INS  (IOIO_TYPE_IN | IOIO_TYPE_STR)
@@ -538,6 +586,10 @@ DoVcCommon (
     NaeExit = IoioExit;
     break;
 
+  case SvmExitMsr:
+    NaeExit = MsrExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (13 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a NPF intercept for an NPT entry with a reserved bit set
generates a #VC exception. This condition is assumed to be an MMIO access.
VMGEXIT must be used to allow the hypervisor to handle this intercept.

Add support to construct the required GHCB values to support a NPF NAE
event for MMIO.  Parse the instruction that generated the #VC exception,
setting the required register values in the GHCB and creating the proper
SW_EXIT_INFO1, SW_EXITINFO2 and SW_SCRATCH values in the GHCB.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 285 +++++++++++++++++-
 1 file changed, 283 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 2b25919ea496..5b2df92acf72 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -78,8 +78,8 @@ typedef struct {
     UINT8  Scale;
   } Sib;
 
-  UINTN  RegData;
-  UINTN  RmData;
+  INTN  RegData;
+  INTN  RmData;
 } SEV_ES_INSTRUCTION_OPCODE_EXT;
 
 typedef struct {
@@ -124,6 +124,198 @@ UINTN
   SEV_ES_INSTRUCTION_DATA  *InstructionData
   );
 
+STATIC
+INT64 *
+GetRegisterPointer (
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  UINT8                    Register
+  )
+{
+  UINT64 *Reg;
+
+  switch (Register) {
+  case 0:
+    Reg = &Regs->Rax;
+    break;
+  case 1:
+    Reg = &Regs->Rcx;
+    break;
+  case 2:
+    Reg = &Regs->Rdx;
+    break;
+  case 3:
+    Reg = &Regs->Rbx;
+    break;
+  case 4:
+    Reg = &Regs->Rsp;
+    break;
+  case 5:
+    Reg = &Regs->Rbp;
+    break;
+  case 6:
+    Reg = &Regs->Rsi;
+    break;
+  case 7:
+    Reg = &Regs->Rdi;
+    break;
+  case 8:
+    Reg = &Regs->R8;
+    break;
+  case 9:
+    Reg = &Regs->R9;
+    break;
+  case 10:
+    Reg = &Regs->R10;
+    break;
+  case 11:
+    Reg = &Regs->R11;
+    break;
+  case 12:
+    Reg = &Regs->R12;
+    break;
+  case 13:
+    Reg = &Regs->R13;
+    break;
+  case 14:
+    Reg = &Regs->R14;
+    break;
+  case 15:
+    Reg = &Regs->R15;
+    break;
+  default:
+    Reg = NULL;
+  }
+  ASSERT (Reg);
+
+  return (INT64 *) Reg;
+}
+
+STATIC
+VOID
+UpdateForDisplacement (
+  SEV_ES_INSTRUCTION_DATA  *InstructionData,
+  UINTN                    Size
+  )
+{
+  InstructionData->DisplacementSize = Size;
+  InstructionData->Immediate += Size;
+  InstructionData->End += Size;
+}
+
+STATIC
+BOOLEAN
+IsRipRelative (
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext = &InstructionData->Ext;
+
+  return ((InstructionData == LongMode64Bit) &&
+          (Ext->ModRm.Mod == 0) &&
+          (Ext->ModRm.Rm == 5)  &&
+          (InstructionData->SibPresent == FALSE));
+}
+
+STATIC
+UINTN
+GetEffectiveMemoryAddress (
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext = &InstructionData->Ext;
+  INTN                           EffectiveAddress = 0;
+
+  if (IsRipRelative (InstructionData)) {
+    /* RIP-relative displacement is a 32-bit signed value */
+    INT32 RipRelative = *(INT32 *) InstructionData->Displacement;
+
+    UpdateForDisplacement (InstructionData, 4);
+    return (UINTN) ((INTN) Regs->Rip + RipRelative);
+  }
+
+  switch (Ext->ModRm.Mod) {
+  case 1:
+    UpdateForDisplacement (InstructionData, 1);
+    EffectiveAddress += (INT8) (*(INT8 *) (InstructionData->Displacement));
+    break;
+  case 2:
+    switch (InstructionData->AddrSize) {
+    case Size16Bits:
+      UpdateForDisplacement (InstructionData, 2);
+      EffectiveAddress += (INT16) (*(INT16 *) (InstructionData->Displacement));
+      break;
+    default:
+      UpdateForDisplacement (InstructionData, 4);
+      EffectiveAddress += (INT32) (*(INT32 *) (InstructionData->Displacement));
+      break;
+    }
+    break;
+  }
+
+  if (InstructionData->SibPresent) {
+    if (Ext->Sib.Index != 4) {
+      EffectiveAddress += (*GetRegisterPointer (Regs, Ext->Sib.Index) << Ext->Sib.Scale);
+    }
+
+    if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
+      EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
+    } else {
+      UpdateForDisplacement (InstructionData, 4);
+      EffectiveAddress += (INT32) (*(INT32 *) (InstructionData->Displacement));
+    }
+  } else {
+    EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
+  }
+
+  return (UINTN) EffectiveAddress;
+}
+
+STATIC
+VOID
+DecodeModRm (
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_REX_PREFIX  *RexPrefix = &InstructionData->RexPrefix;
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext = &InstructionData->Ext;
+  SEV_ES_INSTRUCTION_MODRM       *ModRm = &InstructionData->ModRm;
+  SEV_ES_INSTRUCTION_SIB         *Sib = &InstructionData->Sib;
+
+  InstructionData->ModRmPresent = TRUE;
+  ModRm->Uint8 = *(InstructionData->End);
+
+  InstructionData->Displacement++;
+  InstructionData->Immediate++;
+  InstructionData->End++;
+
+  Ext->ModRm.Mod = ModRm->Bits.Mod;
+  Ext->ModRm.Reg = (RexPrefix->Bits.R << 3) | ModRm->Bits.Reg;
+  Ext->ModRm.Rm  = (RexPrefix->Bits.B << 3) | ModRm->Bits.Rm;
+
+  Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
+
+  if (Ext->ModRm.Mod == 3) {
+    Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
+  } else {
+    if (ModRm->Bits.Rm == 4) {
+      InstructionData->SibPresent = TRUE;
+      Sib->Uint8 = *(InstructionData->End);
+
+      InstructionData->Displacement++;
+      InstructionData->Immediate++;
+      InstructionData->End++;
+
+      Ext->Sib.Scale = Sib->Bits.Scale;
+      Ext->Sib.Index = (RexPrefix->Bits.X << 3) | Sib->Bits.Index;
+      Ext->Sib.Base  = (RexPrefix->Bits.B << 3) | Sib->Bits.Base;
+    }
+
+    Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
+  }
+}
+
 STATIC
 VOID
 DecodePrefixes (
@@ -235,6 +427,91 @@ InitInstructionData (
   DecodePrefixes (Regs, InstructionData);
 }
 
+STATIC
+UINT64
+MmioExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINT64  ExitInfo1, ExitInfo2;
+  UINTN   Status;
+  UINTN   Bytes;
+  INTN    *Register;
+
+  Bytes = 0;
+
+  switch (*(InstructionData->OpCodes)) {
+  /* MMIO write */
+  case 0x88:
+    Bytes = 1;
+  case 0x89:
+    DecodeModRm (Regs, InstructionData);
+    Bytes = (Bytes) ? Bytes
+                    : (InstructionData->DataSize == Size16Bits) ? 2
+                    : (InstructionData->DataSize == Size32Bits) ? 4
+                    : (InstructionData->DataSize == Size64Bits) ? 8
+                    : 0;
+
+    if (InstructionData->Ext.ModRm.Mod == 3) {
+      /* NPF on two register operands??? */
+      VmgExit (Ghcb, SvmExitUnsupported, SvmExitNpf, 0);
+      ASSERT (0);
+    }
+
+    ExitInfo1 = InstructionData->Ext.RmData;
+    ExitInfo2 = Bytes;
+    CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
+
+    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+    Status = VmgExit (Ghcb, SvmExitMmioWrite, ExitInfo1, ExitInfo2);
+    if (Status) {
+      return Status;
+    }
+    break;
+
+  /* MMIO read */
+  case 0x8A:
+    Bytes = 1;
+  case 0x8B:
+    DecodeModRm (Regs, InstructionData);
+    Bytes = (Bytes) ? Bytes
+                    : (InstructionData->DataSize == Size16Bits) ? 2
+                    : (InstructionData->DataSize == Size32Bits) ? 4
+                    : (InstructionData->DataSize == Size64Bits) ? 8
+                    : 0;
+    if (InstructionData->Ext.ModRm.Mod == 3) {
+      /* NPF on two register operands??? */
+      VmgExit (Ghcb, SvmExitUnsupported, SvmExitNpf, 0);
+      ASSERT (0);
+    }
+
+    ExitInfo1 = InstructionData->Ext.RmData;
+    ExitInfo2 = Bytes;
+
+    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+    Status = VmgExit (Ghcb, SvmExitMmioRead, ExitInfo1, ExitInfo2);
+    if (Status) {
+      return Status;
+    }
+
+    Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
+    if (Bytes == 4) {
+      /* Zero-extend for 32-bit operation */
+      *Register = 0;
+    }
+    CopyMem (Register, Ghcb->SharedBuffer, Bytes);
+    break;
+
+  default:
+    Status = GP_EXCEPTION;
+    ASSERT (0);
+  }
+
+  return Status;
+}
+
 STATIC
 UINTN
 UnsupportedExit (
@@ -590,6 +867,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitNpf:
+    NaeExit = MmioExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (14 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a WBINVD intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 5b2df92acf72..78d9b315c446 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,24 @@ UnsupportedExit (
   return Status;
 }
 
+STATIC
+UINTN
+WbinvdExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN   Status;
+
+  Status = VmgExit (Ghcb, SvmExitWbinvd, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  return 0;
+}
+
 STATIC
 UINTN
 MsrExit (
@@ -867,6 +885,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitWbinvd:
+    NaeExit = WbinvdExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (15 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a RDTSC intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 78d9b315c446..198b979bbb01 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -857,6 +857,32 @@ CpuidExit (
   return 0;
 }
 
+STATIC
+UINTN
+RdtscExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN  Status;
+
+  Status = VmgExit (Ghcb, SvmExitRdtsc, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+      !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdtsc, 0);
+    ASSERT (0);
+  }
+  Regs->Rax = Ghcb->SaveArea.Rax;
+  Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+  return 0;
+}
+
 UINTN
 DoVcCommon (
   GHCB                *Ghcb,
@@ -873,6 +899,10 @@ DoVcCommon (
 
   ExitCode = Regs->ExceptionData;
   switch (ExitCode) {
+  case SvmExitRdtsc:
+    NaeExit = RdtscExit;
+    break;
+
   case SvmExitCpuid:
     NaeExit = CpuidExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (16 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a RDPMC intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 198b979bbb01..6c3e7f67f6cb 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -857,6 +857,35 @@ CpuidExit (
   return 0;
 }
 
+STATIC
+UINTN
+RdpmcExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN  Status;
+
+  Ghcb->SaveArea.Rcx = Regs->Rcx;
+  GhcbSetRegValid (Ghcb, GhcbRcx);
+
+  Status = VmgExit (Ghcb, SvmExitRdpmc, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+      !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdpmc, 0);
+    ASSERT (0);
+  }
+  Regs->Rax = Ghcb->SaveArea.Rax;
+  Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+  return 0;
+}
+
 STATIC
 UINTN
 RdtscExit (
@@ -903,6 +932,10 @@ DoVcCommon (
     NaeExit = RdtscExit;
     break;
 
+  case SvmExitRdpmc:
+    NaeExit = RdpmcExit;
+    break;
+
   case SvmExitCpuid:
     NaeExit = CpuidExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (17 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a INVD intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 6c3e7f67f6cb..3f10af401aa0 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -818,6 +818,24 @@ IoioExit (
   return 0;
 }
 
+STATIC
+UINTN
+InvdExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN   Status;
+
+  Status = VmgExit (Ghcb, SvmExitInvd, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  return 0;
+}
+
 STATIC
 UINTN
 CpuidExit (
@@ -940,6 +958,10 @@ DoVcCommon (
     NaeExit = CpuidExit;
     break;
 
+  case SvmExitInvd:
+    NaeExit = InvdExit;
+    break;
+
   case SvmExitIoioProt:
     NaeExit = IoioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (18 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a VMMCALL intercept generates a #VC exception. VMGEXIT must
be used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 3f10af401aa0..1a0a8f5cd718 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -546,6 +546,37 @@ WbinvdExit (
   return 0;
 }
 
+STATIC
+UINTN
+VmmCallExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN   Status;
+
+  DecodeModRm (Regs, InstructionData);
+
+  Ghcb->SaveArea.Rax = Regs->Rax;
+  GhcbSetRegValid (Ghcb, GhcbRax);
+  Ghcb->SaveArea.Cpl = (UINT8) (Regs->Cs & 0x3);
+  GhcbSetRegValid (Ghcb, GhcbCpl);
+
+  Status = VmgExit (Ghcb, SvmExitVmmCall, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitVmmCall, 0);
+    ASSERT (0);
+  }
+  Regs->Rax = Ghcb->SaveArea.Rax;
+
+  return 0;
+}
+
 STATIC
 UINTN
 MsrExit (
@@ -970,6 +1001,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitVmmCall:
+    NaeExit = VmmCallExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (19 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a RDTSCP intercept generates a #VC exception. VMGEXIT must be
used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 1a0a8f5cd718..8f9b742f942c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -546,6 +546,36 @@ WbinvdExit (
   return 0;
 }
 
+STATIC
+UINTN
+RdtscpExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN  Status;
+
+  DecodeModRm (Regs, InstructionData);
+
+  Status = VmgExit (Ghcb, SvmExitRdtscp, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
+      !GhcbIsRegValid (Ghcb, GhcbRcx) ||
+      !GhcbIsRegValid (Ghcb, GhcbRdx)) {
+    VmgExit (Ghcb, SvmExitUnsupported, SvmExitRdtscp, 0);
+    ASSERT (0);
+  }
+  Regs->Rax = Ghcb->SaveArea.Rax;
+  Regs->Rcx = Ghcb->SaveArea.Rcx;
+  Regs->Rdx = Ghcb->SaveArea.Rdx;
+
+  return 0;
+}
+
 STATIC
 UINTN
 VmmCallExit (
@@ -1005,6 +1035,10 @@ DoVcCommon (
     NaeExit = VmmCallExit;
     break;
 
+  case SvmExitRdtscp:
+    NaeExit = RdtscpExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (20 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a MONITOR/MONITORX intercept generates a #VC exception.
VMGEXIT must be used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 8f9b742f942c..154ca091936d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,33 @@ UnsupportedExit (
   return Status;
 }
 
+STATIC
+UINTN
+MonitorExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN   Status;
+
+  DecodeModRm (Regs, InstructionData);
+
+  Ghcb->SaveArea.Rax = Regs->Rax;  // Identity mapped, so VA = PA
+  GhcbSetRegValid (Ghcb, GhcbRax);
+  Ghcb->SaveArea.Rcx = Regs->Rcx;
+  GhcbSetRegValid (Ghcb, GhcbRcx);
+  Ghcb->SaveArea.Rdx = Regs->Rdx;
+  GhcbSetRegValid (Ghcb, GhcbRdx);
+
+  Status = VmgExit (Ghcb, SvmExitMonitor, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  return 0;
+}
+
 STATIC
 UINTN
 WbinvdExit (
@@ -1043,6 +1070,10 @@ DoVcCommon (
     NaeExit = WbinvdExit;
     break;
 
+  case SvmExitMonitor:
+    NaeExit = MonitorExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (21 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a MWAIT/MWAITX intercept generates a #VC exception.
VMGEXIT must be used to allow the hypervisor to handle this intercept.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 154ca091936d..43a3a116af5d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -528,6 +528,31 @@ UnsupportedExit (
   return Status;
 }
 
+STATIC
+UINTN
+MwaitExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  UINTN   Status;
+
+  DecodeModRm (Regs, InstructionData);
+
+  Ghcb->SaveArea.Rax = Regs->Rax;
+  GhcbSetRegValid (Ghcb, GhcbRax);
+  Ghcb->SaveArea.Rcx = Regs->Rcx;
+  GhcbSetRegValid (Ghcb, GhcbRcx);
+
+  Status = VmgExit (Ghcb, SvmExitMwait, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  return 0;
+}
+
 STATIC
 UINTN
 MonitorExit (
@@ -1074,6 +1099,10 @@ DoVcCommon (
     NaeExit = MonitorExit;
     break;
 
+  case SvmExitMwait:
+    NaeExit = MwaitExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (22 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Under SEV-ES, a DR7 read or write intercept generates a #VC exception.
The #VC handler must provide special support to the guest for this. On
a DR7 write, the #VC handler must cache the value and issue a VMGEXIT
to notify the hypervisor of the write. However, the #VC handler must
not actually set the value of the DR7 register. On a DR7 read, the #VC
handler must return the cached value of the DR7 register to the guest.
VMGEXIT is not invoked for a DR7 register read.

To avoid exception recursion, a #VC exception will not try to read and
push the actual debug registers into the EFI_SYSTEM_CONTEXT_X64 struct
and instead push zeroes. The #VC exception handler does not make use of
the debug registers from saved context.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 68 +++++++++++++++++++
 .../X64/ExceptionHandlerAsm.nasm              | 15 ++++
 2 files changed, 83 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 43a3a116af5d..8d7633b15e25 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -5,6 +5,12 @@
 
 #define CR4_OSXSAVE (1 << 18)
 
+#define DR7_RESET_VALUE 0x400
+typedef struct {
+  BOOLEAN  Dr7Cached;
+  UINT64   Dr7;
+} SEV_ES_PER_CPU_DATA;
+
 typedef enum {
   LongMode64Bit        = 0,
   LongModeCompat32Bit,
@@ -1043,6 +1049,60 @@ RdtscExit (
   return 0;
 }
 
+STATIC
+UINTN
+Dr7WriteExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext = &InstructionData->Ext;
+  SEV_ES_PER_CPU_DATA            *SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);
+  INTN                           *Register;
+  UINTN                          Status;
+
+  DecodeModRm (Regs, InstructionData);
+
+  /* MOV DRn always treats MOD == 3 no matter how encoded */
+  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
+
+  /* Using a value of 0 for ExitInfo1 means RAX holds the value */
+  Ghcb->SaveArea.Rax = *Register;
+  GhcbSetRegValid (Ghcb, GhcbRax);
+
+  Status = VmgExit (Ghcb, SvmExitDr7Write, 0, 0);
+  if (Status) {
+    return Status;
+  }
+
+  SevEsData->Dr7 = *Register;
+  SevEsData->Dr7Cached = TRUE;
+
+  return 0;
+}
+
+STATIC
+UINTN
+Dr7ReadExit (
+  GHCB                     *Ghcb,
+  EFI_SYSTEM_CONTEXT_X64   *Regs,
+  SEV_ES_INSTRUCTION_DATA  *InstructionData
+  )
+{
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext = &InstructionData->Ext;
+  SEV_ES_PER_CPU_DATA            *SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);
+  INTN                           *Register;
+
+  DecodeModRm (Regs, InstructionData);
+
+  /* MOV DRn always treats MOD == 3 no matter how encoded */
+  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
+  *Register = (SevEsData->Dr7Cached) ? SevEsData->Dr7 : DR7_RESET_VALUE;
+
+  return 0;
+}
+
 UINTN
 DoVcCommon (
   GHCB                *Ghcb,
@@ -1059,6 +1119,14 @@ DoVcCommon (
 
   ExitCode = Regs->ExceptionData;
   switch (ExitCode) {
+  case SvmExitDr7Read:
+    NaeExit = Dr7ReadExit;
+    break;
+
+  case SvmExitDr7Write:
+    NaeExit = Dr7WriteExit;
+    break;
+
   case SvmExitRdtsc:
     NaeExit = RdtscExit;
     break;
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
index 4db1a09f2881..d23af671df66 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
@@ -223,6 +223,9 @@ HasErrorCode:
     push    rax
 
 ;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+    cmp     qword [rbp + 8], 29
+    je      VcDebugRegs          ; For SEV-ES (#VC) Debug registers ignored
+
     mov     rax, dr7
     push    rax
     mov     rax, dr6
@@ -235,7 +238,19 @@ HasErrorCode:
     push    rax
     mov     rax, dr0
     push    rax
+    jmp     DrFinish
 
+VcDebugRegs:
+;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
+    xor     rax, rax
+    push    rax
+    push    rax
+    push    rax
+    push    rax
+    push    rax
+    push    rax
+
+DrFinish:
 ;; FX_SAVE_STATE_X64 FxSaveState;
     sub rsp, 512
     mov rdi, rsp
-- 
2.17.1


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

* [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (23 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

An SEV-ES guest will generate a #VC exception when it encounters a
non-automatic exit (NAE) event. It is expected that the #VC exception
handler will communicate with the hypervisor using the GHCB to handle
the NAE event.

Update the Pei and Dxe exception handling support to recognize the #VC
exception and call a common #VC handler.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../DxeCpuExceptionHandlerLib.inf                 |  2 ++
 .../PeiCpuExceptionHandlerLib.inf                 |  2 ++
 .../PeiDxeAMDSevVcHandler.c                       | 15 +++++++++++++--
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index 331ae7334c45..75fafd346add 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
   Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/AMDSevVcCommon.c
 
 [Sources.X64]
   X64/ExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/AMDSevVcCommon.c
 
 [Sources.common]
   CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index 89b5d496e56f..50124b598509 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -26,11 +26,13 @@ [Sources.Ia32]
   Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/AMDSevVcCommon.c
 
 [Sources.X64]
   X64/ExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/AMDSevVcCommon.c
 
 [Sources.common]
   CpuExceptionCommon.h
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
index 1e027b3f2964..d32de9efb09e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -1,11 +1,22 @@
 
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Amd/Msr.h>
 #include "CpuExceptionCommon.h"
 #include "AMDSevVcCommon.h"
 
 UINTN
-DoVcException(
+DoVcException (
   EFI_SYSTEM_CONTEXT  Context
   )
 {
-  return 0;
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+  GHCB                      *Ghcb;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  ASSERT(!Msr.Bits.GhcbNegotiateBit);
+
+  Ghcb = Msr.Ghcb;
+
+  return DoVcCommon (Ghcb, Context);
 }
-- 
2.17.1


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

* [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (24 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

When starting APs in an SMP configuration, the AP needs to know if it is
running as an SEV-ES guest in order to assign a GHCB page.

Add a field to the CPU_MP_DATA structure that will indicate if SEV-ES is
active. This new field is set during MP library initialization with the
PCD value PcdCpuSevEsActive. This flag can then be used to determine if
SEV-ES is active.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec                     | 3 +++
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          | 2 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 1 +
 5 files changed, 8 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 4d5a2593cf13..163146afb752 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -327,5 +327,8 @@ [PcdsDynamic, PcdsDynamicEx]
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
 
+  ## Contains the SEV-ES active setting
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0x0|UINT32|0x60000019
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 37b3f64e578a..1b7ac00ab361 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -67,5 +67,6 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 82b77b63ea87..bcdd2ca82612 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -59,6 +59,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive                      ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f89037c59e13..2f75b82e8401 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -256,6 +256,8 @@ struct _CPU_MP_DATA {
   // driver.
   //
   BOOLEAN                        WakeUpByInitSipiSipi;
+
+  UINT32                         SevEsActive;
 };
 
 extern EFI_GUID mCpuInitMpLibHobGuid;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 6f51bc4ebfb9..74cfc513ec93 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1639,6 +1639,7 @@ MpInitLibInitialize (
     CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;
   }
 
+  CpuMpData->SevEsActive      = PcdGet32 (PcdCpuSevEsActive);
   InitializeSpinLock(&CpuMpData->MpLock);
 
   //
-- 
2.17.1


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

* [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (25 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
  2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Typically, an AP is booted using the INIT-SIPI-SIPI sequence. This
sequence is intercepted by the hypervisor, which sets the AP's registers
to the values requested by the sequence. At that point, the hypervisor can
start the AP, which will then begin execution at the appropriate location.

Under SEV-ES, AP booting presents some challenges since the hypervisor is
not allowed to alter the AP's register state. In this situation, we have
to distinguish between the AP's first boot and AP's subsequent boots.

First boot:
 Once the AP's register state has been defined (which is before the guest
 is first booted) it cannot be altered. Should the hypervisor attempt to
 alter the register state, the change would be detected by the hardware
 and the VMRUN instruction would fail. Given this, the first boot for the
 AP is required to begin execution with this initial register state, which
 is typically the reset vector. This prevents the BSP from directing the
 AP startup location through the INIT-SIPI-SIPI sequence.

 To work around this, provide a four-byte field at offset 0xffffffd0 that
 can contain an IP / CS register combination, that if non-zero, causes
 the AP to perform a far jump to that location instead of a near jump to
 EarlyBspInitReal16. Before booting the AP for the first time, the BSP
 should set the IP / CS value for the AP based on the value that would be
 derived from the INIT-SIPI-SIPI sequence.

Subsequent boots:
 Again, the hypervisor cannot alter the AP register state, so a method is
 required to take the AP out of halt state and redirect it to the desired
 IP location. If it is determined that the AP is running in an SEV-ES
 guest, then instead of calling CpuSleep(), a VMGEXIT is issued with the
 AP Reset Hold exit code (0x80000004). The hypervisor will put the AP in
 a halt state, waiting for an INIT-SIPI-SIPI sequence. Once the sequence
 is recognized, the hypervisor will resume the AP. At this point the AP
 must transition from the current 64-bit long mode down to 16-bit real
 mode and begin executing at the derived location from the INIT-SIPI-SIPI
 sequence.

 Another change is around the area of obtaining the (x2)APIC ID during AP
 startup. During AP startup, the AP can't take a #VC exception before the
 AP has established a stack. However, the AP stack is set by using the
 (x2)APIC ID, which is obtained through CPUID instructions. A CPUID
 instruction will cause a #VC, so a different method must be used. The
 GHCB protocol supports a method to obtain CPUID information from the
 hypervisor through the GHCB MSR. This method does not require a stack,
 so it is used to obtain the necessary CPUID information to determine the
 (x2)APIC ID.

The OVMF SEV support is updated to set the SEV-ES active PCD entry
(PcdCpuSevEsActive) when the guest is an SEV-ES guest. Also, the OVMF
support is updated to create its own reset vector routine in order to
supply the far jump field required for an AP first boot.

A new 16-bit protected mode GDT entry is created in order to transition
from 64-bit long mode down to 16-bit real mode.

A new assembler routine is created that takes the AP from 64-bit long mode
to 16-bit real mode.  This is located under 1MB in memory and transitions
from 64-bit long mode to 32-bit compatibility mode to 16-bit protected
mode and finally 16-bit real mode.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 OvmfPkg/OvmfPkgX64.dsc                        |   2 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |   1 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +-
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   1 +
 UefiCpuPkg/CpuDxe/CpuGdt.h                    |   2 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  55 ++++
 .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |   2 +-
 OvmfPkg/PlatformPei/AmdSev.c                  |   3 +
 UefiCpuPkg/CpuDxe/CpuGdt.c                    |  10 +-
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  67 ++++-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 229 ++++++++++++++++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |  16 ++
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |   2 +-
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |  85 +++++++
 UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |   4 +-
 .../Library/MpInitLib/Ia32/MpFuncs.nasm       |  15 ++
 UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |   4 +-
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 239 ++++++++++++++++++
 .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |   9 +
 21 files changed, 728 insertions(+), 23 deletions(-)
 create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 5bbf87540ab9..566a631efbff 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -554,6 +554,7 @@ [PcdsDynamicDefault]
   # UefiCpuPkg PCDs related to initial AP bringup and general AP management.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
 
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 5015e92b6eea..776a0186498d 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -566,6 +566,7 @@ [PcdsDynamicDefault]
   # UefiCpuPkg PCDs related to initial AP bringup and general AP management.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
 
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index d6fc7cdf7da8..5e8e6e76d63d 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -300,6 +300,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
@@ -565,6 +566,7 @@ [PcdsDynamicDefault]
   # UefiCpuPkg PCDs related to initial AP bringup and general AP management.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive|0
 
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index f53195e6dda5..76599d9e5649 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -104,6 +104,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 1b7ac00ab361..e6c0b1c5f3b9 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -13,7 +13,7 @@ [Defines]
   FILE_GUID                      = B88F7146-9834-4c55-BFAC-481CC0C33736
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.1
-  LIBRARY_CLASS                  = MpInitLib|DXE_DRIVER
+  LIBRARY_CLASS                  = MpInitLib|DXE_CORE DXE_DRIVER
 
 #
 # The following information is for reference only and not required by the build tools.
@@ -68,5 +68,6 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive                      ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index bcdd2ca82612..d57110c93fdf 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -60,6 +60,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSevEsActive                      ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.h b/UefiCpuPkg/CpuDxe/CpuGdt.h
index e5c36f37b96a..b8798cdb1fd4 100644
--- a/UefiCpuPkg/CpuDxe/CpuGdt.h
+++ b/UefiCpuPkg/CpuDxe/CpuGdt.h
@@ -36,7 +36,7 @@ struct _GDT_ENTRIES {
   GDT_ENTRY LinearCode;
   GDT_ENTRY SysData;
   GDT_ENTRY SysCode;
-  GDT_ENTRY Spare4;
+  GDT_ENTRY SysCode16;
   GDT_ENTRY LinearData64;
   GDT_ENTRY LinearCode64;
   GDT_ENTRY Spare5;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 2f75b82e8401..f2ba1a508715 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -151,6 +151,11 @@ typedef struct {
   UINT8             *RelocateApLoopFuncAddress;
   UINTN             RelocateApLoopFuncSize;
   UINTN             ModeTransitionOffset;
+  UINTN             SwitchToRealSize;
+  UINTN             SwitchToRealOffset;
+  UINTN             SwitchToRealNoNxOffset;
+  UINTN             SwitchToRealPM16ModeOffset;
+  UINTN             SwitchToRealPM16ModeSize;
 } MP_ASSEMBLY_ADDRESS_MAP;
 
 typedef struct _CPU_MP_DATA  CPU_MP_DATA;
@@ -185,6 +190,8 @@ typedef struct {
   UINT16                ModeTransitionSegment;
   UINT32                ModeHighMemory;
   UINT16                ModeHighSegment;
+  UINT32                SevEsActive;
+  UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
 #pragma pack()
@@ -232,6 +239,7 @@ struct _CPU_MP_DATA {
   UINT8                          ApLoopMode;
   UINT8                          ApTargetCState;
   UINT16                         PmCodeSegment;
+  UINT16                         Pm16CodeSegment;
   CPU_AP_DATA                    *CpuData;
   volatile MP_CPU_EXCHANGE_INFO  *MpCpuExchangeInfo;
 
@@ -258,8 +266,45 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   UINT32                         SevEsActive;
+  UINTN                          SevEsAPBuffer;
+  UINTN                          SevEsAPResetStackStart;
+  CPU_MP_DATA                    *NewCpuMpData;
+
+  UINT64                         GhcbBase;
 };
 
+#define AP_RESET_STACK_SIZE 64
+
+typedef union {
+  struct {
+    UINT16  Rip;
+    UINT16  Segment;
+  } ApStart;
+  UINT32    Uint32;
+} SEV_ES_AP_JMP_FAR;
+
+/**
+  Assembly code to move an AP from long mode to real mode.
+
+  Move an AP from long mode to real mode in preparation to invoking
+  the reset vector.  This is used for SEV-ES guests where a hypervisor
+  is not allowed to set the CS and RIP to point to the reset vector.
+
+  @param[in]  BufferStart  The reset vector target.
+  @param[in]  Code16       16-bit protected mode code segment value.
+  @param[in]  Code32       32-bit protected mode code segment value.
+  @param[in]  StackStart   The start of a stack to be used for transitioning
+                           from long mode to real mode.
+**/
+typedef
+VOID
+(EFIAPI AP_RESET) (
+  IN UINTN    BufferStart,
+  IN UINT16   Code16,
+  IN UINT16   Code32,
+  IN UINTN    StackStart
+  );
+
 extern EFI_GUID mCpuInitMpLibHobGuid;
 
 /**
@@ -365,6 +410,16 @@ GetModeTransitionBuffer (
   IN UINTN                BufferSize
   );
 
+/**
+  Get ...
+
+  @retval other   Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+  VOID
+  );
+
 /**
   This function will be called by BSP to wakeup AP.
 
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index 630a3503f6ba..b9af22bede61 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -33,7 +33,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries[] = {
 /* 0x10 */  {{0xffff, 0,  0,  0xf,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //linear code segment descriptor
 /* 0x18 */  {{0xffff, 0,  0,  0x3,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system data segment descriptor
 /* 0x20 */  {{0xffff, 0,  0,  0xa,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system code segment descriptor
-/* 0x28 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, //spare segment descriptor
+/* 0x28 */  {{0xffff, 0,  0,  0xa,  1,  0,  1,  0xf,  0,  0, 0,  1,  0}}, //system code16 segment descriptor
 /* 0x30 */  {{0xffff, 0,  0,  0x2,  1,  0,  1,  0xf,  0,  0, 1,  1,  0}}, //system data segment descriptor
 /* 0x38 */  {{0xffff, 0,  0,  0xa,  1,  0,  1,  0xf,  0,  1, 0,  1,  0}}, //system code segment descriptor
 /* 0x40 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, //spare segment descriptor
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 5f4983fd36d8..fc396a6f229d 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -74,6 +74,8 @@ AmdSevEsInitialize (
   ASSERT_RETURN_ERROR (PcdStatus);
   PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
   ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet32S (PcdCpuSevEsActive, 1);
+  ASSERT_RETURN_ERROR (PcdStatus);
 
   DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
 
@@ -92,6 +94,7 @@ AmdSevEsInitialize (
   CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
   Gdtr.Base = (UINTN) Gdt;
   AsmWriteGdtr (&Gdtr);
+
 }
 
 /**
diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.c b/UefiCpuPkg/CpuDxe/CpuGdt.c
index 87fd6955f24b..b2fdb87a285e 100644
--- a/UefiCpuPkg/CpuDxe/CpuGdt.c
+++ b/UefiCpuPkg/CpuDxe/CpuGdt.c
@@ -70,15 +70,15 @@ STATIC GDT_ENTRIES GdtTemplate = {
     0x0,
   },
   //
-  // SPARE4_SEL
+  // SYS_CODE16_SEL
   //
   {
-    0x0,            // limit 15:0
+    0x0FFFF,        // limit 15:0
     0x0,            // base 15:0
     0x0,            // base 23:16
-    0x0,            // type
-    0x0,            // limit 19:16, flags
-    0x0,            // base 31:24
+    0x09A,          // present, ring 0, code, execute/read
+    0x08F,          // page-granular, 16-bit
+    0x0,
   },
   //
   // LINEAR_DATA64_SEL
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 6be1bae464fb..127f64eb87e1 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -12,6 +12,8 @@
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/DebugAgentLib.h>
 #include <Library/DxeServicesTableLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
 
 #include <Protocol/Timer.h>
 
@@ -145,6 +147,36 @@ GetModeTransitionBuffer (
   return (UINTN)StartAddress;
 }
 
+/**
+  Get ...
+
+  @retval other   Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+  VOID
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  StartAddress;
+
+  //
+  // Allocate 1 page for AP jump table page
+  //
+  StartAddress = BASE_4GB - 1;
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiReservedMemoryType,
+                  1,
+                  &StartAddress
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));
+
+  return (UINTN) StartAddress;
+}
+
 /**
   Checks APs status and updates APs status if needed.
 
@@ -219,6 +251,38 @@ CheckApsStatus (
   }
 }
 
+/**
+  Get Protected mode code segment with 16-bit default addressing
+  from current GDT table.
+
+  @return  Protected mode 16-bit code segment value.
+**/
+UINT16
+GetProtectedMode16CS (
+  VOID
+  )
+{
+  IA32_DESCRIPTOR          GdtrDesc;
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;
+  UINTN                    GdtEntryCount;
+  UINT16                   Index;
+
+  Index = (UINT16) -1;
+  AsmReadGdtr (&GdtrDesc);
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+  GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+  for (Index = 0; Index < GdtEntryCount; Index++) {
+    if (GdtEntry->Bits.L == 0) {
+      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 0) {
+        break;
+      }
+    }
+    GdtEntry++;
+  }
+  ASSERT (Index != GdtEntryCount);
+  return Index * 8;
+}
+
 /**
   Get Protected mode code segment from current GDT table.
 
@@ -239,7 +303,7 @@ GetProtectedModeCS (
   GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
   for (Index = 0; Index < GdtEntryCount; Index++) {
     if (GdtEntry->Bits.L == 0) {
-      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
+      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {
         break;
       }
     }
@@ -301,6 +365,7 @@ MpInitChangeApLoopCallback (
 
   CpuMpData = GetCpuMpData ();
   CpuMpData->PmCodeSegment = GetProtectedModeCS ();
+  CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
   CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
   mNumberToFinish = CpuMpData->CpuCount - 1;
   WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 74cfc513ec93..0939019d7b8c 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -7,6 +7,8 @@
 **/
 
 #include "MpLib.h"
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
 
 EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
 
@@ -555,6 +557,108 @@ InitializeApData (
   SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
 }
 
+/**
+  Get Protected mode code segment with 16-bit default addressing
+  from current GDT table.
+
+  @return  Protected mode 16-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode16CS (
+  VOID
+  )
+{
+  IA32_DESCRIPTOR          GdtrDesc;
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;
+  UINTN                    GdtEntryCount;
+  UINT16                   Index;
+
+  Index = (UINT16) -1;
+  AsmReadGdtr (&GdtrDesc);
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+  GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+  for (Index = 0; Index < GdtEntryCount; Index++) {
+    if (GdtEntry->Bits.L == 0 &&
+        GdtEntry->Bits.DB == 0 &&
+        GdtEntry->Bits.Type > 8) {
+      break;
+    }
+    GdtEntry++;
+  }
+  ASSERT (Index != GdtEntryCount);
+  return Index * 8;
+}
+
+/**
+  Get Protected mode code segment with 32-bit default addressing
+  from current GDT table.
+
+  @return  Protected mode 32-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode32CS (
+  VOID
+  )
+{
+  IA32_DESCRIPTOR          GdtrDesc;
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;
+  UINTN                    GdtEntryCount;
+  UINT16                   Index;
+
+  Index = (UINT16) -1;
+  AsmReadGdtr (&GdtrDesc);
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+  GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+  for (Index = 0; Index < GdtEntryCount; Index++) {
+    if (GdtEntry->Bits.L == 0 &&
+        GdtEntry->Bits.DB == 1 &&
+        GdtEntry->Bits.Type > 8) {
+      break;
+    }
+    GdtEntry++;
+  }
+  ASSERT (Index != GdtEntryCount);
+  return Index * 8;
+}
+
+/**
+  Reset an AP when in SEV-ES mode.
+
+  @retval EFI_DEVICE_ERROR        Reset of AP failed.
+**/
+STATIC
+VOID
+MpInitLibSevEsAPReset (
+  GHCB                         *Ghcb,
+  CPU_MP_DATA                  *CpuMpData
+  )
+{
+  UINT16           Code16, Code32;
+  AP_RESET         *APResetFn;
+  UINTN            BufferStart;
+  UINTN            StackStart;
+
+  Code16 = GetProtectedMode16CS ();
+  Code32 = GetProtectedMode32CS ();
+
+  if (CpuMpData->WakeupBufferHigh != 0) {
+    APResetFn = (AP_RESET *) (CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);
+  } else {
+    APResetFn = (AP_RESET *) (CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);
+  }
+
+  BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;
+  StackStart = CpuMpData->SevEsAPResetStackStart -
+                 (AP_RESET_STACK_SIZE * GetApicId ());
+
+  //
+  // This call never returns.
+  //
+  APResetFn (BufferStart, Code16, Code32, StackStart);
+}
+
 /**
   This function will be called from AP reset code if BSP uses WakeUpAP.
 
@@ -714,7 +818,28 @@ ApWakeupFunction (
       //
       while (TRUE) {
         DisableInterrupts ();
-        CpuSleep ();
+        if (CpuMpData->SevEsActive) {
+          MSR_SEV_ES_GHCB_REGISTER  Msr;
+          GHCB                      *Ghcb;
+
+          Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+          Ghcb = Msr.Ghcb;
+
+          VmgInit (Ghcb);
+          VmgExit (Ghcb, SvmExitApResetHold, 0, 0);
+          /*TODO: Check return value to verify SIPI issued */
+
+          //
+          // Awakened in a new phase? Use the new CpuMpData
+          //
+          if (CpuMpData->NewCpuMpData) {
+            CpuMpData = CpuMpData->NewCpuMpData;
+          }
+
+          MpInitLibSevEsAPReset (Ghcb, CpuMpData);
+        } else {
+          CpuSleep ();
+        }
         CpuPause ();
       }
     }
@@ -814,6 +939,9 @@ FillExchangeInfoData (
 
   ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;
 
+  ExchangeInfo->SevEsActive     = CpuMpData->SevEsActive;
+  ExchangeInfo->GhcbBase        = CpuMpData->GhcbBase;
+
   //
   // Get the BSP's data of GDT and IDT
   //
@@ -840,8 +968,9 @@ FillExchangeInfoData (
   // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
   //
   if (CpuMpData->WakeupBufferHigh != 0) {
-    Size = CpuMpData->AddressMap.RendezvousFunnelSize -
-           CpuMpData->AddressMap.ModeTransitionOffset;
+    Size = CpuMpData->AddressMap.RendezvousFunnelSize +
+             CpuMpData->AddressMap.SwitchToRealSize -
+             CpuMpData->AddressMap.ModeTransitionOffset;
     CopyMem (
       (VOID *)CpuMpData->WakeupBufferHigh,
       CpuMpData->AddressMap.RendezvousFunnelAddress +
@@ -894,7 +1023,8 @@ BackupAndPrepareWakeupBuffer(
   CopyMem (
     (VOID *) CpuMpData->WakeupBuffer,
     (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
-    CpuMpData->AddressMap.RendezvousFunnelSize
+    CpuMpData->AddressMap.RendezvousFunnelSize +
+      CpuMpData->AddressMap.SwitchToRealSize
     );
 }
 
@@ -915,6 +1045,40 @@ RestoreWakeupBuffer(
     );
 }
 
+/**
+  Calculate the size of the reset stack.
+**/
+STATIC
+UINTN
+GetApResetStackSize(
+  VOID
+  )
+{
+  return AP_RESET_STACK_SIZE * PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+}
+
+/**
+  Calculate the size of the reset vector.
+
+  @param[in]  AddressMap  The pointer to Address Map structure.
+**/
+STATIC
+UINTN
+GetApResetVectorSize(
+  IN MP_ASSEMBLY_ADDRESS_MAP  *AddressMap
+  )
+{
+  UINTN  Size;
+
+  Size = ALIGN_VALUE (AddressMap->RendezvousFunnelSize +
+                        AddressMap->SwitchToRealSize +
+                        sizeof (MP_CPU_EXCHANGE_INFO),
+                      CPU_STACK_ALIGNMENT);
+  Size += GetApResetStackSize ();
+
+  return Size;
+}
+
 /**
   Allocate reset vector buffer.
 
@@ -928,16 +1092,22 @@ AllocateResetVector (
   UINTN           ApResetVectorSize;
 
   if (CpuMpData->WakeupBuffer == (UINTN) -1) {
-    ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
-                          sizeof (MP_CPU_EXCHANGE_INFO);
+    ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);
 
     CpuMpData->WakeupBuffer      = GetWakeupBuffer (ApResetVectorSize);
     CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
-                    (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
+                    (CpuMpData->WakeupBuffer +
+                       CpuMpData->AddressMap.RendezvousFunnelSize +
+                       CpuMpData->AddressMap.SwitchToRealSize);
     CpuMpData->WakeupBufferHigh  = GetModeTransitionBuffer (
-                                    CpuMpData->AddressMap.RendezvousFunnelSize -
+                                    CpuMpData->AddressMap.RendezvousFunnelSize +
+                                    CpuMpData->AddressMap.SwitchToRealSize -
                                     CpuMpData->AddressMap.ModeTransitionOffset
                                     );
+    //
+    // The reset stack starts at the end of the buffer.
+    //
+    CpuMpData->SevEsAPResetStackStart = CpuMpData->WakeupBuffer + ApResetVectorSize;
   }
   BackupAndPrepareWakeupBuffer (CpuMpData);
 }
@@ -952,7 +1122,30 @@ FreeResetVector (
   IN CPU_MP_DATA              *CpuMpData
   )
 {
-  RestoreWakeupBuffer (CpuMpData);
+  //
+  // If SEV-ES is active, the reset area is needed for AP parking and
+  // and AP startup in the OS, so the reset area is reserved. Do not
+  // perform the restore as this will overwrite memory which has data
+  // needed by SEV-ES.
+  //
+  if (!CpuMpData->SevEsActive) {
+    RestoreWakeupBuffer (CpuMpData);
+  }
+}
+
+/**
+  Allocate ...
+
+  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateSevEsAPMemory (
+  IN OUT CPU_MP_DATA          *CpuMpData
+  )
+{
+  if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
+    CpuMpData->SevEsAPBuffer = CpuMpData->SevEsActive ? GetSevEsAPMemory () : 0;
+  }
 }
 
 /**
@@ -985,10 +1178,12 @@ WakeUpAP (
   CpuMpData->FinishedCount = 0;
   ResetVectorRequired = FALSE;
 
+  AllocateResetVector (CpuMpData);
+  AllocateSevEsAPMemory (CpuMpData);
+
   if (CpuMpData->WakeUpByInitSipiSipi ||
       CpuMpData->InitFlag   != ApInitDone) {
     ResetVectorRequired = TRUE;
-    AllocateResetVector (CpuMpData);
     FillExchangeInfoData (CpuMpData);
     SaveLocalApicTimerSetting (CpuMpData);
   }
@@ -1025,6 +1220,15 @@ WakeUpAP (
       }
     }
     if (ResetVectorRequired) {
+      //
+      // For SEV-ES, set the jump address for initial AP boot
+      //
+      if (CpuMpData->SevEsActive) {
+        SEV_ES_AP_JMP_FAR *JmpFar = (SEV_ES_AP_JMP_FAR *)0xFFFFFFD0;
+
+        JmpFar->ApStart.Rip = 0;
+        JmpFar->ApStart.Segment = (UINT16) (ExchangeInfo->BufferStart >> 4);
+      }
       //
       // Wakeup all APs
       //
@@ -1550,7 +1754,7 @@ MpInitLibInitialize (
   ASSERT (MaxLogicalProcessorNumber != 0);
 
   AsmGetAddressMap (&AddressMap);
-  ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+  ApResetVectorSize = GetApResetVectorSize (&AddressMap);
   ApStackSize = PcdGet32(PcdCpuApStackSize);
   ApLoopMode  = GetApLoopMode (&MonitorFilterSize);
 
@@ -1640,6 +1844,8 @@ MpInitLibInitialize (
   }
 
   CpuMpData->SevEsActive      = PcdGet32 (PcdCpuSevEsActive);
+  CpuMpData->SevEsAPBuffer    = (UINTN) -1;
+  CpuMpData->GhcbBase         = PcdGet64 (PcdGhcbBase);
   InitializeSpinLock(&CpuMpData->MpLock);
 
   //
@@ -1707,6 +1913,7 @@ MpInitLibInitialize (
     // APs have been wakeup before, just get the CPU Information
     // from HOB
     //
+    OldCpuMpData->NewCpuMpData = CpuMpData;
     CpuMpData->CpuCount  = OldCpuMpData->CpuCount;
     CpuMpData->BspNumber = OldCpuMpData->BspNumber;
     CpuMpData->InitFlag  = ApInitReconfig;
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 35dff91fd2a5..75b8e38ae8e3 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -279,6 +279,22 @@ GetModeTransitionBuffer (
   return 0;
 }
 
+/**
+  Get ...
+
+  @retval other   Return SEV-ES AP wakeup buffer
+**/
+UINTN
+GetSevEsAPMemory (
+  VOID
+  )
+{
+  //
+  // PEI phase doesn't need to do this pre-allocation. So simply return 0.
+  //
+  return 0;
+}
+
 /**
   Checks APs status and updates APs status if needed.
 
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
index 6298571e29b2..28f8e8e133e5 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
@@ -121,7 +121,7 @@ GetProtectedModeCS (
   GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
   for (Index = 0; Index < GdtEntryCount; Index++) {
     if (GdtEntry->Bits.L == 0) {
-      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
+      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {
         break;
       }
     }
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
new file mode 100644
index 000000000000..bed832d7efe6
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -0,0 +1,85 @@
+;------------------------------------------------------------------------------
+; @file
+; First code executed by processor after resetting.
+;
+; Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution.  The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+;------------------------------------------------------------------------------
+
+BITS    16
+
+ALIGN   16
+
+;
+; Pad the image size to 4k when page tables are in VTF0
+;
+; If the VTF0 image has page tables built in, then we need to make
+; sure the end of VTF0 is 4k above where the page tables end.
+;
+; This is required so the page tables will be 4k aligned when VTF0 is
+; located just below 0x100000000 (4GB) in the firmware device.
+;
+%ifdef ALIGN_TOP_TO_4K_FOR_PAGING
+    TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
+%endif
+
+;
+; SEV-ES Processor Reset support
+;
+; standardProcessorReset:    (0xffffffd0)
+;   When using the Application Processors entry point, always perform a
+;   far jump to the RIP/CS value contained at this location.  This will
+;   default to EarlyBspInitReal16 unless specifically overridden.
+
+standardProcessorSevEsReset:
+    DW      0x0000
+    DW      0x0000
+
+ALIGN   16
+
+applicationProcessorEntryPoint:
+;
+; Application Processors entry point
+;
+; GenFv generates code aligned on a 4k boundary which will jump to this
+; location.  (0xffffffe0)  This allows the Local APIC Startup IPI to be
+; used to wake up the application processors.
+;
+    jmp     EarlyApInitReal16
+
+ALIGN   8
+
+    DD      0
+
+;
+; The VTF signature
+;
+; VTF-0 means that the VTF (Volume Top File) code does not require
+; any fixups.
+;
+vtfSignature:
+    DB      'V', 'T', 'F', 0
+
+ALIGN   16
+
+resetVector:
+;
+; Reset Vector
+;
+; This is where the processor will begin execution
+;
+    cmp     dword [CS:0xFFD0], 0
+    je      EarlyBspInitReal16
+    jmp     far [CS:0xFFD0]
+
+ALIGN   16
+
+fourGigabytes:
+
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
index efb1bc2bf7cb..180fa87b8dca 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
@@ -19,7 +19,7 @@ CPU_SWITCH_STATE_IDLE         equ        0
 CPU_SWITCH_STATE_STORED       equ        1
 CPU_SWITCH_STATE_LOADED       equ        2
 
-LockLocation                  equ        (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+LockLocation                  equ        (SwitchToRealProcEnd - RendezvousFunnelProcStart)
 StackStartAddressLocation     equ        LockLocation + 04h
 StackSizeLocation             equ        LockLocation + 08h
 ApProcedureLocation           equ        LockLocation + 0Ch
@@ -40,4 +40,6 @@ ModeTransitionMemoryLocation        equ  LockLocation + 4Ch
 ModeTransitionSegmentLocation       equ  LockLocation + 50h
 ModeHighMemoryLocation              equ  LockLocation + 52h
 ModeHighSegmentLocation             equ  LockLocation + 56h
+SevEsActiveLocation           equ        LockLocation + 58h
+GhcbBaseLocation              equ        LockLocation + 5Ch
 
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
index b74046b76af3..309d53bf3b37 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
@@ -215,6 +215,16 @@ CProcedureInvoke:
     jmp        $                 ; Never reach here
 RendezvousFunnelProcEnd:
 
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;NOT USED IN 32 BIT MODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+    jmp        $                 ; Never reach here
+SwitchToRealProcEnd:
+
 ;-------------------------------------------------------------------------------------
 ;  AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
 ;-------------------------------------------------------------------------------------
@@ -263,6 +273,11 @@ ASM_PFX(AsmGetAddressMap):
     mov        dword [ebx + 0Ch], AsmRelocateApLoopStart
     mov        dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
     mov        dword [ebx + 14h], Flat32Start - RendezvousFunnelProcStart
+    mov        dword [ebx + 18h], SwitchToRealProcEnd - SwitchToRealProcStart       ; SwitchToRealSize
+    mov        dword [ebx + 1Ch], SwitchToRealProcStart - RendezvousFunnelProcStart ; SwitchToRealOffset
+    mov        dword [ebx + 20h], SwitchToRealProcStart - Flat32Start               ; SwitchToRealNoNxOffset
+    mov        dword [ebx + 24h], 0                                                 ; SwitchToRealPM16ModeOffset
+    mov        dword [ebx + 28h], 0                                                 ; SwitchToRealPM16ModeSize
 
     popad
     ret
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
index 467f54a8602e..e05ef9a664ba 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
@@ -19,7 +19,7 @@ CPU_SWITCH_STATE_IDLE         equ        0
 CPU_SWITCH_STATE_STORED       equ        1
 CPU_SWITCH_STATE_LOADED       equ        2
 
-LockLocation                  equ        (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+LockLocation                  equ        (SwitchToRealProcEnd - RendezvousFunnelProcStart)
 StackStartAddressLocation     equ        LockLocation + 08h
 StackSizeLocation             equ        LockLocation + 10h
 ApProcedureLocation           equ        LockLocation + 18h
@@ -40,3 +40,5 @@ ModeTransitionMemoryLocation        equ  LockLocation + 94h
 ModeTransitionSegmentLocation       equ  LockLocation + 98h
 ModeHighMemoryLocation              equ  LockLocation + 9Ah
 ModeHighSegmentLocation             equ  LockLocation + 9Eh
+SevEsActiveLocation           equ        LockLocation + 0A0h
+GhcbBaseLocation              equ        LockLocation + 0A4h
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index cea90f3d4deb..286fa297791c 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -172,9 +172,97 @@ Releaselock:
     add        edi, StackStartAddressLocation
     add        rax, qword [edi]
     mov        rsp, rax
+
+    lea        edi, [esi + SevEsActiveLocation]
+    cmp        dword [edi], 1       ; SevEsActive
+    jne        CProcedureInvoke
+
+    ;
+    ; program GHCB
+    ;   Each page after the GHCB is a per-CPU page, so the calculation programs
+    ;   a GHCB to be every 8KB.
+    ;
+    mov        eax, SIZE_4KB
+    shl        eax, 1                            ; EAX = SIZE_4K * 2
+    mov        ecx, ebx
+    mul        ecx                               ; EAX = SIZE_4K * 2 * CpuNumber
+    mov        edi, esi
+    add        edi, GhcbBaseLocation
+    add        rax, qword [edi]
+    mov        rdx, rax
+    shr        rdx, 32
+    mov        rcx, 0xc0010130
+    wrmsr
     jmp        CProcedureInvoke
 
 GetApicId:
+    lea        edi, [esi + SevEsActiveLocation]
+    cmp        dword [edi], 1       ; SevEsActive
+    jne        DoCpuid
+
+    ;
+    ; Since we don't have a stack yet, we can't take a #VC
+    ; exception. Use the GHCB protocol to perform the CPUID
+    ; calls.
+    ;
+    mov        rcx, 0xc0010130
+    rdmsr
+    shl        rdx, 32
+    or         rax, rdx
+    mov        rdi, rax             ; RDI now holds the original GHCB GPA
+
+    mov        rdx, 0               ; CPUID function 0
+    mov        rax, 0               ; RAX register requested
+    or         rax, 4
+    wrmsr
+    rep vmmcall
+    rdmsr
+    cmp        edx, 0bh
+    jb         NoX2ApicSevEs        ; CPUID level below CPUID_EXTENDED_TOPOLOGY
+
+    mov        rdx, 0bh             ; CPUID function 0x0b
+    mov        rax, 040000000h      ; RBX register requested
+    or         rax, 4
+    wrmsr
+    rep vmmcall
+    rdmsr
+    test       edx, 0ffffh
+    jz         NoX2ApicSevEs        ; CPUID.0BH:EBX[15:0] is zero
+
+    mov        rdx, 0bh             ; CPUID function 0x0b
+    mov        rax, 0c0000000h      ; RDX register requested
+    or         rax, 4
+    wrmsr
+    rep vmmcall
+    rdmsr
+
+    ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
+    jmp        RestoreGhcb
+
+NoX2ApicSevEs:
+    ; Processor is not x2APIC capable, so get 8-bit APIC ID
+    mov        rdx, 1               ; CPUID function 1
+    mov        rax, 040000000h      ; RBX register requested
+    or         rax, 4
+    wrmsr
+    rep vmmcall
+    rdmsr
+    shr        edx, 24
+
+RestoreGhcb:
+    mov        rbx, rdx             ; Save x2APIC/APIC ID
+
+    mov        rdx, rdi             ; RDI holds the saved GHCB GPA
+    shr        rdx, 32
+    mov        eax, edi
+    wrmsr
+
+    mov        rdx, rbx
+
+    ; x2APIC ID or APIC ID is in EDX
+    jmp        GetProcessorNumber
+
+DoCpuid:
     mov        eax, 0
     cpuid
     cmp        eax, 0bh
@@ -241,12 +329,158 @@ CProcedureInvoke:
 
 RendezvousFunnelProcEnd:
 
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;  SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
+;  rcx - Buffer Start
+;  rdx - Code16 Selector Offset
+;  r8  - Code32 Selector Offset
+;  r9  - Stack Start
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+BITS 64
+    cli
+
+    ;
+    ; Get RDX reset value before changing stacks since the
+    ; new stack won't be able to accomodate a #VC exception.
+    ;
+    push       rax
+    push       rbx
+    push       rcx
+    push       rdx
+
+    mov        rax, 1
+    cpuid
+    mov        rsi, rax                    ; Save off the reset value for RDX
+
+    pop        rdx
+    pop        rcx
+    pop        rbx
+    pop        rax
+
+    ;
+    ; Establish stack below 1MB
+    ;
+    mov        rsp, r9
+
+    ;
+    ; Push ultimate Reset Vector onto the stack
+    ;
+    mov        rax, rcx
+    shr        rax, 4
+    push       word 0x0002                 ; RFLAGS
+    push       ax                          ; CS
+    push       word 0x0000                 ; RIP
+    push       word 0x0000                 ; For alignment, will be discarded
+
+    ;
+    ; Get address of "16-bit operand size" label
+    ;
+    lea        rbx, [PM16Mode]
+
+    ;
+    ; Push addresses used to change to compatibility mode
+    ;
+    lea        rax, [CompatMode]
+    push       r8
+    push       rax
+
+    ;
+    ; Clear R8 - R15, for reset, before going into 32-bit mode
+    ;
+    xor        r8, r8
+    xor        r9, r9
+    xor        r10, r10
+    xor        r11, r11
+    xor        r12, r12
+    xor        r13, r13
+    xor        r14, r14
+    xor        r15, r15
+
+    ;
+    ; Far return into 32-bit mode
+    ;
+o64 retf
+
+BITS 32
+CompatMode:
+    ;
+    ; Set up stack to prepare for exiting protected mode
+    ;
+    push       edx                         ; Code16 CS
+    push       ebx                         ; PM16Mode label address
+
+    ;
+    ; Disable paging
+    ;
+    mov        eax, cr0                    ; Read CR0
+    btr        eax, 31                     ; Set PG=0
+    mov        cr0, eax                    ; Write CR0
+
+    ;
+    ; Disable long mode
+    ;
+    mov        ecx, 0c0000080h             ; EFER MSR number
+    rdmsr                                  ; Read EFER
+    btr        eax, 8                      ; Set LME=0
+    wrmsr                                  ; Write EFER
+
+    ;
+    ; Disable PAE
+    ;
+    mov        eax, cr4                    ; Read CR4
+    btr        eax, 5                      ; Set PAE=0
+    mov        cr4, eax                    ; Write CR4
+
+    mov        edx, esi                    ; Restore RDX reset value
+
+    ;
+    ; Switch to 16-bit operand size
+    ;
+    retf
+
+BITS 16
+    ;
+    ; At entry to this label
+    ;   - RDX will have its reset value
+    ;   - On the top of the stack
+    ;     - Alignment data (two bytes) to be discarded
+    ;     - IP for Real Mode (two bytes)
+    ;     - CS for Real Mode (two bytes)
+    ;
+PM16Mode:
+    mov        eax, cr0                    ; Read CR0
+    btr        eax, 0                      ; Set PE=0
+    mov        cr0, eax                    ; Write CR0
+
+    pop        ax                          ; Discard alignment data
+
+    ;
+    ; Clear registers (except RDX and RSP) before going into 16-bit mode
+    ;
+    xor        eax, eax
+    xor        ebx, ebx
+    xor        ecx, ecx
+    xor        esi, esi
+    xor        edi, edi
+    xor        ebp, ebp
+
+    iret
+
+SwitchToRealProcEnd:
+
 ;-------------------------------------------------------------------------------------
 ;  AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
 ;-------------------------------------------------------------------------------------
 global ASM_PFX(AsmRelocateApLoop)
 ASM_PFX(AsmRelocateApLoop):
 AsmRelocateApLoopStart:
+BITS 64
     cli                          ; Disable interrupt before switching to 32-bit mode
     mov        rax, [rsp + 40]   ; CountTofinish
     lock dec   dword [rax]       ; (*CountTofinish)--
@@ -312,6 +546,11 @@ ASM_PFX(AsmGetAddressMap):
     mov        qword [rcx + 18h], rax
     mov        qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
     mov        qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart
+    mov        qword [rcx + 30h], SwitchToRealProcEnd - SwitchToRealProcStart          ; SwitchToRealSize
+    mov        qword [rcx + 38h], SwitchToRealProcStart - RendezvousFunnelProcStart    ; SwitchToRealOffset
+    mov        qword [rcx + 40h], SwitchToRealProcStart - Flat32Start                  ; SwitchToRealNoNxOffset
+    mov        qword [rcx + 48h], PM16Mode - RendezvousFunnelProcStart                 ; SwitchToRealPM16ModeOffset
+    mov        qword [rcx + 50h], SwitchToRealProcEnd - PM16Mode                       ; SwitchToRealPM16ModeSize
     ret
 
 ;-------------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
index ce4ebfffb688..0e79a3984b16 100644
--- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
+++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm
@@ -129,5 +129,14 @@ LINEAR_CODE64_SEL   equ $-GDT_BASE
     DB      0            ; base 31:24
 %endif
 
+; linear code segment descriptor
+LINEAR_CODE16_SEL     equ $-GDT_BASE
+    DW      0xffff       ; limit 15:0
+    DW      0            ; base 15:0
+    DB      0            ; base 23:16
+    DB      PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(CODE32_TYPE)
+    DB      GRANULARITY_FLAG(1)|DEFAULT_SIZE32(0)|CODE64_FLAG(0)|UPPER_LIMIT(0xf)
+    DB      0            ; base 31:24
+
 GDT_END:
 
-- 
2.17.1


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

* [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (26 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
@ 2019-08-19 21:36 ` Lendacky, Thomas
  2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek
  28 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 21:36 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh

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

Introduce a finalization routine to the MP library.  This routine is
used at the end of UEFI before transferring control to the OS and allows
for SEV-ES related AP state and information to be communicated to the OS.
The APs will be parked using VMGEXIT AP Reset Hold and the GHCB will be
modified to communicate a reserved page of memory that will be used by the
OS to direct the "initial" AP boot in the OS.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Include/Protocol/Cpu.h                 |   6 +
 UefiCpuPkg/CpuDxe/CpuDxe.h                    |  14 ++
 UefiCpuPkg/Include/Library/MpInitLib.h        |  17 +++
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  18 ++-
 MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c       |   5 +
 OvmfPkg/PlatformPei/AmdSev.c                  |   2 +-
 UefiCpuPkg/CpuDxe/CpuDxe.c                    |  10 ++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  57 +++++++-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  25 ++++
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 130 ++++++++++++++++--
 10 files changed, 265 insertions(+), 19 deletions(-)

diff --git a/MdePkg/Include/Protocol/Cpu.h b/MdePkg/Include/Protocol/Cpu.h
index e392f4cd9a13..79a701bc0d93 100644
--- a/MdePkg/Include/Protocol/Cpu.h
+++ b/MdePkg/Include/Protocol/Cpu.h
@@ -257,6 +257,11 @@ EFI_STATUS
   IN  UINT64                            Attributes
   );
 
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FINALIZE)(
+  IN EFI_CPU_ARCH_PROTOCOL              *This
+  );
 
 ///
 /// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
@@ -273,6 +278,7 @@ struct _EFI_CPU_ARCH_PROTOCOL {
   EFI_CPU_REGISTER_INTERRUPT_HANDLER  RegisterInterruptHandler;
   EFI_CPU_GET_TIMER_VALUE             GetTimerValue;
   EFI_CPU_SET_MEMORY_ATTRIBUTES       SetMemoryAttributes;
+  EFI_CPU_FINALIZE                    Finalize;
   ///
   /// The number of timers that are available in a processor. The value in this
   /// field is a constant that must not be modified after the CPU Architectural
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
index b029be430b4c..c5b9ada72ac9 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.h
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
@@ -232,6 +232,20 @@ CpuSetMemoryAttributes (
   IN UINT64                     Attributes
   );
 
+/**
+  Set ...
+
+  @param  This                   Protocol instance structure
+
+  @retval EFI_SUCCESS            If ...
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFinalize (
+  IN EFI_CPU_ARCH_PROTOCOL      *This
+  );
+
 /**
   Initialize Global Descriptor Table.
 
diff --git a/UefiCpuPkg/Include/Library/MpInitLib.h b/UefiCpuPkg/Include/Library/MpInitLib.h
index fa8252937313..2095fb758664 100644
--- a/UefiCpuPkg/Include/Library/MpInitLib.h
+++ b/UefiCpuPkg/Include/Library/MpInitLib.h
@@ -344,4 +344,21 @@ MpInitLibWhoAmI (
   OUT UINTN                    *ProcessorNumber
   );
 
+/**
+  MP Exit ...
+
+  This service ...
+
+  This service must be invoked before ...
+
+  @retval  EFI_SUCCESS           MP initialization succeeds.
+  @retval  Others                MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpLibFinalize (
+  VOID
+  );
+
 #endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f2ba1a508715..a2ba6de0278f 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -273,7 +273,8 @@ struct _CPU_MP_DATA {
   UINT64                         GhcbBase;
 };
 
-#define AP_RESET_STACK_SIZE 64
+#define AP_SAFE_STACK_SIZE  128
+#define AP_RESET_STACK_SIZE AP_SAFE_STACK_SIZE
 
 typedef union {
   struct {
@@ -327,8 +328,11 @@ VOID
   IN BOOLEAN                 MwaitSupport,
   IN UINTN                   ApTargetCState,
   IN UINTN                   PmCodeSegment,
+  IN UINTN                   Pm16CodeSegment,
   IN UINTN                   TopOfApStack,
-  IN UINTN                   NumberToFinish
+  IN UINTN                   NumberToFinish,
+  IN UINTN                   SevEsAPJumpTable,
+  IN UINTN                   WakeupBuffer
   );
 
 /**
@@ -645,5 +649,15 @@ EnableDebugAgent (
   VOID
   );
 
+/**
+  MP finalize ...
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
+**/
+EFI_STATUS
+MpFinalize (
+  IN CPU_MP_DATA   *CpuMpData
+  );
+
 #endif
 
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
index 514d1aa75ada..13c962247243 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -785,6 +785,11 @@ CoreExitBootServices (
   //
   gCpu->DisableInterrupt (gCpu);
 
+  //
+  // Finalize CPU
+  //
+  gCpu->Finalize (gCpu);
+
   //
   // Clear the non-runtime values of the EFI System Table
   //
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index fc396a6f229d..f0a18f026460 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -65,7 +65,7 @@ AmdSevEsInitialize (
   BuildMemoryAllocationHob (
     GhcbBasePa,
     EFI_PAGES_TO_SIZE (GhcbPageCount),
-    EfiBootServicesData
+    EfiReservedMemoryType
     );
 
   SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c
index 7d7270e10b4a..7003f74e7d87 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.c
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.c
@@ -92,6 +92,7 @@ EFI_CPU_ARCH_PROTOCOL  gCpu = {
   CpuRegisterInterruptHandler,
   CpuGetTimerValue,
   CpuSetMemoryAttributes,
+  CpuFinalize,
   1,                          // NumberOfTimers
   4                           // DmaBufferAlignment
 };
@@ -499,6 +500,15 @@ CpuSetMemoryAttributes (
   return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
 }
 
+EFI_STATUS
+EFIAPI
+CpuFinalize (
+  IN EFI_CPU_ARCH_PROTOCOL     *This
+  )
+{
+  return MpLibFinalize ();
+}
+
 /**
   Initializes the valid bits mask and valid address mask for MTRRs.
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 127f64eb87e1..6e1bdbeed259 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -18,7 +18,6 @@
 #include <Protocol/Timer.h>
 
 #define  AP_CHECK_INTERVAL     (EFI_TIMER_PERIOD_MILLISECONDS (100))
-#define  AP_SAFE_STACK_SIZE    128
 
 CPU_MP_DATA      *mCpuMpData = NULL;
 EFI_EVENT        mCheckAllApsEvent = NULL;
@@ -98,7 +97,7 @@ GetWakeupBuffer (
   StartAddress = 0x88000;
   Status = gBS->AllocatePages (
                   AllocateMaxAddress,
-                  EfiBootServicesData,
+                  EfiReservedMemoryType,
                   EFI_SIZE_TO_PAGES (WakeupBufferSize),
                   &StartAddress
                   );
@@ -328,17 +327,26 @@ RelocateApLoop (
   BOOLEAN                MwaitSupport;
   ASM_RELOCATE_AP_LOOP   AsmRelocateApLoopFunc;
   UINTN                  ProcessorNumber;
+  UINTN                  StackStart;
 
   MpInitLibWhoAmI (&ProcessorNumber);
   CpuMpData    = GetCpuMpData ();
   MwaitSupport = IsMwaitSupport ();
+  if (CpuMpData->SevEsActive) {
+    StackStart = CpuMpData->SevEsAPResetStackStart;
+  } else {
+    StackStart = mReservedTopOfApStack;
+  }
   AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;
   AsmRelocateApLoopFunc (
     MwaitSupport,
     CpuMpData->ApTargetCState,
     CpuMpData->PmCodeSegment,
-    mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,
-    (UINTN) &mNumberToFinish
+    CpuMpData->Pm16CodeSegment,
+    StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
+    (UINTN) &mNumberToFinish,
+    CpuMpData->SevEsAPBuffer,
+    CpuMpData->WakeupBuffer
     );
   //
   // It should never reach here
@@ -880,3 +888,44 @@ MpInitLibEnableDisableAP (
 
   return Status;
 }
+
+/**
+  MP finalize ...
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
+**/
+EFI_STATUS
+MpFinalize (
+  IN CPU_MP_DATA   *CpuMpData
+  )
+{
+  if (CpuMpData->SevEsActive) {
+    //
+    // Perform SEV-ES specific finalization
+    //
+    if (CpuMpData->WakeupBuffer == (UINTN) -1) {
+      //
+      // No APs parked in UEFI, clear the GHCB
+      //
+      AsmWriteMsr64 (MSR_SEV_ES_GHCB, 0);
+    } else {
+      //
+      // Re-use reserved memory area below 1MB from WakeupBuffer
+      //
+      CopyMem (
+        (VOID *) CpuMpData->WakeupBuffer,
+        (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress +
+                   CpuMpData->AddressMap.SwitchToRealPM16ModeOffset,
+        CpuMpData->AddressMap.SwitchToRealPM16ModeSize
+        );
+
+      //
+      // Point the GHCB at the AP jump table to communicate the address to
+      // the booting system.
+      //
+      AsmWriteMsr64 (MSR_SEV_ES_GHCB, (CpuMpData->SevEsAPBuffer) | 0x03);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 0939019d7b8c..bc800a69527e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1707,6 +1707,31 @@ CheckAllAPs (
   return EFI_NOT_READY;
 }
 
+/**
+  MP Exit ...
+
+  This service ...
+
+  This service must be invoked before ...
+
+  @retval  EFI_SUCCESS           MP initialization succeeds.
+  @retval  Others                MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpLibFinalize (
+  VOID
+  )
+{
+  CPU_MP_DATA              *CpuMpData;
+
+  CpuMpData = GetCpuMpData ();
+  MpFinalize (CpuMpData);
+
+  return EFI_SUCCESS;
+}
+
 /**
   MP Initialize Library initialization.
 
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 286fa297791c..8936963913c4 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -446,7 +446,7 @@ CompatMode:
 
 BITS 16
     ;
-    ; At entry to this label
+    ; At entry to this label (used also by AsmRelocateApLoop):
     ;   - RDX will have its reset value
     ;   - On the top of the stack
     ;     - Alignment data (two bytes) to be discarded
@@ -475,32 +475,93 @@ PM16Mode:
 SwitchToRealProcEnd:
 
 ;-------------------------------------------------------------------------------------
-;  AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish);
+;  AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, Pm16CodeSegment, TopOfApStack, CountTofinish, SevEsAPJumpTable, WakeupBuffer);
 ;-------------------------------------------------------------------------------------
 global ASM_PFX(AsmRelocateApLoop)
 ASM_PFX(AsmRelocateApLoop):
 AsmRelocateApLoopStart:
 BITS 64
+    cmp        qword [rsp + 56], 0
+    je         NoSevEs
+
+    ;
+    ; Perform some SEV-ES related setup before leaving 64-bit mode
+    ;
+    push       rcx
+    push       rdx
+
+    ;
+    ; Get the RDX reset value using CPUID
+    ;
+    mov        rax, 1
+    cpuid
+    mov        rsi, rax          ; Save off the reset value for RDX
+
+    ;
+    ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call
+    ;   - No NAE events can be generated once this is set otherwise
+    ;     the AP_HLT_LOOP SW_EXITCODE will be overwritten.
+    ;
+    mov        rcx, 0xc0010130
+    rdmsr                        ; Retrieve current GHCB address
+    shl        rdx, 32
+    or         rdx, rax
+
+    mov        rdi, rdx
+    xor        rax, rax
+    mov        rcx, 0x800
+    shr        rcx, 3
+    rep stosq                    ; Clear the GHCB
+
+    mov        rax, 0x80000004   ; VMGEXIT AP_HLT_LOOP
+    mov        [rdx + 0x390], rax
+
+    pop        rdx
+    pop        rcx
+
+NoSevEs:
     cli                          ; Disable interrupt before switching to 32-bit mode
-    mov        rax, [rsp + 40]   ; CountTofinish
+    mov        rax, [rsp + 48]   ; CountTofinish
     lock dec   dword [rax]       ; (*CountTofinish)--
-    mov        rsp, r9
-    push       rcx
-    push       rdx
 
-    lea        rsi, [PmEntry]    ; rsi <- The start address of transition code
+    mov        rax, [rsp + 56]   ; SevEsAPJumpTable
+    mov        rbx, [rsp + 64]   ; WakeupBuffer
+    mov        rsp, [rsp + 40]   ; TopOfApStack
+
+    push       rax               ; Save SevEsAPJumpTable
+    push       rbx               ; Save WakeupBuffer
+    push       r9                ; Save Pm16CodeSegment
+    push       rcx               ; Save MwaitSupport
+    push       rdx               ; Save ApTargetCState
+
+    lea        rax, [PmEntry]    ; rax <- The start address of transition code
 
     push       r8
-    push       rsi
-    DB         0x48
-    retf
+    push       rax
+
+    ;
+    ; Clear R8 - R15, for reset, before going into 32-bit mode
+    ;
+    xor        r8, r8
+    xor        r9, r9
+    xor        r10, r10
+    xor        r11, r11
+    xor        r12, r12
+    xor        r13, r13
+    xor        r14, r14
+    xor        r15, r15
+
+    ;
+    ; Far return into 32-bit mode
+    ;
+o64 retf
+
 BITS 32
 PmEntry:
     mov        eax, cr0
     btr        eax, 31           ; Clear CR0.PG
     mov        cr0, eax          ; Disable paging and caches
 
-    mov        ebx, edx          ; Save EntryPoint to rbx, for rdmsr will overwrite rdx
     mov        ecx, 0xc0000080
     rdmsr
     and        ah, ~ 1           ; Clear LME
@@ -513,6 +574,8 @@ PmEntry:
     add        esp, 4
     pop        ecx,
     add        esp, 4
+
+MwaitCheck:
     cmp        cl, 1              ; Check mwait-monitor support
     jnz        HltLoop
     mov        ebx, edx           ; Save C-State to ebx
@@ -526,10 +589,53 @@ MwaitLoop:
     shl        eax, 4
     mwait
     jmp        MwaitLoop
+
 HltLoop:
+    pop        edx                ; PM16CodeSegment
+    add        esp, 4
+    pop        ebx                ; WakeupBuffer
+    add        esp, 4
+    pop        eax                ; SevEsAPJumpTable
+    add        esp, 4
+    cmp        eax, 0             ; Check for SEV-ES
+    je         DoHlt
+
+    cli
+    ;
+    ; SEV-ES is active, use VMGEXIT (GHCB information already
+    ; set by caller)
+    ;
+    ; VMGEXIT is rep vmmcall
+    ;
+    db         0xf3
+    db         0x0f
+    db         0x01
+    db         0xd9
+
+    ;
+    ; Back from VMGEXIT AP_HLT_LOOP
+    ;   Push the FLAGS/CS/IP values to use
+    ;
+    push       word 0x0002        ; EFLAGS
+    xor        ecx, ecx
+    mov        cx, [eax + 2]      ; CS
+    push       cx
+    mov        cx, [eax]          ; IP
+    push       cx
+    push       word 0x0000        ; For alignment, will be discarded
+
+    push       edx
+    push       ebx
+
+    mov        edx, esi           ; Restore RDX reset value
+
+    retf
+
+DoHlt:
     cli
     hlt
-    jmp        HltLoop
+    jmp        DoHlt
+
 BITS 64
 AsmRelocateApLoopEnd:
 
-- 
2.17.1


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

* Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
  2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
@ 2019-08-19 21:47   ` Ni, Ray
  2019-08-19 22:25     ` Lendacky, Thomas
  0 siblings, 1 reply; 46+ messages in thread
From: Ni, Ray @ 2019-08-19 21:47 UTC (permalink / raw)
  To: Lendacky, Thomas, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Singh, Brijesh

Tom,
1. It's not a common practice to have static inline functions defined in header file. Who is going to call them?
2. Recently I made a change to move the AMD registers definitions to MdePkg/Include/Register/Amd from UefiCpuPkg. Do you think that's a good idea and can you please put your new register definitions to MdePkg as well?
3. What happens if the "rep; vmmcall" is executed in Intel processor?

Thanks,
Ray

> -----Original Message-----
> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
> Sent: Monday, August 19, 2019 2:36 PM
> To: devel@edk2.groups.io
> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong,
> Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Singh, Brijesh <brijesh.singh@amd.com>
> Subject: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
> 
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> VMGEXIT is a new instruction used for Hypervisor/Guest communication when
> running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
> to occur, resulting in a #VMEXIT with an exit code value of 0x403.
> 
> To support VMGEXIT, define the VMGEXIT assember routine to issue the
> instruction (rep; vmmcall), the GHCB structure and some helper functions
> for communicating register information to and from the hypervisor and the
> guest.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  MdePkg/Library/BaseLib/BaseLib.inf      |   1 +
>  MdePkg/Include/Library/BaseLib.h        |  14 ++
>  UefiCpuPkg/Include/Register/Amd/Ghcb.h  | 197 ++++++++++++++++++++++++
>  MdePkg/Library/BaseLib/X64/GccInline.c  |  17 ++
>  MdePkg/Library/BaseLib/X64/VmgExit.nasm |  38 +++++
>  5 files changed, 267 insertions(+)
>  create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
>  create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
> 
> diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
> index 3586beb0ab5c..a41401340f95 100644
> --- a/MdePkg/Library/BaseLib/BaseLib.inf
> +++ b/MdePkg/Library/BaseLib/BaseLib.inf
> @@ -286,6 +286,7 @@ [Sources.X64]
>    X64/ReadCr2.nasm| MSFT
>    X64/ReadCr0.nasm| MSFT
>    X64/ReadEflags.nasm| MSFT
> +  X64/VmgExit.nasm | MSFT
> 
> 
>    X64/Non-existing.c
> diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
> index 2a75bc023f56..80bd5cf57a72 100644
> --- a/MdePkg/Include/Library/BaseLib.h
> +++ b/MdePkg/Include/Library/BaseLib.h
> @@ -7880,6 +7880,20 @@ AsmLfence (
>    VOID
>    );
> 
> +/**
> +  Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
> +
> +  Executes a VMGEXIT instruction. This function is only available on IA-32 and
> +  x64.
> +
> +**/
> +VOID
> +EFIAPI
> +AsmVmgExit (
> +  VOID
> +  );
> +
> +
>  /**
>    Patch the immediate operand of an IA32 or X64 instruction such that the byte,
>    word, dword or qword operand is encoded at the end of the instruction's
> diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
> new file mode 100644
> index 000000000000..e9fd116fac25
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
> @@ -0,0 +1,197 @@
> +
> +#ifndef __GHCB_H__
> +#define __GHCB_H__
> +
> +#include <Protocol/DebugSupport.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +
> +#define UD_EXCEPTION  6
> +#define GP_EXCEPTION 13
> +
> +#define GHCB_VERSION_MIN     1
> +#define GHCB_VERSION_MAX     1
> +
> +#define GHCB_STANDARD_USAGE  0
> +
> +typedef enum {
> +  SvmExitDr7Read       = 0x27,
> +  SvmExitDr7Write      = 0x37,
> +  SvmExitRdtsc         = 0x6E,
> +  SvmExitRdpmc,
> +  SvmExitCpuid         = 0x72,
> +  SvmExitInvd          = 0x76,
> +  SvmExitIoioProt      = 0x7B,
> +  SvmExitMsr,
> +  SvmExitVmmCall       = 0x81,
> +  SvmExitRdtscp        = 0x87,
> +  SvmExitWbinvd        = 0x89,
> +  SvmExitMonitor,
> +  SvmExitMwait,
> +  SvmExitNpf           = 0x400,
> +
> +  // VMG special exits
> +  SvmExitMmioRead      = 0x80000001,
> +  SvmExitMmioWrite,
> +  SvmExitNmiComplete,
> +  SvmExitApResetHold,
> +
> +  SvmExitUnsupported   = 0x8000FFFF,
> +} SVM_EXITCODE;
> +
> +typedef enum {
> +  GhcbCpl              = 25,
> +  GhcbRflags           = 46,
> +  GhcbRip,
> +  GhcbRsp              = 59,
> +  GhcbRax              = 63,
> +  GhcbRcx              = 97,
> +  GhcbRdx,
> +  GhcbRbx,
> +  GhcbRbp              = 101,
> +  GhcbRsi,
> +  GhcbRdi,
> +  GhcbR8,
> +  GhcbR9,
> +  GhcbR10,
> +  GhcbR11,
> +  GhcbR12,
> +  GhcbR13,
> +  GhcbR14,
> +  GhcbR15,
> +  GhcbXCr0             = 125,
> +} GHCB_REGISTER;
> +
> +typedef struct {
> +  UINT8                  Reserved1[203];
> +  UINT8                  Cpl;
> +  UINT8                  Reserved2[148];
> +  UINT64                 Dr7;
> +  UINT8                  Reserved3[144];
> +  UINT64                 Rax;
> +  UINT8                  Reserved4[264];
> +  UINT64                 Rcx;
> +  UINT64                 Rdx;
> +  UINT64                 Rbx;
> +  UINT8                  Reserved5[112];
> +  UINT64                 SwExitCode;
> +  UINT64                 SwExitInfo1;
> +  UINT64                 SwExitInfo2;
> +  UINT64                 SwScratch;
> +  UINT8                  Reserved6[56];
> +  UINT64                 XCr0;
> +  UINT8                  ValidBitmap[16];
> +  UINT64                 X87StateGpa;
> +  UINT8                  Reserved7[1016];
> +} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
> +
> +typedef struct {
> +  GHCB_SAVE_AREA         SaveArea;
> +  UINT8                  SharedBuffer[2032];
> +  UINT8                  Reserved1[10];
> +  UINT16                 ProtocolVersion;
> +  UINT32                 GhcbUsage;
> +} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
> +
> +typedef union {
> +  struct {
> +    UINT32  Lower32Bits;
> +    UINT32  Upper32Bits;
> +  } Elements;
> +
> +  UINT64    Uint64;
> +} GHCB_EXIT_INFO;
> +
> +static inline
> +BOOLEAN
> +GhcbIsRegValid(
> +  GHCB                   *Ghcb,
> +  GHCB_REGISTER          Reg
> +  )
> +{
> +  UINT32  RegIndex = Reg / 8;
> +  UINT32  RegBit   = Reg & 0x07;
> +
> +  return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
> +}
> +
> +static inline
> +VOID
> +GhcbSetRegValid(
> +  GHCB                   *Ghcb,
> +  GHCB_REGISTER          Reg
> +  )
> +{
> +  UINT32  RegIndex = Reg / 8;
> +  UINT32  RegBit   = Reg & 0x07;
> +
> +  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
> +}
> +
> +static inline
> +VOID
> +VmgException(
> +  UINTN                  Exception
> +  )
> +{
> +  switch (Exception) {
> +  case UD_EXCEPTION:
> +  case GP_EXCEPTION:
> +    break;
> +  default:
> +    ASSERT (0);
> +  }
> +}
> +
> +static inline
> +UINTN
> +VmgExit(
> +  GHCB                   *Ghcb,
> +  UINT64                 ExitCode,
> +  UINT64                 ExitInfo1,
> +  UINT64                 ExitInfo2
> +  )
> +{
> +  GHCB_EXIT_INFO   ExitInfo;
> +  UINTN            Reason, Action;
> +
> +  Ghcb->SaveArea.SwExitCode = ExitCode;
> +  Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
> +  Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
> +  AsmVmgExit ();
> +
> +  if (!Ghcb->SaveArea.SwExitInfo1) {
> +    return 0;
> +  }
> +
> +  ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
> +  Reason = ExitInfo.Elements.Upper32Bits;
> +  Action = ExitInfo.Elements.Lower32Bits;
> +  switch (Action) {
> +  case 1:
> +    VmgException (Reason);
> +    break;
> +  default:
> +    ASSERT (0);
> +  }
> +
> +  return Reason;
> +}
> +
> +static inline
> +VOID
> +VmgInit(
> +  GHCB                   *Ghcb
> +  )
> +{
> +  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
> +}
> +
> +static inline
> +VOID
> +VmgDone(
> +  GHCB                   *Ghcb
> +  )
> +{
> +}
> +#endif
> diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
> index 154ce1f57e92..17539caa0798 100644
> --- a/MdePkg/Library/BaseLib/X64/GccInline.c
> +++ b/MdePkg/Library/BaseLib/X64/GccInline.c
> @@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
>  }
> 
> 
> +/**
> +  Executes a VMGEXIT instruction.
> +
> +  Executes a VMGEXIT instruction. This function is only available on IA-32 and
> +  X64.
> +
> +**/
> +VOID
> +EFIAPI
> +AsmVmgExit (
> +  VOID
> +  )
> +{
> +  __asm__ __volatile__ ("rep; vmmcall":::"memory");
> +}
> +
> +
> diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
> new file mode 100644
> index 000000000000..b673bb94b60d
> --- /dev/null
> +++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
> @@ -0,0 +1,38 @@
> +;------------------------------------------------------------------------------
> +;
> +; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
> +; This program and the accompanying materials
> +; are licensed and made available under the terms and conditions of the BSD License
> +; which accompanies this distribution.  The full text of the license may be found at
> +; http://opensource.org/licenses/bsd-license.php.
> +;
> +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +;
> +; Module Name:
> +;
> +;   VmgExit.Asm
> +;
> +; Abstract:
> +;
> +;   AsmVmgExit function
> +;
> +; Notes:
> +;
> +;------------------------------------------------------------------------------
> +
> +    DEFAULT REL
> +    SECTION .text
> +
> +;------------------------------------------------------------------------------
> +; VOID
> +; EFIAPI
> +; AsmVmgExit (
> +;   VOID
> +;   );
> +;------------------------------------------------------------------------------
> +global ASM_PFX(AsmVmgExit)
> +ASM_PFX(AsmVmgExit):
> +    rep; vmmcall
> +    ret
> +
> --
> 2.17.1


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

* Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
  2019-08-19 21:47   ` Ni, Ray
@ 2019-08-19 22:25     ` Lendacky, Thomas
  0 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-19 22:25 UTC (permalink / raw)
  To: Ni, Ray, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Singh, Brijesh

Hi Ray,

On 8/19/19 4:47 PM, Ni, Ray wrote:
> Tom,
> 1. It's not a common practice to have static inline functions defined in header file. Who is going to call them?

The functions are called from two locations, so that's why I made them
static inline. I'm new to EDK2 programming, so I'm sure there will be a
number of things I do that will need to be changed.

Should I make them non-inline and move them to the BaseLib in MdePkg or
somewhere else?

> 2. Recently I made a change to move the AMD registers definitions to MdePkg/Include/Register/Amd from UefiCpuPkg. Do you think that's a good idea and can you please put your new register definitions to MdePkg as well?

Ok, let me pull the latest tree and rebase. This patchset is currently
based on a July 17th patch:

cce01f538fb4 ("MdePkg/BaseLib: Base64Decode(): don't declare variables in nested blocks")

so I'm probably behind the change that you made if it was recent.

> 3. What happens if the "rep; vmmcall" is executed in Intel processor?

Good question, I'm not sure. Is there a way that EDK2 has to prevent
execution of unsupported instructions?  Currently, this instruction will
only be invoked when it is known that SEV-ES is active.

Thanks,
Tom

> 
> Thanks,
> Ray
> 
>> -----Original Message-----
>> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
>> Sent: Monday, August 19, 2019 2:36 PM
>> To: devel@edk2.groups.io
>> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel
>> <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong,
>> Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Singh, Brijesh <brijesh.singh@amd.com>
>> Subject: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support
>>
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> VMGEXIT is a new instruction used for Hypervisor/Guest communication when
>> running as an SEV-ES guest. A VMGEXIT will cause an automatic exit (AE)
>> to occur, resulting in a #VMEXIT with an exit code value of 0x403.
>>
>> To support VMGEXIT, define the VMGEXIT assember routine to issue the
>> instruction (rep; vmmcall), the GHCB structure and some helper functions
>> for communicating register information to and from the hypervisor and the
>> guest.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  MdePkg/Library/BaseLib/BaseLib.inf      |   1 +
>>  MdePkg/Include/Library/BaseLib.h        |  14 ++
>>  UefiCpuPkg/Include/Register/Amd/Ghcb.h  | 197 ++++++++++++++++++++++++
>>  MdePkg/Library/BaseLib/X64/GccInline.c  |  17 ++
>>  MdePkg/Library/BaseLib/X64/VmgExit.nasm |  38 +++++
>>  5 files changed, 267 insertions(+)
>>  create mode 100644 UefiCpuPkg/Include/Register/Amd/Ghcb.h
>>  create mode 100644 MdePkg/Library/BaseLib/X64/VmgExit.nasm
>>
>> diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
>> index 3586beb0ab5c..a41401340f95 100644
>> --- a/MdePkg/Library/BaseLib/BaseLib.inf
>> +++ b/MdePkg/Library/BaseLib/BaseLib.inf
>> @@ -286,6 +286,7 @@ [Sources.X64]
>>    X64/ReadCr2.nasm| MSFT
>>    X64/ReadCr0.nasm| MSFT
>>    X64/ReadEflags.nasm| MSFT
>> +  X64/VmgExit.nasm | MSFT
>>
>>
>>    X64/Non-existing.c
>> diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
>> index 2a75bc023f56..80bd5cf57a72 100644
>> --- a/MdePkg/Include/Library/BaseLib.h
>> +++ b/MdePkg/Include/Library/BaseLib.h
>> @@ -7880,6 +7880,20 @@ AsmLfence (
>>    VOID
>>    );
>>
>> +/**
>> +  Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
>> +
>> +  Executes a VMGEXIT instruction. This function is only available on IA-32 and
>> +  x64.
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +AsmVmgExit (
>> +  VOID
>> +  );
>> +
>> +
>>  /**
>>    Patch the immediate operand of an IA32 or X64 instruction such that the byte,
>>    word, dword or qword operand is encoded at the end of the instruction's
>> diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
>> new file mode 100644
>> index 000000000000..e9fd116fac25
>> --- /dev/null
>> +++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
>> @@ -0,0 +1,197 @@
>> +
>> +#ifndef __GHCB_H__
>> +#define __GHCB_H__
>> +
>> +#include <Protocol/DebugSupport.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +
>> +#define UD_EXCEPTION  6
>> +#define GP_EXCEPTION 13
>> +
>> +#define GHCB_VERSION_MIN     1
>> +#define GHCB_VERSION_MAX     1
>> +
>> +#define GHCB_STANDARD_USAGE  0
>> +
>> +typedef enum {
>> +  SvmExitDr7Read       = 0x27,
>> +  SvmExitDr7Write      = 0x37,
>> +  SvmExitRdtsc         = 0x6E,
>> +  SvmExitRdpmc,
>> +  SvmExitCpuid         = 0x72,
>> +  SvmExitInvd          = 0x76,
>> +  SvmExitIoioProt      = 0x7B,
>> +  SvmExitMsr,
>> +  SvmExitVmmCall       = 0x81,
>> +  SvmExitRdtscp        = 0x87,
>> +  SvmExitWbinvd        = 0x89,
>> +  SvmExitMonitor,
>> +  SvmExitMwait,
>> +  SvmExitNpf           = 0x400,
>> +
>> +  // VMG special exits
>> +  SvmExitMmioRead      = 0x80000001,
>> +  SvmExitMmioWrite,
>> +  SvmExitNmiComplete,
>> +  SvmExitApResetHold,
>> +
>> +  SvmExitUnsupported   = 0x8000FFFF,
>> +} SVM_EXITCODE;
>> +
>> +typedef enum {
>> +  GhcbCpl              = 25,
>> +  GhcbRflags           = 46,
>> +  GhcbRip,
>> +  GhcbRsp              = 59,
>> +  GhcbRax              = 63,
>> +  GhcbRcx              = 97,
>> +  GhcbRdx,
>> +  GhcbRbx,
>> +  GhcbRbp              = 101,
>> +  GhcbRsi,
>> +  GhcbRdi,
>> +  GhcbR8,
>> +  GhcbR9,
>> +  GhcbR10,
>> +  GhcbR11,
>> +  GhcbR12,
>> +  GhcbR13,
>> +  GhcbR14,
>> +  GhcbR15,
>> +  GhcbXCr0             = 125,
>> +} GHCB_REGISTER;
>> +
>> +typedef struct {
>> +  UINT8                  Reserved1[203];
>> +  UINT8                  Cpl;
>> +  UINT8                  Reserved2[148];
>> +  UINT64                 Dr7;
>> +  UINT8                  Reserved3[144];
>> +  UINT64                 Rax;
>> +  UINT8                  Reserved4[264];
>> +  UINT64                 Rcx;
>> +  UINT64                 Rdx;
>> +  UINT64                 Rbx;
>> +  UINT8                  Reserved5[112];
>> +  UINT64                 SwExitCode;
>> +  UINT64                 SwExitInfo1;
>> +  UINT64                 SwExitInfo2;
>> +  UINT64                 SwScratch;
>> +  UINT8                  Reserved6[56];
>> +  UINT64                 XCr0;
>> +  UINT8                  ValidBitmap[16];
>> +  UINT64                 X87StateGpa;
>> +  UINT8                  Reserved7[1016];
>> +} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
>> +
>> +typedef struct {
>> +  GHCB_SAVE_AREA         SaveArea;
>> +  UINT8                  SharedBuffer[2032];
>> +  UINT8                  Reserved1[10];
>> +  UINT16                 ProtocolVersion;
>> +  UINT32                 GhcbUsage;
>> +} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
>> +
>> +typedef union {
>> +  struct {
>> +    UINT32  Lower32Bits;
>> +    UINT32  Upper32Bits;
>> +  } Elements;
>> +
>> +  UINT64    Uint64;
>> +} GHCB_EXIT_INFO;
>> +
>> +static inline
>> +BOOLEAN
>> +GhcbIsRegValid(
>> +  GHCB                   *Ghcb,
>> +  GHCB_REGISTER          Reg
>> +  )
>> +{
>> +  UINT32  RegIndex = Reg / 8;
>> +  UINT32  RegBit   = Reg & 0x07;
>> +
>> +  return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
>> +}
>> +
>> +static inline
>> +VOID
>> +GhcbSetRegValid(
>> +  GHCB                   *Ghcb,
>> +  GHCB_REGISTER          Reg
>> +  )
>> +{
>> +  UINT32  RegIndex = Reg / 8;
>> +  UINT32  RegBit   = Reg & 0x07;
>> +
>> +  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgException(
>> +  UINTN                  Exception
>> +  )
>> +{
>> +  switch (Exception) {
>> +  case UD_EXCEPTION:
>> +  case GP_EXCEPTION:
>> +    break;
>> +  default:
>> +    ASSERT (0);
>> +  }
>> +}
>> +
>> +static inline
>> +UINTN
>> +VmgExit(
>> +  GHCB                   *Ghcb,
>> +  UINT64                 ExitCode,
>> +  UINT64                 ExitInfo1,
>> +  UINT64                 ExitInfo2
>> +  )
>> +{
>> +  GHCB_EXIT_INFO   ExitInfo;
>> +  UINTN            Reason, Action;
>> +
>> +  Ghcb->SaveArea.SwExitCode = ExitCode;
>> +  Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
>> +  Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
>> +  AsmVmgExit ();
>> +
>> +  if (!Ghcb->SaveArea.SwExitInfo1) {
>> +    return 0;
>> +  }
>> +
>> +  ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
>> +  Reason = ExitInfo.Elements.Upper32Bits;
>> +  Action = ExitInfo.Elements.Lower32Bits;
>> +  switch (Action) {
>> +  case 1:
>> +    VmgException (Reason);
>> +    break;
>> +  default:
>> +    ASSERT (0);
>> +  }
>> +
>> +  return Reason;
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgInit(
>> +  GHCB                   *Ghcb
>> +  )
>> +{
>> +  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
>> +}
>> +
>> +static inline
>> +VOID
>> +VmgDone(
>> +  GHCB                   *Ghcb
>> +  )
>> +{
>> +}
>> +#endif
>> diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
>> index 154ce1f57e92..17539caa0798 100644
>> --- a/MdePkg/Library/BaseLib/X64/GccInline.c
>> +++ b/MdePkg/Library/BaseLib/X64/GccInline.c
>> @@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
>>  }
>>
>>
>> +/**
>> +  Executes a VMGEXIT instruction.
>> +
>> +  Executes a VMGEXIT instruction. This function is only available on IA-32 and
>> +  X64.
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +AsmVmgExit (
>> +  VOID
>> +  )
>> +{
>> +  __asm__ __volatile__ ("rep; vmmcall":::"memory");
>> +}
>> +
>> +
>> diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
>> new file mode 100644
>> index 000000000000..b673bb94b60d
>> --- /dev/null
>> +++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
>> @@ -0,0 +1,38 @@
>> +;------------------------------------------------------------------------------
>> +;
>> +; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
>> +; This program and the accompanying materials
>> +; are licensed and made available under the terms and conditions of the BSD License
>> +; which accompanies this distribution.  The full text of the license may be found at
>> +; http://opensource.org/licenses/bsd-license.php.
>> +;
>> +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
>> +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>> +;
>> +; Module Name:
>> +;
>> +;   VmgExit.Asm
>> +;
>> +; Abstract:
>> +;
>> +;   AsmVmgExit function
>> +;
>> +; Notes:
>> +;
>> +;------------------------------------------------------------------------------
>> +
>> +    DEFAULT REL
>> +    SECTION .text
>> +
>> +;------------------------------------------------------------------------------
>> +; VOID
>> +; EFIAPI
>> +; AsmVmgExit (
>> +;   VOID
>> +;   );
>> +;------------------------------------------------------------------------------
>> +global ASM_PFX(AsmVmgExit)
>> +ASM_PFX(AsmVmgExit):
>> +    rep; vmmcall
>> +    ret
>> +
>> --
>> 2.17.1
> 

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

* Re: [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support
  2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
                   ` (27 preceding siblings ...)
  2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
@ 2019-08-21 14:17 ` Laszlo Ersek
  28 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:17 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

Hi Tom,

On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> This patch series provides support for running EDK2/OVMF under SEV-ES.
> 
> Secure Encrypted Virtualization - Encrypted State (SEV-ES) expands on the
> SEV support to protect the guest register state from the hypervisor. See
> "AMD64 Architecture Programmer's Manual Volume 2: System Programming",
> section "15.35 Encrypted State (SEV-ES)" [1].
> 
> In order to allow a hypervisor to perform functions on behalf of a guest,
> there is architectural support for notifying a guest's operating system
> when certain types of VMEXITs are about to occur. This allows the guest to
> selectively share information with the hypervisor to satisfy the requested
> function. The notification is performed using a new exception, the VMM
> Communication exception (#VC). The information is shared through the
> Guest-Hypervisor Communication Block (GHCB) using the VMGEXIT instruction.
> The GHCB format and the protocol for using it is documented in "SEV-ES
> Guest-Hypervisor Communication Block Standardization" [2].
> 
> The main areas of the EDK2 code that are updated to support SEV-ES are
> around the exception handling support and the AP boot support.
> 
> Exception support is required starting in Sec, continuing through Pei
> and into Dxe in order to handle #VC exceptions that are generated.  Each
> AP requires it's own GHCB page as well as a page to hold values specific
> to that AP.
> 
> AP booting poses some interesting challenges. The INIT-SIPI-SIPI sequence
> is typically used to boot the APs. However, the hypervisor is not allowed
> to update the guest registers. The GHCB document [2] talks about how SMP
> booting under SEV-ES is performed.
> 
> Since the GHCB page must be a shared (unencrypted) page, the processor
> must be running in long mode in order for the guest and hypervisor to
> communicate with each other. As a result, SEV-ES is only supported under
> the X64 architecture.
> 
> [1] https://www.amd.com/system/files/TechDocs/24593.pdf
> [2] https://developer.amd.com/wp-content/resources/56421.pdf
> [3] https://github.com/AMDESE/ovmf/tree/sev-es-v6

some very high level comments first.

(1) If there is any way, please avoid modifying multiple top-level
directories in a single patch. For example, a patch that currently
modifies both OvmfPkg and UefiCpuPkg, should be split in at least two,
but possibly three, parts. Otherwise, it becomes very difficult to
isolate reviewer responsibilities.

Furthermore, if you can split changes even inside a top-level package
directory, along module boundaries (such that a patch only modify a
single library instance or a driver module, if possible), that's
appreciated.

Clearly this would result in an even larger number of patches in the
series -- for which reason it's usually good to split the series into
"waves" (smaller series). Of course whenever you post a wave, you should
have a functional "whole" (a full stack of waves) in your local tree.
But posting smaller waves is helpful for reviewers (speaking generally),
and the tail of the full work might undergo quite significant updates
due to changes requested for the front.


(2) Please pass "--stat=1000" to git-format-patch. (The additional
"--stat-graph-width=20" option should already be present in your config,
persistently, from running SetupGit.py.) Otherwise, pathnames will be
truncated on the left in the diffstat sections, and that's quite
distracting.


(3) Please consider using "BaseTools/Scripts/GetMaintainer.py", for
determining the set of reviewers for each patch in isolation. Please use
explicit "Cc:" tags in the commit messages. The cover letter should
contain a unified "Cc:" list, also explicitly.


(4) As a general rule, any new memory areas that you access during SEC
and PEI by constant addresses (PCDs) must be considered for S3 resume.
These areas should be reserved from the OS, so that the OS not store
data there, which we'd overwrite during S3. It is also necessary to
guarantee that we never read data from such an area before writing to it
-- in S3, we must not consume any data planted by the OS. So, we should
protect a well-meaning OS during S3, and thwart a malicious OS.

This applies to the new ranges you introduce in [FD.MEMFD]. The current
areas are all covered by PlatformPei explicitly. For details, please
refer to the following document (it could be somewhat out of date, but
the general point stands):

http://www.linux-kvm.org/downloads/lersek/ovmf-whitepaper-c770f8c.txt

section "A comprehensive memory map of OVMF" -- look for the part saying
"With regard to RAM that is statically used by OVMF, ...".

It's OK if S3 support is out of scope for this work. Even in that case,
the life cycles of the new memory ranges should be investigated and
documented explicitly. If S3 is not to be supported with SEV-ES, then
the S3Verification() function should catch that.


(5) Specifically for the SEC GHCB range: can it be carved out of the
32KB gap at 0x80_8000, i.e. without shuffling around preexistent areas?


(6) Please file a BZ (Product = TianoCore Feature Request) in the
TianoCore bugzilla instance, and assign it to yourself. The patches
should all reference the BZ (in the commit message). The bugzilla should
please contain a high level description of the feature (more or less the
current cover letter). In addition, whenever a new version or wave of
the work is posted to edk2-devel, a mailing list URL should be captured
in the BZ, so that in a few months or years distance, we can see the
posted versions under a single ticket.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-08-21 14:21   ` Laszlo Ersek
  2019-08-21 21:25     ` Lendacky, Thomas
  2019-08-21 21:51     ` Jordan Justen
  0 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:21 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Currently, the OVMF code relies on the hypervisor to enable the cache
> support on the processor in order to improve the boot speed. However,
> with SEV-ES, the hypervisor is not allowed to change the CR0 register
> to enable caching.
> 
> Update the OVMF Sec support to enable caching in order to improve the
> boot speed.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/Sec/SecMain.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index 3914355cd17b..2448be0cd408 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>  
>    ProcessLibraryConstructorList (NULL, NULL);
>  
> +  //
> +  // Enable caching
> +  //
> +  AsmEnableCache ();
> +
>    DEBUG ((EFI_D_INFO,
>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>      (UINT32)(UINTN)BootFv,
> 

This makes me uncomfortable. There used to be problems related to
caching when VFIO device assignment were used. My concern is admittedly
vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
"well what could break here", I'd answer "you never know, and the burden
of proof is not on me". :) Can we make this change conditional on SEV-ES?

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-08-21 14:25   ` Laszlo Ersek
  2019-08-21 21:29     ` Lendacky, Thomas
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:25 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> A GHCB page is needed during the Sec phase, so this new page must be
> created.  Since the GHCB must be marked as an un-encrypted, or shared,
> page, an additional pagetable page is required so break down the 2MB
> region where the GHCB page lives into 4K pagetable entries.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkg.dec                        |  5 +++
>  OvmfPkg/OvmfPkgX64.fdf                     | 11 ++++---
>  OvmfPkg/PlatformPei/PlatformPei.inf        |  2 ++
>  OvmfPkg/ResetVector/ResetVector.inf        |  2 ++
>  UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
>  OvmfPkg/ResetVector/Ia32/PageTables64.asm  | 37 +++++++++++++++++++++-
>  OvmfPkg/ResetVector/ResetVector.nasmb      |  2 +-
>  7 files changed, 81 insertions(+), 6 deletions(-)

I've skipped patches 02 and 03 for now, because I'll have to go through
them with a fine toothed comb -- in a subsequent submission, most
probably. I'm just trying to provide formal comments, so that I do the
actual review more easily, later.

As I requested under the blurb, this patch should be split in at least
three parts, if possible -- OvmfPkg/PlatformPei, OvmfPkg/ResetVector,
UefiCpuPkg. (The DEC and FDF changes can be kept squashed with the
OvmfPkg patch that seems more suitable for that.)

... Having said that, why do you add PCDs to the PlatformPei INF file?
The code in PlatformPei doesn't change. Could be a leftover from an
earlier (abandoned) approach.

Thanks
Laszlo

> 
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 9640360f6245..2ead9a944af4 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
>    #  The value should be a multiple of 4KB.
>    gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>  
> +  ## Specify the GHCB base address and size.
> +  #  The value should be a multiple of 4KB for each.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
> +
>  [PcdsDynamic, PcdsDynamicEx]
>    gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 74407072563b..2a2427092382 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -67,13 +67,16 @@ [FD.MEMFD]
>  BlockSize     = 0x10000
>  NumBlocks     = 0xC0
>  
> -0x000000|0x006000
> +0x000000|0x007000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>  
> -0x006000|0x001000
> -gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> -
>  0x007000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> +
> +0x008000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> +
> +0x009000|0x001000
>  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>  
>  0x010000|0x010000
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index d9fd9c8f05b3..aed1f64b7c93 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -72,6 +72,8 @@ [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
> index 960b47cd0797..d66f4dc29737 100644
> --- a/OvmfPkg/ResetVector/ResetVector.inf
> +++ b/OvmfPkg/ResetVector/ResetVector.inf
> @@ -37,3 +37,5 @@ [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> index 37b935dcdb30..55a5723e164e 100644
> --- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> +++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
> @@ -17,6 +17,34 @@
>  #ifndef __FAM17_MSR_H__
>  #define __FAM17_MSR_H__
>  
> +/**
> +  Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
> +
> +**/
> +#define MSR_SEV_ES_GHCB                    0xc0010130
> +
> +/**
> +  MSR information returned for #MSR_SEV_ES_GHCB
> +**/
> +typedef union {
> +  struct {
> +    UINT32  GhcbNegotiateBit:1;
> +
> +    UINT32  Reserved:31;
> +  } Bits;
> +
> +  struct {
> +    UINT8   Reserved[3];
> +    UINT8   SevEncryptionBitPos;
> +    UINT16  SevEsProtocolMin;
> +    UINT16  SevEsProtocolMax;
> +  } GhcbProtocol;
> +
> +  VOID    *Ghcb;
> +
> +  UINT64  GhcbPhysicalAddress;
> +} MSR_SEV_ES_GHCB_REGISTER;
> +
>  /**
>    Secure Encrypted Virtualization (SEV) status register
>  
> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> index c6071fe934de..fd4d5b1d8661 100644
> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> @@ -21,6 +21,11 @@ BITS    32
>  %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 + \
> @@ -120,7 +125,7 @@ SevNotActive:
>      ; more permanent location by DxeIpl.
>      ;
>  
> -    mov     ecx, 6 * 0x1000 / 4
> +    mov     ecx, 7 * 0x1000 / 4
>      xor     eax, eax
>  clearPageTablesMemoryLoop:
>      mov     dword[ecx * 4 + PT_ADDR (0) - 4], eax
> @@ -157,6 +162,36 @@ pageTableEntriesLoop:
>      mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
>      loop    pageTableEntriesLoop
>  
> +    ;
> +    ; The GHCB will live at 0x807000 (just after the page tables)
> +    ; and needs to be un-encrypted.  This requires the 2MB page
> +    ; (index 4 in the first 1GB page) for this range be broken down
> +    ; into 512 4KB pages.  All will be marked as encrypted, except
> +    ; for the GHCB.
> +    ;
> +    mov     ecx, 4
> +    mov     eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
> +    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
> +
> +    mov     ecx, 512
> +pageTableEntries4kLoop:
> +    mov     eax, ecx
> +    dec     eax
> +    shl     eax, 12
> +    add     eax, 0x800000
> +    add     eax, PAGE_4K_PDE_ATTR
> +    mov     [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
> +    mov     [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
> +    loop    pageTableEntries4kLoop
> +
> +    ;
> +    ; Clear the encryption bit from the GHCB entry (index 7 in the
> +    ; new PTE table - (0x807000 - 0x800000) >> 12).
> +    ;
> +    mov     ecx, 7
> +    xor     edx, edx
> +    mov     [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
> +
>      ;
>      ; Set CR3 now that the paging structures are available
>      ;
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 3b213cd05ab2..56d9b86ed943 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -49,7 +49,7 @@
>  %ifdef ARCH_X64
>    #include <AutoGen.h>
>  
> -  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
> +  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
>      %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>    %endif
>  
> 


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

* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-08-21 14:31   ` Laszlo Ersek
  2019-08-21 21:42     ` Lendacky, Thomas
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 14:31 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Allocate memory for the GHCB pages during SEV initialization for use
> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
> are created without the encryption bit set.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
>  OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
>  OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
>  .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
>  .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
>  .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
>  .../MemEncryptSevLibInternal.c                |  1 -
>  .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
>  OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
>  11 files changed, 164 insertions(+), 23 deletions(-)

Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).

In addition, MdeModulePkg content must not depend on UefiCpuPkg content
-- if modules under both packages need to consume a new PCD, then the
PCD should be declared under MdeModulePkg. The rough dependency order is:

- MdePkg (must be self-contained)
- MdeModulePkg (may consume MdePkg)
- UefiCpuPkg (may consume everything above, to my knowledge)
- OvmfPkg (may consume everything above)

Thanks
Laszlo

> 
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
> index 6ddf0cd22466..4d5a2593cf13 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dec
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
> @@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
>    # @ValidRange  0x80000001 | 0 - 1
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
>  
> +  ## Contains the GHCB page allocation information.<BR><BR>
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
> +
>  [UserExtensions.TianoCore."ExtraFiles"]
>    UefiCpuPkgExtra.uni
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index dda8dac18441..d6fc7cdf7da8 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -569,6 +569,10 @@ [PcdsDynamicDefault]
>    # Set memory encryption mask
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>  
> +  # Set GHCB base address for SEV-ES
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
> +
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index abc3217b0179..b994398633e3 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
>  
>  [Packages.ARM, Packages.AARCH64]
>    ArmPkg/ArmPkg.dec
> @@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase                                 ## CONSUMES
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize                                 ## CONSUMES
>  
>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index aed1f64b7c93..f53195e6dda5 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -102,6 +102,8 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
>  
>  [FixedPcd]
>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 2d0493f109e8..6b7c38a441d6 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -201,6 +201,8 @@ EnableExecuteDisableBit (
>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>    @param[in]      StackBase             Stack base address.
>    @param[in]      StackSize             Stack size.
> +  @param[in]      GhcbBase              GHCB page area base address.
> +  @param[in]      GhcbSize              GHCB page area size.
>  
>  **/
>  VOID
> @@ -208,7 +210,9 @@ Split2MPageTo4K (
>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>    IN OUT UINT64                         *PageEntry2M,
>    IN EFI_PHYSICAL_ADDRESS               StackBase,
> -  IN UINTN                              StackSize
> +  IN UINTN                              StackSize,
> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
> +  IN UINTN                              GhcbSize
>    );
>  
>  /**
> @@ -217,6 +221,8 @@ Split2MPageTo4K (
>  
>    @param[in] StackBase  Stack base address.
>    @param[in] StackSize  Stack size.
> +  @param[in] GhcbBase   GHCB page area base address.
> +  @param[in] GhcbSize   GHCB page area size.
>  
>    @return The address of 4 level page map.
>  
> @@ -224,7 +230,9 @@ Split2MPageTo4K (
>  UINTN
>  CreateIdentityMappingPageTables (
>    IN EFI_PHYSICAL_ADDRESS   StackBase,
> -  IN UINTN                  StackSize
> +  IN UINTN                  StackSize,
> +  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
> +  IN UINTN                  GhcbkSize
>    );
>  
>  
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index 172d7cd1c60c..630a3503f6ba 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
>          //
>          // Need to split this 2M page that covers stack range.
>          //
> -        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> +        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
>        } else {
>          //
>          // Fill in the Page Directory entries
> @@ -278,7 +278,7 @@ HandOffToDxeCore (
>      //
>      // Create page table and save PageMapLevel4 to CR3
>      //
> -    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
> +    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
>  
>      //
>      // End of PEI phase signal
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> index 2867610bff4d..77da20e5c5c5 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
> @@ -35,6 +35,8 @@ HandOffToDxeCore (
>    UINT32                          Index;
>    EFI_VECTOR_HANDOFF_INFO         *VectorInfo;
>    EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
> +  VOID                            *GhcbBase;
> +  UINTN                           GhcbSize;
>  
>    if (IsNullDetectionEnabled ()) {
>      ClearFirst4KPage (HobList.Raw);
> @@ -77,12 +79,19 @@ HandOffToDxeCore (
>    TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
>    TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
>  
> +  //
> +  // Get the address and size of the GHCB pages
> +  //
> +  GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
> +  GhcbSize = PcdGet64 (PcdGhcbSize);
> +
>    PageTables = 0;
>    if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
>      //
>      // Create page table and save PageMapLevel4 to CR3
>      //
> -    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
> +    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
> +                                                  (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
>    } else {
>      //
>      // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index edc38e4525c4..b3c3c3276e6a 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -180,6 +180,8 @@ EnableExecuteDisableBit (
>    @param Size         Size of the given physical memory.
>    @param StackBase    Base address of stack.
>    @param StackSize    Size of stack.
> +  @param GhcbBase     Base address of GHCB pages.
> +  @param GhcbSize     Size of GHCB area.
>  
>    @retval TRUE      Page table should be split.
>    @retval FALSE     Page table should not be split.
> @@ -189,7 +191,9 @@ ToSplitPageTable (
>    IN EFI_PHYSICAL_ADDRESS               Address,
>    IN UINTN                              Size,
>    IN EFI_PHYSICAL_ADDRESS               StackBase,
> -  IN UINTN                              StackSize
> +  IN UINTN                              StackSize,
> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
> +  IN UINTN                              GhcbSize
>    )
>  {
>    if (IsNullDetectionEnabled () && Address == 0) {
> @@ -208,6 +212,12 @@ ToSplitPageTable (
>      }
>    }
>  
> +  if (GhcbBase) {
> +    if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
> +      return TRUE;
> +    }
> +  }
> +
>    return FALSE;
>  }
>  /**
> @@ -321,6 +331,8 @@ AllocatePageTableMemory (
>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>    @param[in]      StackBase             Stack base address.
>    @param[in]      StackSize             Stack size.
> +  @param[in]      GhcbBase              GHCB page area base address.
> +  @param[in]      GhcbSize              GHCB page area size.
>  
>  **/
>  VOID
> @@ -328,7 +340,9 @@ Split2MPageTo4K (
>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>    IN OUT UINT64                         *PageEntry2M,
>    IN EFI_PHYSICAL_ADDRESS               StackBase,
> -  IN UINTN                              StackSize
> +  IN UINTN                              StackSize,
> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
> +  IN UINTN                              GhcbSize
>    )
>  {
>    EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
> @@ -354,7 +368,12 @@ Split2MPageTo4K (
>      //
>      // Fill in the Page Table entries
>      //
> -    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
> +    if (!GhcbBase
> +        || (PhysicalAddress4K < GhcbBase)
> +        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
> +      PageTableEntry->Uint64 |= AddressEncMask;
> +    }
>      PageTableEntry->Bits.ReadWrite = 1;
>  
>      if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
> @@ -382,6 +401,8 @@ Split2MPageTo4K (
>    @param[in, out] PageEntry1G           Pointer to 1G page entry.
>    @param[in]      StackBase             Stack base address.
>    @param[in]      StackSize             Stack size.
> +  @param[in]      GhcbBase              GHCB page area base address.
> +  @param[in]      GhcbSize              GHCB page area size.
>  
>  **/
>  VOID
> @@ -389,7 +410,9 @@ Split1GPageTo2M (
>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>    IN OUT UINT64                         *PageEntry1G,
>    IN EFI_PHYSICAL_ADDRESS               StackBase,
> -  IN UINTN                              StackSize
> +  IN UINTN                              StackSize,
> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
> +  IN UINTN                              GhcbSize
>    )
>  {
>    EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
> @@ -412,11 +435,11 @@ Split1GPageTo2M (
>  
>    PhysicalAddress2M = PhysicalAddress;
>    for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
> -    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
> +    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>        //
>        // Need to split this 2M page that covers NULL or stack range.
>        //
> -      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> +      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>      } else {
>        //
>        // Fill in the Page Directory entries
> @@ -615,6 +638,8 @@ EnablePageTableProtection (
>  
>    @param[in] StackBase  Stack base address.
>    @param[in] StackSize  Stack size.
> +  @param[in] GhcbBase   GHCB base address.
> +  @param[in] GhcbSize   GHCB size.
>  
>    @return The address of 4 level page map.
>  
> @@ -622,7 +647,9 @@ EnablePageTableProtection (
>  UINTN
>  CreateIdentityMappingPageTables (
>    IN EFI_PHYSICAL_ADDRESS   StackBase,
> -  IN UINTN                  StackSize
> +  IN UINTN                  StackSize,
> +  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
> +  IN UINTN                  GhcbSize
>    )
>  {
>    UINT32                                        RegEax;
> @@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
>        PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
>  
>        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
> -        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
> -          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
> +        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
> +          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>          } else {
>            //
>            // Fill in the Page Directory entries
> @@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
>          PageDirectoryPointerEntry->Bits.Present = 1;
>  
>          for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
> -          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
> +          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>              //
>              // Need to split this 2M page that covers NULL or stack range.
>              //
> -            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
> +            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>            } else {
>              //
>              // Fill in the Page Directory entries
> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> index 9c1d68e017fe..1dce01dd7546 100644
> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
> @@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
>    return mSevStatus;
>  }
>  
> -
>  /**
>    Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
>    Save State Map.
> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> index 5e110c84ff81..3a4f223f8a86 100644
> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
> @@ -183,6 +183,8 @@ AllocatePageTableMemory (
>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>    @param[in]      StackBase             Stack base address.
>    @param[in]      StackSize             Stack size.
> +  @param[in]      GhcbBase              GHCB page area base address.
> +  @param[in]      GhcbSize              GHCB page area size.
>  
>  **/
>  STATIC
> @@ -191,7 +193,9 @@ Split2MPageTo4K (
>    IN        PHYSICAL_ADDRESS               PhysicalAddress,
>    IN  OUT   UINT64                        *PageEntry2M,
>    IN        PHYSICAL_ADDRESS               StackBase,
> -  IN        UINTN                          StackSize
> +  IN        UINTN                          StackSize,
> +  IN        PHYSICAL_ADDRESS               GhcbBase,
> +  IN        UINTN                          GhcbSize
>    )
>  {
>    PHYSICAL_ADDRESS                  PhysicalAddress4K;
> @@ -217,7 +221,12 @@ Split2MPageTo4K (
>      //
>      // Fill in the Page Table entries
>      //
> -    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
> +    if (!GhcbBase
> +        || (PhysicalAddress4K < GhcbBase)
> +        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
> +      PageTableEntry->Uint64 |= AddressEncMask;
> +    }
>      PageTableEntry->Bits.ReadWrite = 1;
>      PageTableEntry->Bits.Present = 1;
>      if ((PhysicalAddress4K >= StackBase) &&
> @@ -417,6 +426,8 @@ EnablePageTableProtection (
>    @param[in, out] PageEntry1G           Pointer to 1G page entry.
>    @param[in]      StackBase             Stack base address.
>    @param[in]      StackSize             Stack size.
> +  @param[in]      GhcbBase              GHCB page area base address.
> +  @param[in]      GhcbSize              GHCB page area size.
>  
>  **/
>  STATIC
> @@ -425,7 +436,9 @@ Split1GPageTo2M (
>    IN          PHYSICAL_ADDRESS               PhysicalAddress,
>    IN  OUT     UINT64                         *PageEntry1G,
>    IN          PHYSICAL_ADDRESS               StackBase,
> -  IN          UINTN                          StackSize
> +  IN          UINTN                          StackSize,
> +  IN          PHYSICAL_ADDRESS               GhcbBase,
> +  IN          UINTN                          GhcbSize
>    )
>  {
>    PHYSICAL_ADDRESS                  PhysicalAddress2M;
> @@ -450,8 +463,10 @@ Split1GPageTo2M (
>         (IndexOfPageDirectoryEntries++,
>          PageDirectoryEntry++,
>          PhysicalAddress2M += SIZE_2MB)) {
> -    if ((PhysicalAddress2M < StackBase + StackSize) &&
> -        ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
> +    if (((PhysicalAddress2M < StackBase + StackSize) &&
> +         ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
> +        ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
> +         ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
>        //
>        // Need to split this 2M page that covers stack range.
>        //
> @@ -459,7 +474,9 @@ Split1GPageTo2M (
>          PhysicalAddress2M,
>          (UINT64 *)PageDirectoryEntry,
>          StackBase,
> -        StackSize
> +        StackSize,
> +        GhcbBase,
> +        GhcbSize
>          );
>      } else {
>        //
> @@ -714,6 +731,8 @@ SetMemoryEncDec (
>            (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
>            (UINT64 *)PageDirectory1GEntry,
>            0,
> +          0,
> +          0,
>            0
>            );
>          continue;
> @@ -768,6 +787,8 @@ SetMemoryEncDec (
>              (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
>              (UINT64 *)PageDirectory2MEntry,
>              0,
> +            0,
> +            0,
>              0
>              );
>            continue;
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 2ae8126ccf8a..84896d4681f9 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -16,9 +16,68 @@
>  #include <PiPei.h>
>  #include <Register/Amd/Cpuid.h>
>  #include <Register/Cpuid.h>
> +#include <Register/Amd/Msr.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
>  
>  #include "Platform.h"
>  
> +/**
> +
> +  Initialize SEV-ES support if running an SEV-ES guest.
> +
> +  **/
> +STATIC
> +VOID
> +AmdSevEsInitialize (
> +  VOID
> +  )
> +{
> +  VOID              *GhcbBase;
> +  PHYSICAL_ADDRESS  GhcbBasePa;
> +  UINTN             GhcbPageCount;
> +  RETURN_STATUS     DecryptStatus, PcdStatus;
> +
> +  if (!MemEncryptSevEsIsEnabled ()) {
> +    return;
> +  }
> +
> +  GhcbPageCount = mMaxCpuCount;
> +
> +  //
> +  // Allocate GHCB pages.
> +  //
> +  GhcbBase = AllocatePages (GhcbPageCount);
> +  ASSERT (GhcbBase);
> +
> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> +  DecryptStatus = MemEncryptSevClearPageEncMask (
> +    0,
> +    GhcbBasePa,
> +    GhcbPageCount,
> +    TRUE
> +    );
> +  ASSERT_RETURN_ERROR (DecryptStatus);
> +
> +  BuildMemoryAllocationHob (
> +    GhcbBasePa,
> +    EFI_PAGES_TO_SIZE (GhcbPageCount),
> +    EfiBootServicesData
> +    );
> +
> +  SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
> +
> +  PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +  PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
> +
> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
> +}
> +
>  /**
>  
>    Function checks if SEV support is available, if present then it sets
> @@ -89,4 +148,9 @@ AmdSevInitialize (
>        EfiBootServicesData                // MemoryType
>        );
>    }
> +
> +  //
> +  // Check and perform SEV-ES initialization if required.
> +  //
> +  AmdSevEsInitialize ();
>  }
> 


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

* Re: [edk2-devel] [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-08-21 15:44   ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-21 15:44 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/19/19 23:35, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> The SEV support will clear the C-bit from non-RAM areas.  The early GDT
> lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
> will be read as un-encrypted even though it is encrypted. This will result
> in a failure to be able to handle the exception.
> 
> Move the GDT into RAM so it can be accessed without error when running as
> an SEV-ES guest.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/PlatformPei/AmdSev.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 87ac842a1590..5f4983fd36d8 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -37,6 +37,8 @@ AmdSevEsInitialize (
>    PHYSICAL_ADDRESS  GhcbBasePa;
>    UINTN             GhcbPageCount;
>    RETURN_STATUS     DecryptStatus, PcdStatus;
> +  IA32_DESCRIPTOR   Gdtr;
> +  VOID              *Gdt;
>  
>    if (!MemEncryptSevEsIsEnabled ()) {
>      return;
> @@ -76,6 +78,20 @@ AmdSevEsInitialize (
>    DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
>  
>    AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
> +
> +  //
> +  // The SEV support will clear the C-bit from the non-RAM areas. Since
> +  // the GDT initially lives in that area and it will be read when a #VC
> +  // exception happens, it needs to be moved to RAM for an SEV-ES guest.
> +  //
> +  AsmReadGdtr (&Gdtr);
> +
> +  Gdt = AllocatePool (Gdtr.Limit + 1);
> +  ASSERT (Gdt);
> +
> +  CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
> +  Gdtr.Base = (UINTN) Gdt;
> +  AsmWriteGdtr (&Gdtr);
>  }
>  
>  /**
> 

This doesn't look safe enough to me.

AllocatePool() in the PEI phase means the creation of an
EFI_HOB_TYPE_MEMORY_POOL HOB. The data allocated lives inside the HOB.
According to the PI spec v1.7, volume 3, section "4.5.2 HOB Construction
Rules":

  3. HOBs may be relocated in system memory by the HOB consumer phase.
     HOBs must not contain pointers to other data in the HOB list,
     including that in other HOBs. The table must be able to be copied
     without requiring internal pointer adjustment.

Additionally, in section "5.9 Memory Pool HOB",

  [...] The HOB consumer phase should be able to ignore these HOBs [...]

which seems to imply that the HOB might not survive into DXE at all (the
memory could be released and repurposed).

I don't feel good about pointing the GDTR into such a possibly ephemeral
HOB, even if we reload the GDTR with a different GDT address at a later
time.

Instead, I suggest AllocatePages().

AmdSevEsInitialize() is invoked as part of AmdSevInitialize(), which in
turn is invoked after PublishPeiMemory() returns. Therefore, using
AllocatePages() instead of AllocatePool() should be safe -- the address
produced by AllocatePages() should be stable.

Namely, in PI v1.7, volume 1, section "4.6 PEI Memory Services",
AllocatePages() is specified as:

  [...] Allocation made prior to permanent memory will be migrated to
  permanent memory [...] After InstallPeiMemory() is called, PEI will
  allocate pages within the region of memory provided by
  InstallPeiMemory() service [...]

The edk2 code agrees -- PublishPeiMemory() in OVMF's PlatformPei
exercises PeiInstallPeiMemory()
[MdeModulePkg/Core/Pei/Memory/MemoryServices.c], which sets
"SwitchStackSignal". Although actual RAM migration doesn't happen until
after PlatformPei exits, PeiAllocatePages() explicitly looks for

  (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal)

so it will do the right thing. As a result, AllocatePages() *before*
actual RAM migration (from temporary to permanent), but *after*
PeiInstallPeiMemory(), will allocate permanent memory.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-21 14:21   ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:25     ` Lendacky, Thomas
  2019-08-21 21:51     ` Jordan Justen
  1 sibling, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:25 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 8/21/19 9:21 AM, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> Currently, the OVMF code relies on the hypervisor to enable the cache
>> support on the processor in order to improve the boot speed. However,
>> with SEV-ES, the hypervisor is not allowed to change the CR0 register
>> to enable caching.
>>
>> Update the OVMF Sec support to enable caching in order to improve the
>> boot speed.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/Sec/SecMain.c | 5 +++++
>>  1 file changed, 5 insertions(+)
>>
>> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
>> index 3914355cd17b..2448be0cd408 100644
>> --- a/OvmfPkg/Sec/SecMain.c
>> +++ b/OvmfPkg/Sec/SecMain.c
>> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>>  
>>    ProcessLibraryConstructorList (NULL, NULL);
>>  
>> +  //
>> +  // Enable caching
>> +  //
>> +  AsmEnableCache ();
>> +
>>    DEBUG ((EFI_D_INFO,
>>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>>      (UINT32)(UINTN)BootFv,
>>
> 
> This makes me uncomfortable. There used to be problems related to
> caching when VFIO device assignment were used. My concern is admittedly
> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> "well what could break here", I'd answer "you never know, and the burden
> of proof is not on me". :) Can we make this change conditional on SEV-ES?
> 

I'll look into that. Anything is possible, just might have to read an MSR
at this stage.

Thanks,
Tom

> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-08-21 14:25   ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:29     ` Lendacky, Thomas
  0 siblings, 0 replies; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:29 UTC (permalink / raw)
  To: devel@edk2.groups.io, lersek@redhat.com
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 8/21/19 9:25 AM, Laszlo Ersek via Groups.Io wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> A GHCB page is needed during the Sec phase, so this new page must be
>> created.  Since the GHCB must be marked as an un-encrypted, or shared,
>> page, an additional pagetable page is required so break down the 2MB
>> region where the GHCB page lives into 4K pagetable entries.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkg.dec                        |  5 +++
>>  OvmfPkg/OvmfPkgX64.fdf                     | 11 ++++---
>>  OvmfPkg/PlatformPei/PlatformPei.inf        |  2 ++
>>  OvmfPkg/ResetVector/ResetVector.inf        |  2 ++
>>  UefiCpuPkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++
>>  OvmfPkg/ResetVector/Ia32/PageTables64.asm  | 37 +++++++++++++++++++++-
>>  OvmfPkg/ResetVector/ResetVector.nasmb      |  2 +-
>>  7 files changed, 81 insertions(+), 6 deletions(-)
> 
> I've skipped patches 02 and 03 for now, because I'll have to go through
> them with a fine toothed comb -- in a subsequent submission, most
> probably. I'm just trying to provide formal comments, so that I do the
> actual review more easily, later.
> 
> As I requested under the blurb, this patch should be split in at least
> three parts, if possible -- OvmfPkg/PlatformPei, OvmfPkg/ResetVector,
> UefiCpuPkg. (The DEC and FDF changes can be kept squashed with the
> OvmfPkg patch that seems more suitable for that.)

Ok.

> 
> ... Having said that, why do you add PCDs to the PlatformPei INF file?
> The code in PlatformPei doesn't change. Could be a leftover from an
> earlier (abandoned) approach.

Yeah, most likely. I'll remove that.

Thanks,
Tom

> 
> Thanks
> Laszlo
> 
>>
>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
>> index 9640360f6245..2ead9a944af4 100644
>> --- a/OvmfPkg/OvmfPkg.dec
>> +++ b/OvmfPkg/OvmfPkg.dec
>> @@ -218,6 +218,11 @@ [PcdsFixedAtBuild]
>>    #  The value should be a multiple of 4KB.
>>    gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>>  
>> +  ## Specify the GHCB base address and size.
>> +  #  The value should be a multiple of 4KB for each.
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x32
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x33
>> +
>>  [PcdsDynamic, PcdsDynamicEx]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index 74407072563b..2a2427092382 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -67,13 +67,16 @@ [FD.MEMFD]
>>  BlockSize     = 0x10000
>>  NumBlocks     = 0xC0
>>  
>> -0x000000|0x006000
>> +0x000000|0x007000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>>  
>> -0x006000|0x001000
>> -gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>> -
>>  0x007000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> +
>> +0x008000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>> +
>> +0x009000|0x001000
>>  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>>  
>>  0x010000|0x010000
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index d9fd9c8f05b3..aed1f64b7c93 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -72,6 +72,8 @@ [Pcd]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
>> index 960b47cd0797..d66f4dc29737 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.inf
>> +++ b/OvmfPkg/ResetVector/ResetVector.inf
>> @@ -37,3 +37,5 @@ [Pcd]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> diff --git a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> index 37b935dcdb30..55a5723e164e 100644
>> --- a/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> +++ b/UefiCpuPkg/Include/Register/Amd/Fam17Msr.h
>> @@ -17,6 +17,34 @@
>>  #ifndef __FAM17_MSR_H__
>>  #define __FAM17_MSR_H__
>>  
>> +/**
>> +  Secure Encrypted Virtualization - Encrypted State (SEV-ES) GHCB register
>> +
>> +**/
>> +#define MSR_SEV_ES_GHCB                    0xc0010130
>> +
>> +/**
>> +  MSR information returned for #MSR_SEV_ES_GHCB
>> +**/
>> +typedef union {
>> +  struct {
>> +    UINT32  GhcbNegotiateBit:1;
>> +
>> +    UINT32  Reserved:31;
>> +  } Bits;
>> +
>> +  struct {
>> +    UINT8   Reserved[3];
>> +    UINT8   SevEncryptionBitPos;
>> +    UINT16  SevEsProtocolMin;
>> +    UINT16  SevEsProtocolMax;
>> +  } GhcbProtocol;
>> +
>> +  VOID    *Ghcb;
>> +
>> +  UINT64  GhcbPhysicalAddress;
>> +} MSR_SEV_ES_GHCB_REGISTER;
>> +
>>  /**
>>    Secure Encrypted Virtualization (SEV) status register
>>  
>> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> index c6071fe934de..fd4d5b1d8661 100644
>> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> @@ -21,6 +21,11 @@ BITS    32
>>  %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 + \
>> @@ -120,7 +125,7 @@ SevNotActive:
>>      ; more permanent location by DxeIpl.
>>      ;
>>  
>> -    mov     ecx, 6 * 0x1000 / 4
>> +    mov     ecx, 7 * 0x1000 / 4
>>      xor     eax, eax
>>  clearPageTablesMemoryLoop:
>>      mov     dword[ecx * 4 + PT_ADDR (0) - 4], eax
>> @@ -157,6 +162,36 @@ pageTableEntriesLoop:
>>      mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
>>      loop    pageTableEntriesLoop
>>  
>> +    ;
>> +    ; The GHCB will live at 0x807000 (just after the page tables)
>> +    ; and needs to be un-encrypted.  This requires the 2MB page
>> +    ; (index 4 in the first 1GB page) for this range be broken down
>> +    ; into 512 4KB pages.  All will be marked as encrypted, except
>> +    ; for the GHCB.
>> +    ;
>> +    mov     ecx, 4
>> +    mov     eax, PT_ADDR (0x6000) + PAGE_PDP_ATTR
>> +    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
>> +
>> +    mov     ecx, 512
>> +pageTableEntries4kLoop:
>> +    mov     eax, ecx
>> +    dec     eax
>> +    shl     eax, 12
>> +    add     eax, 0x800000
>> +    add     eax, PAGE_4K_PDE_ATTR
>> +    mov     [ecx * 8 + PT_ADDR (0x6000 - 8)], eax
>> +    mov     [(ecx * 8 + PT_ADDR (0x6000 - 8)) + 4], edx
>> +    loop    pageTableEntries4kLoop
>> +
>> +    ;
>> +    ; Clear the encryption bit from the GHCB entry (index 7 in the
>> +    ; new PTE table - (0x807000 - 0x800000) >> 12).
>> +    ;
>> +    mov     ecx, 7
>> +    xor     edx, edx
>> +    mov     [(ecx * 8 + PT_ADDR (0x6000)) + 4], edx
>> +
>>      ;
>>      ; Set CR3 now that the paging structures are available
>>      ;
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 3b213cd05ab2..56d9b86ed943 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -49,7 +49,7 @@
>>  %ifdef ARCH_X64
>>    #include <AutoGen.h>
>>  
>> -  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x6000)
>> +  %if (FixedPcdGet32 (PcdOvmfSecPageTablesSize) != 0x7000)
>>      %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>>    %endif
>>  
>>
> 
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-21 14:31   ` [edk2-devel] " Laszlo Ersek
@ 2019-08-21 21:42     ` Lendacky, Thomas
  2019-08-22 14:12       ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-21 21:42 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 8/21/19 9:31 AM, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> Allocate memory for the GHCB pages during SEV initialization for use
>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>> are created without the encryption bit set.
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
>>  OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
>>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
>>  OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
>>  .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
>>  .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
>>  .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
>>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
>>  .../MemEncryptSevLibInternal.c                |  1 -
>>  .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
>>  OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
>>  11 files changed, 164 insertions(+), 23 deletions(-)
> 
> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
> 
> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
> -- if modules under both packages need to consume a new PCD, then the
> PCD should be declared under MdeModulePkg. The rough dependency order is:
> 
> - MdePkg (must be self-contained)
> - MdeModulePkg (may consume MdePkg)
> - UefiCpuPkg (may consume everything above, to my knowledge)
> - OvmfPkg (may consume everything above)
> 

Ok, thanks for the guidance.

Ideally, I just would like to modify the newly created page tables after
the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
or callback or notification service so that the main changes would be
limited to the OvmfPkg files and would that be acceptable?

Thanks,
Tom

> Thanks
> Laszlo
> 
>>
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>> index 6ddf0cd22466..4d5a2593cf13 100644
>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>> @@ -323,5 +323,9 @@ [PcdsDynamic, PcdsDynamicEx]
>>    # @ValidRange  0x80000001 | 0 - 1
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015
>>  
>> +  ## Contains the GHCB page allocation information.<BR><BR>
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0|UINT64|0x60000016
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0|UINT64|0x60000017
>> +
>>  [UserExtensions.TianoCore."ExtraFiles"]
>>    UefiCpuPkgExtra.uni
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index dda8dac18441..d6fc7cdf7da8 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -569,6 +569,10 @@ [PcdsDynamicDefault]
>>    # Set memory encryption mask
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>>  
>> +  # Set GHCB base address for SEV-ES
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase|0x0
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize|0x0
>> +
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> index abc3217b0179..b994398633e3 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>> @@ -52,6 +52,7 @@ [Sources.ARM, Sources.AARCH64]
>>  [Packages]
>>    MdePkg/MdePkg.dec
>>    MdeModulePkg/MdeModulePkg.dec
>> +  UefiCpuPkg/UefiCpuPkg.dec
>>  
>>  [Packages.ARM, Packages.AARCH64]
>>    ArmPkg/ArmPkg.dec
>> @@ -110,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase                                 ## CONSUMES
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize                                 ## CONSUMES
>>  
>>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index aed1f64b7c93..f53195e6dda5 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -102,6 +102,8 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbBase
>> +  gUefiCpuPkgTokenSpaceGuid.PcdGhcbSize
>>  
>>  [FixedPcd]
>>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> index 2d0493f109e8..6b7c38a441d6 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>> @@ -201,6 +201,8 @@ EnableExecuteDisableBit (
>>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>>    @param[in]      StackBase             Stack base address.
>>    @param[in]      StackSize             Stack size.
>> +  @param[in]      GhcbBase              GHCB page area base address.
>> +  @param[in]      GhcbSize              GHCB page area size.
>>  
>>  **/
>>  VOID
>> @@ -208,7 +210,9 @@ Split2MPageTo4K (
>>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>>    IN OUT UINT64                         *PageEntry2M,
>>    IN EFI_PHYSICAL_ADDRESS               StackBase,
>> -  IN UINTN                              StackSize
>> +  IN UINTN                              StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
>> +  IN UINTN                              GhcbSize
>>    );
>>  
>>  /**
>> @@ -217,6 +221,8 @@ Split2MPageTo4K (
>>  
>>    @param[in] StackBase  Stack base address.
>>    @param[in] StackSize  Stack size.
>> +  @param[in] GhcbBase   GHCB page area base address.
>> +  @param[in] GhcbSize   GHCB page area size.
>>  
>>    @return The address of 4 level page map.
>>  
>> @@ -224,7 +230,9 @@ Split2MPageTo4K (
>>  UINTN
>>  CreateIdentityMappingPageTables (
>>    IN EFI_PHYSICAL_ADDRESS   StackBase,
>> -  IN UINTN                  StackSize
>> +  IN UINTN                  StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
>> +  IN UINTN                  GhcbkSize
>>    );
>>  
>>  
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> index 172d7cd1c60c..630a3503f6ba 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>> @@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
>>          //
>>          // Need to split this 2M page that covers stack range.
>>          //
>> -        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> +        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
>>        } else {
>>          //
>>          // Fill in the Page Directory entries
>> @@ -278,7 +278,7 @@ HandOffToDxeCore (
>>      //
>>      // Create page table and save PageMapLevel4 to CR3
>>      //
>> -    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);
>> +    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
>>  
>>      //
>>      // End of PEI phase signal
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> index 2867610bff4d..77da20e5c5c5 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
>> @@ -35,6 +35,8 @@ HandOffToDxeCore (
>>    UINT32                          Index;
>>    EFI_VECTOR_HANDOFF_INFO         *VectorInfo;
>>    EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
>> +  VOID                            *GhcbBase;
>> +  UINTN                           GhcbSize;
>>  
>>    if (IsNullDetectionEnabled ()) {
>>      ClearFirst4KPage (HobList.Raw);
>> @@ -77,12 +79,19 @@ HandOffToDxeCore (
>>    TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
>>    TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
>>  
>> +  //
>> +  // Get the address and size of the GHCB pages
>> +  //
>> +  GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
>> +  GhcbSize = PcdGet64 (PcdGhcbSize);
>> +
>>    PageTables = 0;
>>    if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
>>      //
>>      // Create page table and save PageMapLevel4 to CR3
>>      //
>> -    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
>> +    PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
>> +                                                  (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
>>    } else {
>>      //
>>      // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> index edc38e4525c4..b3c3c3276e6a 100644
>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>> @@ -180,6 +180,8 @@ EnableExecuteDisableBit (
>>    @param Size         Size of the given physical memory.
>>    @param StackBase    Base address of stack.
>>    @param StackSize    Size of stack.
>> +  @param GhcbBase     Base address of GHCB pages.
>> +  @param GhcbSize     Size of GHCB area.
>>  
>>    @retval TRUE      Page table should be split.
>>    @retval FALSE     Page table should not be split.
>> @@ -189,7 +191,9 @@ ToSplitPageTable (
>>    IN EFI_PHYSICAL_ADDRESS               Address,
>>    IN UINTN                              Size,
>>    IN EFI_PHYSICAL_ADDRESS               StackBase,
>> -  IN UINTN                              StackSize
>> +  IN UINTN                              StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
>> +  IN UINTN                              GhcbSize
>>    )
>>  {
>>    if (IsNullDetectionEnabled () && Address == 0) {
>> @@ -208,6 +212,12 @@ ToSplitPageTable (
>>      }
>>    }
>>  
>> +  if (GhcbBase) {
>> +    if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
>> +      return TRUE;
>> +    }
>> +  }
>> +
>>    return FALSE;
>>  }
>>  /**
>> @@ -321,6 +331,8 @@ AllocatePageTableMemory (
>>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>>    @param[in]      StackBase             Stack base address.
>>    @param[in]      StackSize             Stack size.
>> +  @param[in]      GhcbBase              GHCB page area base address.
>> +  @param[in]      GhcbSize              GHCB page area size.
>>  
>>  **/
>>  VOID
>> @@ -328,7 +340,9 @@ Split2MPageTo4K (
>>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>>    IN OUT UINT64                         *PageEntry2M,
>>    IN EFI_PHYSICAL_ADDRESS               StackBase,
>> -  IN UINTN                              StackSize
>> +  IN UINTN                              StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
>> +  IN UINTN                              GhcbSize
>>    )
>>  {
>>    EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
>> @@ -354,7 +368,12 @@ Split2MPageTo4K (
>>      //
>>      // Fill in the Page Table entries
>>      //
>> -    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
>> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
>> +    if (!GhcbBase
>> +        || (PhysicalAddress4K < GhcbBase)
>> +        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
>> +      PageTableEntry->Uint64 |= AddressEncMask;
>> +    }
>>      PageTableEntry->Bits.ReadWrite = 1;
>>  
>>      if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
>> @@ -382,6 +401,8 @@ Split2MPageTo4K (
>>    @param[in, out] PageEntry1G           Pointer to 1G page entry.
>>    @param[in]      StackBase             Stack base address.
>>    @param[in]      StackSize             Stack size.
>> +  @param[in]      GhcbBase              GHCB page area base address.
>> +  @param[in]      GhcbSize              GHCB page area size.
>>  
>>  **/
>>  VOID
>> @@ -389,7 +410,9 @@ Split1GPageTo2M (
>>    IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
>>    IN OUT UINT64                         *PageEntry1G,
>>    IN EFI_PHYSICAL_ADDRESS               StackBase,
>> -  IN UINTN                              StackSize
>> +  IN UINTN                              StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS               GhcbBase,
>> +  IN UINTN                              GhcbSize
>>    )
>>  {
>>    EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
>> @@ -412,11 +435,11 @@ Split1GPageTo2M (
>>  
>>    PhysicalAddress2M = PhysicalAddress;
>>    for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
>> -    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize)) {
>> +    if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>>        //
>>        // Need to split this 2M page that covers NULL or stack range.
>>        //
>> -      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> +      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>>      } else {
>>        //
>>        // Fill in the Page Directory entries
>> @@ -615,6 +638,8 @@ EnablePageTableProtection (
>>  
>>    @param[in] StackBase  Stack base address.
>>    @param[in] StackSize  Stack size.
>> +  @param[in] GhcbBase   GHCB base address.
>> +  @param[in] GhcbSize   GHCB size.
>>  
>>    @return The address of 4 level page map.
>>  
>> @@ -622,7 +647,9 @@ EnablePageTableProtection (
>>  UINTN
>>  CreateIdentityMappingPageTables (
>>    IN EFI_PHYSICAL_ADDRESS   StackBase,
>> -  IN UINTN                  StackSize
>> +  IN UINTN                  StackSize,
>> +  IN EFI_PHYSICAL_ADDRESS   GhcbBase,
>> +  IN UINTN                  GhcbSize
>>    )
>>  {
>>    UINT32                                        RegEax;
>> @@ -734,8 +761,8 @@ CreateIdentityMappingPageTables (
>>        PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
>>  
>>        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
>> -        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
>> -          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
>> +        if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>> +          Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>>          } else {
>>            //
>>            // Fill in the Page Directory entries
>> @@ -763,11 +790,11 @@ CreateIdentityMappingPageTables (
>>          PageDirectoryPointerEntry->Bits.Present = 1;
>>  
>>          for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
>> -          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
>> +          if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
>>              //
>>              // Need to split this 2M page that covers NULL or stack range.
>>              //
>> -            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
>> +            Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
>>            } else {
>>              //
>>              // Fill in the Page Directory entries
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> index 9c1d68e017fe..1dce01dd7546 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c
>> @@ -109,7 +109,6 @@ MemEncryptSevIsEnabled (
>>    return mSevStatus;
>>  }
>>  
>> -
>>  /**
>>    Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
>>    Save State Map.
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> index 5e110c84ff81..3a4f223f8a86 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
>> @@ -183,6 +183,8 @@ AllocatePageTableMemory (
>>    @param[in, out] PageEntry2M           Pointer to 2M page entry.
>>    @param[in]      StackBase             Stack base address.
>>    @param[in]      StackSize             Stack size.
>> +  @param[in]      GhcbBase              GHCB page area base address.
>> +  @param[in]      GhcbSize              GHCB page area size.
>>  
>>  **/
>>  STATIC
>> @@ -191,7 +193,9 @@ Split2MPageTo4K (
>>    IN        PHYSICAL_ADDRESS               PhysicalAddress,
>>    IN  OUT   UINT64                        *PageEntry2M,
>>    IN        PHYSICAL_ADDRESS               StackBase,
>> -  IN        UINTN                          StackSize
>> +  IN        UINTN                          StackSize,
>> +  IN        PHYSICAL_ADDRESS               GhcbBase,
>> +  IN        UINTN                          GhcbSize
>>    )
>>  {
>>    PHYSICAL_ADDRESS                  PhysicalAddress4K;
>> @@ -217,7 +221,12 @@ Split2MPageTo4K (
>>      //
>>      // Fill in the Page Table entries
>>      //
>> -    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
>> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
>> +    if (!GhcbBase
>> +        || (PhysicalAddress4K < GhcbBase)
>> +        || (PhysicalAddress4K >= GhcbBase + GhcbSize)) {
>> +      PageTableEntry->Uint64 |= AddressEncMask;
>> +    }
>>      PageTableEntry->Bits.ReadWrite = 1;
>>      PageTableEntry->Bits.Present = 1;
>>      if ((PhysicalAddress4K >= StackBase) &&
>> @@ -417,6 +426,8 @@ EnablePageTableProtection (
>>    @param[in, out] PageEntry1G           Pointer to 1G page entry.
>>    @param[in]      StackBase             Stack base address.
>>    @param[in]      StackSize             Stack size.
>> +  @param[in]      GhcbBase              GHCB page area base address.
>> +  @param[in]      GhcbSize              GHCB page area size.
>>  
>>  **/
>>  STATIC
>> @@ -425,7 +436,9 @@ Split1GPageTo2M (
>>    IN          PHYSICAL_ADDRESS               PhysicalAddress,
>>    IN  OUT     UINT64                         *PageEntry1G,
>>    IN          PHYSICAL_ADDRESS               StackBase,
>> -  IN          UINTN                          StackSize
>> +  IN          UINTN                          StackSize,
>> +  IN          PHYSICAL_ADDRESS               GhcbBase,
>> +  IN          UINTN                          GhcbSize
>>    )
>>  {
>>    PHYSICAL_ADDRESS                  PhysicalAddress2M;
>> @@ -450,8 +463,10 @@ Split1GPageTo2M (
>>         (IndexOfPageDirectoryEntries++,
>>          PageDirectoryEntry++,
>>          PhysicalAddress2M += SIZE_2MB)) {
>> -    if ((PhysicalAddress2M < StackBase + StackSize) &&
>> -        ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
>> +    if (((PhysicalAddress2M < StackBase + StackSize) &&
>> +         ((PhysicalAddress2M + SIZE_2MB) > StackBase)) ||
>> +        ((PhysicalAddress2M < GhcbBase + GhcbSize) &&
>> +         ((PhysicalAddress2M + SIZE_2MB) > GhcbBase))) {
>>        //
>>        // Need to split this 2M page that covers stack range.
>>        //
>> @@ -459,7 +474,9 @@ Split1GPageTo2M (
>>          PhysicalAddress2M,
>>          (UINT64 *)PageDirectoryEntry,
>>          StackBase,
>> -        StackSize
>> +        StackSize,
>> +        GhcbBase,
>> +        GhcbSize
>>          );
>>      } else {
>>        //
>> @@ -714,6 +731,8 @@ SetMemoryEncDec (
>>            (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
>>            (UINT64 *)PageDirectory1GEntry,
>>            0,
>> +          0,
>> +          0,
>>            0
>>            );
>>          continue;
>> @@ -768,6 +787,8 @@ SetMemoryEncDec (
>>              (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
>>              (UINT64 *)PageDirectory2MEntry,
>>              0,
>> +            0,
>> +            0,
>>              0
>>              );
>>            continue;
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 2ae8126ccf8a..84896d4681f9 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -16,9 +16,68 @@
>>  #include <PiPei.h>
>>  #include <Register/Amd/Cpuid.h>
>>  #include <Register/Cpuid.h>
>> +#include <Register/Amd/Msr.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>>  
>>  #include "Platform.h"
>>  
>> +/**
>> +
>> +  Initialize SEV-ES support if running an SEV-ES guest.
>> +
>> +  **/
>> +STATIC
>> +VOID
>> +AmdSevEsInitialize (
>> +  VOID
>> +  )
>> +{
>> +  VOID              *GhcbBase;
>> +  PHYSICAL_ADDRESS  GhcbBasePa;
>> +  UINTN             GhcbPageCount;
>> +  RETURN_STATUS     DecryptStatus, PcdStatus;
>> +
>> +  if (!MemEncryptSevEsIsEnabled ()) {
>> +    return;
>> +  }
>> +
>> +  GhcbPageCount = mMaxCpuCount;
>> +
>> +  //
>> +  // Allocate GHCB pages.
>> +  //
>> +  GhcbBase = AllocatePages (GhcbPageCount);
>> +  ASSERT (GhcbBase);
>> +
>> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> +  DecryptStatus = MemEncryptSevClearPageEncMask (
>> +    0,
>> +    GhcbBasePa,
>> +    GhcbPageCount,
>> +    TRUE
>> +    );
>> +  ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> +  BuildMemoryAllocationHob (
>> +    GhcbBasePa,
>> +    EFI_PAGES_TO_SIZE (GhcbPageCount),
>> +    EfiBootServicesData
>> +    );
>> +
>> +  SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
>> +
>> +  PcdStatus = PcdSet64S (PcdGhcbBase, (UINT64)GhcbBasePa);
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +  PcdStatus = PcdSet64S (PcdGhcbSize, (UINT64)EFI_PAGES_TO_SIZE (GhcbPageCount));
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> +  DEBUG ((DEBUG_INFO, "SEV-ES is enabled, %u GHCB pages allocated starting at 0x%lx\n", GhcbPageCount, GhcbBase));
>> +
>> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
>> +}
>> +
>>  /**
>>  
>>    Function checks if SEV support is available, if present then it sets
>> @@ -89,4 +148,9 @@ AmdSevInitialize (
>>        EfiBootServicesData                // MemoryType
>>        );
>>    }
>> +
>> +  //
>> +  // Check and perform SEV-ES initialization if required.
>> +  //
>> +  AmdSevEsInitialize ();
>>  }
>>
> 

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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-21 14:21   ` [edk2-devel] " Laszlo Ersek
  2019-08-21 21:25     ` Lendacky, Thomas
@ 2019-08-21 21:51     ` Jordan Justen
  2019-08-22 13:46       ` Laszlo Ersek
  1 sibling, 1 reply; 46+ messages in thread
From: Jordan Justen @ 2019-08-21 21:51 UTC (permalink / raw)
  To: Laszlo Ersek, devel, thomas.lendacky
  Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
	Singh, Brijesh, Fang, Peter, D Scott Phillips

On 2019-08-21 07:21:25, Laszlo Ersek wrote:
> On 08/19/19 23:35, Lendacky, Thomas wrote:
> > From: Tom Lendacky <thomas.lendacky@amd.com>
> > 
> > Currently, the OVMF code relies on the hypervisor to enable the cache
> > support on the processor in order to improve the boot speed. However,
> > with SEV-ES, the hypervisor is not allowed to change the CR0 register
> > to enable caching.
> > 
> > Update the OVMF Sec support to enable caching in order to improve the
> > boot speed.
> > 
> > Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> > ---
> >  OvmfPkg/Sec/SecMain.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> > index 3914355cd17b..2448be0cd408 100644
> > --- a/OvmfPkg/Sec/SecMain.c
> > +++ b/OvmfPkg/Sec/SecMain.c
> > @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
> >  
> >    ProcessLibraryConstructorList (NULL, NULL);
> >  
> > +  //
> > +  // Enable caching
> > +  //
> > +  AsmEnableCache ();
> > +
> >    DEBUG ((EFI_D_INFO,
> >      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
> >      (UINT32)(UINTN)BootFv,
> > 
> 
> This makes me uncomfortable. There used to be problems related to
> caching when VFIO device assignment were used. My concern is admittedly
> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> "well what could break here", I'd answer "you never know, and the burden
> of proof is not on me". :) Can we make this change conditional on SEV-ES?

This was also raised as an issue by Peter for the ACRN hypervisor and
Scott for the bhyve hypervisor.

I think it is rare for a platform to enable cache at this early of a
stage, but it is also rare to decompress a firmware volume at this
point.

It appears that it could be helpful to figure out how to safely enable
cache by default here, since it does seem to be impacting several
hypervisors.

-Jordan

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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-21 21:51     ` Jordan Justen
@ 2019-08-22 13:46       ` Laszlo Ersek
  2019-08-22 20:44         ` Jordan Justen
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-22 13:46 UTC (permalink / raw)
  To: Jordan Justen, devel, thomas.lendacky
  Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
	Singh, Brijesh, Fang, Peter, D Scott Phillips

On 08/21/19 23:51, Jordan Justen wrote:
> On 2019-08-21 07:21:25, Laszlo Ersek wrote:
>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> Currently, the OVMF code relies on the hypervisor to enable the cache
>>> support on the processor in order to improve the boot speed. However,
>>> with SEV-ES, the hypervisor is not allowed to change the CR0 register
>>> to enable caching.
>>>
>>> Update the OVMF Sec support to enable caching in order to improve the
>>> boot speed.
>>>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  OvmfPkg/Sec/SecMain.c | 5 +++++
>>>  1 file changed, 5 insertions(+)
>>>
>>> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
>>> index 3914355cd17b..2448be0cd408 100644
>>> --- a/OvmfPkg/Sec/SecMain.c
>>> +++ b/OvmfPkg/Sec/SecMain.c
>>> @@ -739,6 +739,11 @@ SecCoreStartupWithStack (
>>>  
>>>    ProcessLibraryConstructorList (NULL, NULL);
>>>  
>>> +  //
>>> +  // Enable caching
>>> +  //
>>> +  AsmEnableCache ();
>>> +
>>>    DEBUG ((EFI_D_INFO,
>>>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>>>      (UINT32)(UINTN)BootFv,
>>>
>>
>> This makes me uncomfortable. There used to be problems related to
>> caching when VFIO device assignment were used. My concern is admittedly
>> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
>> "well what could break here", I'd answer "you never know, and the burden
>> of proof is not on me". :) Can we make this change conditional on SEV-ES?
> 
> This was also raised as an issue by Peter for the ACRN hypervisor and
> Scott for the bhyve hypervisor.
> 
> I think it is rare for a platform to enable cache at this early of a
> stage, but it is also rare to decompress a firmware volume at this
> point.
> 
> It appears that it could be helpful to figure out how to safely enable
> cache by default here, since it does seem to be impacting several
> hypervisors.

I can't think of anything better than "trial and error". The issues that
used to pop up in the past, due to host kernel (KVM) changes,
particularly in connection with VFIO device assignment, have been
completely obscure and unpenetrable to me. Even though I've contributed
at least one KVM patch to mitigate those problems, they remain a mistery
to me, and I remain unable to *reason* about the problems or the fixes.

So I think we could only flip the behavior (enable cache by default) and
collect bug reports. But that's extremely annoying for end-users, and I
see "no regressions" as one of my top responsibilities.

Even if we provided an fw_cfg knob to disable the change, using
QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
PlatformPei: take no-exec DXE settings from the QEMU command line",
2015-09-15), such fw_cfg knobs are difficult to use through layered
products, such as libvirt, proxmox, etc. And of course fw_cfg is only
available on QEMU.

Laszlo

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

* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-21 21:42     ` Lendacky, Thomas
@ 2019-08-22 14:12       ` Laszlo Ersek
  2019-08-22 15:24         ` Lendacky, Thomas
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-22 14:12 UTC (permalink / raw)
  To: Lendacky, Thomas, devel@edk2.groups.io
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/21/19 23:42, Lendacky, Thomas wrote:
> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> Allocate memory for the GHCB pages during SEV initialization for use
>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>> are created without the encryption bit set.
>>>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
>>>  OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
>>>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
>>>  OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
>>>  .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
>>>  .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
>>>  .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
>>>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
>>>  .../MemEncryptSevLibInternal.c                |  1 -
>>>  .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
>>>  OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
>>>  11 files changed, 164 insertions(+), 23 deletions(-)
>>
>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>
>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>> -- if modules under both packages need to consume a new PCD, then the
>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>
>> - MdePkg (must be self-contained)
>> - MdeModulePkg (may consume MdePkg)
>> - UefiCpuPkg (may consume everything above, to my knowledge)
>> - OvmfPkg (may consume everything above)
>>
> 
> Ok, thanks for the guidance.
> 
> Ideally, I just would like to modify the newly created page tables after
> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
> or callback or notification service so that the main changes would be
> limited to the OvmfPkg files and would that be acceptable?

* https://bugzilla.tianocore.org/show_bug.cgi?id=623

  Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
  resources").

  And it's not like patches had not been proposed -- Leo had implemented
  a notification service --; they were rejected.

* https://bugzilla.tianocore.org/show_bug.cgi?id=847

  Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
  <https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.

I don't know what to tell you. While nobody seems to disagree with the
necessity of such a service and/or library, core maintainers have
rejected all the code proposals thus far (= "don't do that"). And I'm
unaware of any constructive guidance (= "do this instead").

I suggest filing a Feature Request BZ for SEV-ES enablement (for
OvmfPkg), and referencing that as "dependent bug" in both of the
above-mentioned BZs. It might also help to dial in to the APAC/NAMO
design / bug triage meeting, and campaign for the feature there.

https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage

I have a bad track record at convincing core maintainers to do what they
don't want to do. And I see escalating such problems from email to phone
as a work-around, sort of "wear down your opponent by sheer
persistence". So I avoid that. But, I've seen the approach work for
others, so you might have better luck.

(The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)

I think the present RFC patches are a good way to re-raise these topics.

Laszlo

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

* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-22 14:12       ` Laszlo Ersek
@ 2019-08-22 15:24         ` Lendacky, Thomas
  2019-08-23 13:26           ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Lendacky, Thomas @ 2019-08-22 15:24 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 8/22/19 9:12 AM, Laszlo Ersek wrote:
> On 08/21/19 23:42, Lendacky, Thomas wrote:
>> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>>> are created without the encryption bit set.
>>>>
>>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>>> ---
>>>>  UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
>>>>  OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
>>>>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
>>>>  OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
>>>>  .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
>>>>  .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
>>>>  .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
>>>>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
>>>>  .../MemEncryptSevLibInternal.c                |  1 -
>>>>  .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
>>>>  OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
>>>>  11 files changed, 164 insertions(+), 23 deletions(-)
>>>
>>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>>
>>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>>> -- if modules under both packages need to consume a new PCD, then the
>>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>>
>>> - MdePkg (must be self-contained)
>>> - MdeModulePkg (may consume MdePkg)
>>> - UefiCpuPkg (may consume everything above, to my knowledge)
>>> - OvmfPkg (may consume everything above)
>>>
>>
>> Ok, thanks for the guidance.
>>
>> Ideally, I just would like to modify the newly created page tables after
>> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
>> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
>> or callback or notification service so that the main changes would be
>> limited to the OvmfPkg files and would that be acceptable?
> 
> * https://bugzilla.tianocore.org/show_bug.cgi?id=623
> 
>   Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
>   resources").
> 
>   And it's not like patches had not been proposed -- Leo had implemented
>   a notification service --; they were rejected.
> 
> * https://bugzilla.tianocore.org/show_bug.cgi?id=847
> 
>   Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
>   <https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.
> 
> I don't know what to tell you. While nobody seems to disagree with the
> necessity of such a service and/or library, core maintainers have
> rejected all the code proposals thus far (= "don't do that"). And I'm
> unaware of any constructive guidance (= "do this instead").

This isn't on the level of a "notify every time something changes" type
of thing. This is more of a "hey, we built some new pagetables and are
about to make them active, but before we do have a look and change what
you think should be changed."

With that, I'd be able to remove the GhcbBase and GhcbSize that is
propogated on the ToSplit and Split functions.

I'll take a look and see what it would look like and go from there.

> 
> I suggest filing a Feature Request BZ for SEV-ES enablement (for
> OvmfPkg), and referencing that as "dependent bug" in both of the
> above-mentioned BZs. It might also help to dial in to the APAC/NAMO
> design / bug triage meeting, and campaign for the feature there.

Yes, I need to file that Feature Request BZ anyway.

Thanks,
Tom

> 
> https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage
> 
> I have a bad track record at convincing core maintainers to do what they
> don't want to do. And I see escalating such problems from email to phone
> as a work-around, sort of "wear down your opponent by sheer
> persistence". So I avoid that. But, I've seen the approach work for
> others, so you might have better luck.
> 
> (The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)
> 
> I think the present RFC patches are a good way to re-raise these topics.
> 
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-22 13:46       ` Laszlo Ersek
@ 2019-08-22 20:44         ` Jordan Justen
  2019-08-23 13:32           ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Jordan Justen @ 2019-08-22 20:44 UTC (permalink / raw)
  To: Laszlo Ersek, devel, thomas.lendacky
  Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
	Singh, Brijesh, Fang, Peter, D Scott Phillips

On 2019-08-22 06:46:07, Laszlo Ersek wrote:
> On 08/21/19 23:51, Jordan Justen wrote:
> > On 2019-08-21 07:21:25, Laszlo Ersek wrote:
> >> On 08/19/19 23:35, Lendacky, Thomas wrote:
> >>> From: Tom Lendacky <thomas.lendacky@amd.com>
> >>>
> >>> +  //
> >>> +  // Enable caching
> >>> +  //
> >>> +  AsmEnableCache ();
> >>> +
> >>>    DEBUG ((EFI_D_INFO,
> >>>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
> >>>      (UINT32)(UINTN)BootFv,
> >>>
> >>
> >> This makes me uncomfortable. There used to be problems related to
> >> caching when VFIO device assignment were used. My concern is admittedly
> >> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
> >> "well what could break here", I'd answer "you never know, and the burden
> >> of proof is not on me". :) Can we make this change conditional on SEV-ES?
> > 
> > This was also raised as an issue by Peter for the ACRN hypervisor and
> > Scott for the bhyve hypervisor.
> > 
> > I think it is rare for a platform to enable cache at this early of a
> > stage, but it is also rare to decompress a firmware volume at this
> > point.
> > 
> > It appears that it could be helpful to figure out how to safely enable
> > cache by default here, since it does seem to be impacting several
> > hypervisors.
> 
> I can't think of anything better than "trial and error".

Maybe we could try to detect kvm, and enable caching if !kvm.

Maybe we could enable it during the decompress of the PEI FV and
disable it afterward?

> The issues that
> used to pop up in the past, due to host kernel (KVM) changes,
> particularly in connection with VFIO device assignment, have been
> completely obscure and unpenetrable to me.

Don't we eventually enable caching during the boot, so how is VFIO not
affected by that?

> Even though I've contributed
> at least one KVM patch to mitigate those problems, they remain a mistery
> to me, and I remain unable to *reason* about the problems or the fixes.

If VFIO requires uncached access, then what mechanisms does kvm
support for accessing memory ranges uncached? I thought kvm simply
ignored the cache setting and always enabled caching, because this
section of boot is not particularly slow with kvm. But, if enabling
caching causes issues, then I guess it does something.

Does kvm support mtrr to uncache i/o ranges? I didn't think kvm
supported mtrrs in the past.

I hope we wouldn't have to use paging to disable caching for the
affected regions.

-Jordan

> So I think we could only flip the behavior (enable cache by default) and
> collect bug reports. But that's extremely annoying for end-users, and I
> see "no regressions" as one of my top responsibilities.
> 
> Even if we provided an fw_cfg knob to disable the change, using
> QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
> PlatformPei: take no-exec DXE settings from the QEMU command line",
> 2015-09-15), such fw_cfg knobs are difficult to use through layered
> products, such as libvirt, proxmox, etc. And of course fw_cfg is only
> available on QEMU.
> 
> Laszlo

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

* Re: [edk2-devel] [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-08-22 15:24         ` Lendacky, Thomas
@ 2019-08-23 13:26           ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-23 13:26 UTC (permalink / raw)
  To: Lendacky, Thomas, devel@edk2.groups.io
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 08/22/19 17:24, Lendacky, Thomas wrote:
> On 8/22/19 9:12 AM, Laszlo Ersek wrote:
>> On 08/21/19 23:42, Lendacky, Thomas wrote:
>>> On 8/21/19 9:31 AM, Laszlo Ersek wrote:
>>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>>
>>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>>> during Pei and Dxe phases. Since the GHCB pages must be mapped as shared
>>>>> pages, modify CreateIdentityMappingPageTables() so that pagetable entries
>>>>> are created without the encryption bit set.
>>>>>
>>>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>>>> ---
>>>>>  UefiCpuPkg/UefiCpuPkg.dec                     |  4 ++
>>>>>  OvmfPkg/OvmfPkgX64.dsc                        |  4 ++
>>>>>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |  3 +
>>>>>  OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +
>>>>>  .../Core/DxeIplPeim/X64/VirtualMemory.h       | 12 +++-
>>>>>  .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |  4 +-
>>>>>  .../Core/DxeIplPeim/X64/DxeLoadFunc.c         | 11 +++-
>>>>>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 49 ++++++++++----
>>>>>  .../MemEncryptSevLibInternal.c                |  1 -
>>>>>  .../BaseMemEncryptSevLib/X64/VirtualMemory.c  | 33 ++++++++--
>>>>>  OvmfPkg/PlatformPei/AmdSev.c                  | 64 +++++++++++++++++++
>>>>>  11 files changed, 164 insertions(+), 23 deletions(-)
>>>>
>>>> Should be split to at least four patches (UefiCpuPkg, MdeModulePkg,
>>>> OvmfPkg/BaseMemEncryptSevLib, OvmfPkg/PlatformPei).
>>>>
>>>> In addition, MdeModulePkg content must not depend on UefiCpuPkg content
>>>> -- if modules under both packages need to consume a new PCD, then the
>>>> PCD should be declared under MdeModulePkg. The rough dependency order is:
>>>>
>>>> - MdePkg (must be self-contained)
>>>> - MdeModulePkg (may consume MdePkg)
>>>> - UefiCpuPkg (may consume everything above, to my knowledge)
>>>> - OvmfPkg (may consume everything above)
>>>>
>>>
>>> Ok, thanks for the guidance.
>>>
>>> Ideally, I just would like to modify the newly created page tables after
>>> the call to CreateIdentityMappingPageTables() in MdeModulePkg/Core/
>>> DxeIplPeim/Ia32/DxeLoadFunc.c. Is there a preferred way to add a listener
>>> or callback or notification service so that the main changes would be
>>> limited to the OvmfPkg files and would that be acceptable?
>>
>> * https://bugzilla.tianocore.org/show_bug.cgi?id=623
>>
>>   Reported on 2017-07-07, resolved as WONTFIX on 2019-07-30 ("no
>>   resources").
>>
>>   And it's not like patches had not been proposed -- Leo had implemented
>>   a notification service --; they were rejected.
>>
>> * https://bugzilla.tianocore.org/show_bug.cgi?id=847
>>
>>   Reported on 2018-01-11, marked "not high priority" as of 2019-07-23
>>   <https://www.mail-archive.com/devel@edk2.groups.io/msg05507.html>.
>>
>> I don't know what to tell you. While nobody seems to disagree with the
>> necessity of such a service and/or library, core maintainers have
>> rejected all the code proposals thus far (= "don't do that"). And I'm
>> unaware of any constructive guidance (= "do this instead").
> 
> This isn't on the level of a "notify every time something changes" type
> of thing. This is more of a "hey, we built some new pagetables and are
> about to make them active, but before we do have a look and change what
> you think should be changed."
> 
> With that, I'd be able to remove the GhcbBase and GhcbSize that is
> propogated on the ToSplit and Split functions.
> 
> I'll take a look and see what it would look like and go from there.

Maybe not the same kind of notification pattern (and the event
triggering the notification could be different), but the point is the
same -- the platform would like the core to call it back at various
stages / points of page table manipulation. How we implement that, is
"details" (edk2-specific (and versioned) protocol, provided by the
platform and called by the core; versus separate event groups, signaled
by the core; versus custom lib class, implemented by the platform;
versus custom status codes reported by the core; etc). What's important
is for core maintainers to finally accept that the facility *as such* is
needed.

> 
>>
>> I suggest filing a Feature Request BZ for SEV-ES enablement (for
>> OvmfPkg), and referencing that as "dependent bug" in both of the
>> above-mentioned BZs. It might also help to dial in to the APAC/NAMO
>> design / bug triage meeting, and campaign for the feature there.
> 
> Yes, I need to file that Feature Request BZ anyway.

Thanks.
Laszlo

>>
>> https://github.com/tianocore/tianocore.github.io/wiki/Bug-Triage
>>
>> I have a bad track record at convincing core maintainers to do what they
>> don't want to do. And I see escalating such problems from email to phone
>> as a work-around, sort of "wear down your opponent by sheer
>> persistence". So I avoid that. But, I've seen the approach work for
>> others, so you might have better luck.
>>
>> (The APAC/NAMO call is also at a bad time for me, in UTC+1 / UTC+2.)
>>
>> I think the present RFC patches are a good way to re-raise these topics.
>>
>> Laszlo
>>


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

* Re: [edk2-devel] [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-08-22 20:44         ` Jordan Justen
@ 2019-08-23 13:32           ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2019-08-23 13:32 UTC (permalink / raw)
  To: Jordan Justen, devel, thomas.lendacky
  Cc: Ard Biesheuvel, Michael D Kinney, Liming Gao, Eric Dong, Ray Ni,
	Singh, Brijesh, Fang, Peter, D Scott Phillips

On 08/22/19 22:44, Jordan Justen wrote:
> On 2019-08-22 06:46:07, Laszlo Ersek wrote:
>> On 08/21/19 23:51, Jordan Justen wrote:
>>> On 2019-08-21 07:21:25, Laszlo Ersek wrote:
>>>> On 08/19/19 23:35, Lendacky, Thomas wrote:
>>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>>
>>>>> +  //
>>>>> +  // Enable caching
>>>>> +  //
>>>>> +  AsmEnableCache ();
>>>>> +
>>>>>    DEBUG ((EFI_D_INFO,
>>>>>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>>>>>      (UINT32)(UINTN)BootFv,
>>>>>
>>>>
>>>> This makes me uncomfortable. There used to be problems related to
>>>> caching when VFIO device assignment were used. My concern is admittedly
>>>> vague, but this is a very brittle area of OVMF-on-KVM. If you asked me
>>>> "well what could break here", I'd answer "you never know, and the burden
>>>> of proof is not on me". :) Can we make this change conditional on SEV-ES?
>>>
>>> This was also raised as an issue by Peter for the ACRN hypervisor and
>>> Scott for the bhyve hypervisor.
>>>
>>> I think it is rare for a platform to enable cache at this early of a
>>> stage, but it is also rare to decompress a firmware volume at this
>>> point.
>>>
>>> It appears that it could be helpful to figure out how to safely enable
>>> cache by default here, since it does seem to be impacting several
>>> hypervisors.
>>
>> I can't think of anything better than "trial and error".
> 
> Maybe we could try to detect kvm, and enable caching if !kvm.
> 
> Maybe we could enable it during the decompress of the PEI FV and
> disable it afterward?
> 
>> The issues that
>> used to pop up in the past, due to host kernel (KVM) changes,
>> particularly in connection with VFIO device assignment, have been
>> completely obscure and unpenetrable to me.
> 
> Don't we eventually enable caching during the boot, so how is VFIO not
> affected by that?
> 
>> Even though I've contributed
>> at least one KVM patch to mitigate those problems, they remain a mistery
>> to me, and I remain unable to *reason* about the problems or the fixes.
> 
> If VFIO requires uncached access, then what mechanisms does kvm
> support for accessing memory ranges uncached? I thought kvm simply
> ignored the cache setting and always enabled caching, because this
> section of boot is not particularly slow with kvm. But, if enabling
> caching causes issues, then I guess it does something.
> 
> Does kvm support mtrr to uncache i/o ranges? I didn't think kvm
> supported mtrrs in the past.
> 
> I hope we wouldn't have to use paging to disable caching for the
> affected regions.

All good questions, and I'm not equipped to answer them, unfortunately.
I'm happy to review and regression-test -- including GPU assignment, on
my workstation that's dedicated to that use case -- OvmfPkg patches, if
someone posts them.

This stuff is in constant flux in KVM. Recent example:

https://www.redhat.com/archives/vfio-users/2019-August/msg00016.html

Thanks
Laszlo


>> So I think we could only flip the behavior (enable cache by default) and
>> collect bug reports. But that's extremely annoying for end-users, and I
>> see "no regressions" as one of my top responsibilities.
>>
>> Even if we provided an fw_cfg knob to disable the change, using
>> QemuFwCfgSecLib, similarly to commit ab081a50e565 ("OvmfPkg:
>> PlatformPei: take no-exec DXE settings from the QEMU command line",
>> 2015-09-15), such fw_cfg knobs are difficult to use through layered
>> products, such as libvirt, proxmox, etc. And of course fw_cfg is only
>> available on QEMU.
>>
>> Laszlo


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

end of thread, other threads:[~2019-08-23 13:32 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-08-19 21:35 [RFC PATCH 00/28] SEV-ES guest support thomas.lendacky
2019-08-19 21:35 ` [RFC PATCH 01/28] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2019-08-21 14:21   ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:25     ` Lendacky, Thomas
2019-08-21 21:51     ` Jordan Justen
2019-08-22 13:46       ` Laszlo Ersek
2019-08-22 20:44         ` Jordan Justen
2019-08-23 13:32           ` Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 02/28] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 03/28] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 04/28] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2019-08-21 14:25   ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:29     ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 05/28] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2019-08-21 14:31   ` [edk2-devel] " Laszlo Ersek
2019-08-21 21:42     ` Lendacky, Thomas
2019-08-22 14:12       ` Laszlo Ersek
2019-08-22 15:24         ` Lendacky, Thomas
2019-08-23 13:26           ` Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 06/28] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 07/28] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2019-08-21 15:44   ` [edk2-devel] " Laszlo Ersek
2019-08-19 21:35 ` [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support Lendacky, Thomas
2019-08-19 21:47   ` Ni, Ray
2019-08-19 22:25     ` Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 09/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2019-08-19 21:35 ` [RFC PATCH 10/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Sec phase Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 11/28] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 12/28] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 13/28] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 14/28] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 15/28] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 16/28] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 17/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 18/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 19/28] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 20/28] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 21/28] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 22/28] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 23/28] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 24/28] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 25/28] UefiCpuPkg/CpuExceptionHandler: Add base #VC exception handling support for Pei/Dxe phases Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 26/28] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 27/28] UefiCpuPkg/MpInitLib: Allow AP booting under SEV-ES Lendacky, Thomas
2019-08-19 21:36 ` [RFC PATCH 28/28] UefiCpuPkg/MpInitLib: Introduce an MP finalization routine to support SEV-ES Lendacky, Thomas
2019-08-21 14:17 ` [edk2-devel] [RFC PATCH 00/28] SEV-ES guest support Laszlo Ersek

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