public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [RFC PATCH v2 00/44] SEV-ES guest support
@ 2019-09-19 19:52 Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 01/44] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
                   ` (44 more replies)
  0 siblings, 45 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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, Benjamin You,
	Dandan Bi, Guo Dong, Hao A Wu, Jian J Wang, Maurice Ma

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

---

These patches are based on commit:
ada905ab5c0e ("MdeModulePkg DxeCore: Fix for missing Memory Attributes Table (MAT) update")

A version of the tree can be found at:
https://github.com/AMDESE/ovmf/tree/sev-es-v7

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Benjamin You <benjamin.you@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ray Ni <ray.ni@intel.com>

Changes since v1:
- Patches reworked to be more specific to the component/area being updated
  and order of definition/usage
- Created a library for VMGEXIT-related functions to replace use of inline
  functions
- Allocation method for GDT changed from AllocatePool to AllocatePages
- Early caching only enabled for SEV-ES guests
- Ensure AP loop mode set to halt loop mode for SEV-ES guests
- Reserved SEC GHCB-related memory areas when S3 is enabled

Tom Lendacky (44):
  MdePkg: Create PCDs to be used in support of SEV-ES
  OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  OvmfPkg: Add support to perform SEV-ES initialization
  OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  MdePkg: Add the MSR definition for the GHCB register
  OvmfPkg: Create a GHCB page for use during Sec phase
  OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
  OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  OvmfPkg: A per-CPU variable area for #VC usage
  OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  MdePkg: Add a structure definition for the GHCB
  MdePkg/BaseLib: Add support for the VMGEXIT instruction
  UefiCpuPkg: Implement library support for VMGEXIT
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
  UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec
    phase
  OvmfPkg/Sec: Enable cache early to speed up booting
  UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
    events
  MdePkg: Add support for the XGETBV instruction
  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/MpInitLib: Update CPU MP data with a flag to indicate if
    SEV-ES is active
  MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
  OvmfPkg: Add support for SEV-ES AP reset vector re-directing
  UefiCpuPkg: Allow AP booting under SEV-ES
  OvmfPkg: Move the GHCB allocations into reserved memory
  MdePkg: Add a finalization function to the CPU protocol
  UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
  UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
  UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support
    SEV-ES
  MdeModulePkg/DxeCore: Perform the CPU protocol finalization support

 MdeModulePkg/MdeModulePkg.dec                 |   15 +
 OvmfPkg/OvmfPkg.dec                           |   10 +
 UefiCpuPkg/UefiCpuPkg.dec                     |    3 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   10 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   10 +
 OvmfPkg/OvmfPkgX64.dsc                        |   10 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
 UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
 UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
 OvmfPkg/OvmfPkgX64.fdf                        |    6 +
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
 MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
 .../BaseMemEncryptSevLib.inf                  |    2 +-
 OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
 OvmfPkg/ResetVector/ResetVector.inf           |    6 +
 OvmfPkg/Sec/SecMain.inf                       |    2 +
 .../DxeCpuExceptionHandlerLib.inf             |    5 +
 .../PeiCpuExceptionHandlerLib.inf             |    5 +
 .../SecPeiCpuExceptionHandlerLib.inf          |    5 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    3 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    3 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
 .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
 MdePkg/Include/Library/BaseLib.h              |   30 +
 MdePkg/Include/Protocol/Cpu.h                 |   18 +
 MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
 MdePkg/Include/Register/Amd/Ghcb.h            |  105 ++
 OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
 UefiCpuPkg/CpuDxe/CpuDxe.h                    |   12 +
 UefiCpuPkg/CpuDxe/CpuGdt.h                    |    4 +-
 UefiCpuPkg/Include/Library/MpInitLib.h        |   14 +
 UefiCpuPkg/Include/Library/VmgExitLib.h       |   74 +
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
 .../CpuExceptionCommon.h                      |    2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |   77 +-
 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       |   45 +
 MdePkg/Library/BaseLib/X64/GccInline.c        |   47 +
 .../MemEncryptSevLibInternal.c                |   77 +-
 OvmfPkg/PlatformPei/AmdSev.c                  |   78 ++
 OvmfPkg/PlatformPei/MemDetect.c               |   23 +
 OvmfPkg/Sec/SecMain.c                         |   39 +-
 UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
 UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
 .../CpuExceptionCommon.c                      |    2 +-
 .../Ia32/AMDSevVcCommon.c                     |   13 +
 .../PeiDxeAMDSevVcHandler.c                   |   22 +
 .../PeiDxeSmmCpuException.c                   |   16 +
 .../SecAMDSevVcHandler.c                      |   45 +
 .../SecPeiCpuException.c                      |   16 +
 .../X64/AMDSevVcCommon.c                      | 1200 +++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  259 +++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |   75 ++
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   31 +
 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm       |   31 +
 MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   32 +
 MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   34 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   80 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  256 +++-
 OvmfPkg/ResetVector/ResetVector.nasmb         |   13 +
 .../X64/ExceptionHandlerAsm.nasm              |   15 +
 UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    2 +-
 .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
 UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  373 ++++-
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
 .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
 73 files changed, 3600 insertions(+), 97 deletions(-)
 create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h
 create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.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 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
 create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
 create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
 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
 create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni

-- 
2.17.1


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

* [RFC PATCH v2 01/44] MdePkg: Create PCDs to be used in support of SEV-ES
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
                   ` (43 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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, Jian J Wang,
	Hao A Wu

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

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

Three new PCDs are needed to support SEV-ES under OVMF:
  - PcdSevEsActive: BOOLEAN value used to indicate if SEV-ES is active
  - PcdGhcbBase:    UINT64 value that is the base address of the GHCB
                    allocation.
  - PcdGhcbSize:    UINT64 value that is the size, in bytes, of the GHCB
                    allocation (size is dependent on the number of APs).

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdeModulePkg/MdeModulePkg.dec | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 19935c88fab8..c1ec3e335143 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2002,6 +2002,21 @@ [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   # @Prompt Capsule On Disk relocation device path.
   gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath|{0xFF}|VOID*|0x0000002f
 
+  ## Indicates whether SEV-ES is active
+  #   TRUE  - SEV-ES is active
+  #   FALSE - SEV-ES is not active
+  # @Prompt SEV-ES Status
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|FALSE|BOOLEAN|0x00011060
+
+  ## The base address of the GHCB pool allocation.
+  # @Prompt GHCB Pool Base Address
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00011061
+
+  ## The total size of the GHCB allocation.
+  #  The amount of memory allocated for GHCBs is dependent on the number of APs.
+  # @Prompt GHCB Pool Size
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00011062
+
 [PcdsPatchableInModule]
   ## Specify memory size with page number for PEI code when
   #  Loading Module at Fixed Address feature is enabled.
-- 
2.17.1


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

* [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 01/44] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-24 11:53   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
                   ` (42 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
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] 106+ messages in thread

* [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 01/44] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-24 11:59   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
                   ` (41 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

When SEV-ES is active, then SEV is also active. Add support to the SEV
initialization function to also check for SEV-ES being active. If SEV-ES
is active, set the SEV-ES active PCD (PcdSevEsActive).

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc             |  3 +++
 OvmfPkg/OvmfPkgIa32X64.dsc          |  3 +++
 OvmfPkg/OvmfPkgX64.dsc              |  3 +++
 OvmfPkg/PlatformPei/PlatformPei.inf |  1 +
 OvmfPkg/PlatformPei/AmdSev.c        | 26 ++++++++++++++++++++++++++
 5 files changed, 36 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 6ab730018694..0ce5c01722ef 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -558,6 +558,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index f163aa267132..e7455e35a55d 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -570,6 +570,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index fa98f16a3fb3..0b8305cd10a2 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -569,6 +569,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index d9fd9c8f05b3..2736347a2e03 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -100,6 +100,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 2ae8126ccf8a..7ae2f26a2ba7 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -19,6 +19,27 @@
 
 #include "Platform.h"
 
+/**
+
+  Initialize SEV-ES support if running an SEV-ES guest.
+
+  **/
+STATIC
+VOID
+AmdSevEsInitialize (
+  VOID
+  )
+{
+  RETURN_STATUS     PcdStatus;
+
+  if (!MemEncryptSevEsIsEnabled ()) {
+    return;
+  }
+
+  PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
 /**
 
   Function checks if SEV support is available, if present then it sets
@@ -89,4 +110,9 @@ AmdSevInitialize (
       EfiBootServicesData                // MemoryType
       );
   }
+
+  //
+  // Check and perform SEV-ES initialization if required.
+  //
+  AmdSevEsInitialize ();
 }
-- 
2.17.1


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

* [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (2 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-24 13:42   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 05/44] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
                   ` (40 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

During BSP startup, the reset vector code will issue a CPUID instruction
while in 32-bit mode. When running as an SEV-ES guest, this will trigger
a #VC exception.

Add exception handling support to the early reset vector code to catch
these exceptions.  Also, since the guest is in 32-bit mode at this point,
writes to the GHCB will be encrypted and thus not able to be read by the
hypervisor, so use the GHCB CPUID request/response protocol to obtain the
requested CPUID function values and provide these to the guest.

The exception handling support is active during the SEV check and uses the
OVMF temporary RAM space for a stack. After the SEV check is complete, the
exception handling support is removed and the stack pointer cleared.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/ResetVector/ResetVector.inf       |   2 +
 OvmfPkg/ResetVector/Ia32/PageTables64.asm | 177 +++++++++++++++++++++-
 OvmfPkg/ResetVector/ResetVector.nasmb     |   1 +
 3 files changed, 179 insertions(+), 1 deletion(-)

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..40f7814c1134 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -33,10 +33,21 @@ BITS    32
 
 ; Check if Secure Encrypted Virtualization (SEV) feature is enabled
 ;
-; If SEV is enabled then EAX will be at least 32
+; Modified:  EAX, EBX, ECX, EDX, ESP
+;
+; If SEV is enabled then EAX will be at least 32.
 ; If SEV is disabled then EAX will be zero.
 ;
 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 +84,15 @@ NoSev:
     xor       eax, eax
 
 SevExit:
+    ;
+    ; Clear exception handlers and stack
+    ;
+    push      eax
+    mov       eax, ADDR_OF(IdtrClear)
+    lidt      [cs:eax]
+    pop       eax
+    mov       esp, 0
+
     OneTimeCallRet CheckSevFeature
 
 ;
@@ -146,3 +166,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
+
+IdtrClear:
+    dw      0                       ; Limit
+    dd      0                       ; Base
+
+ALIGN   16
+
+;
+; The Interrupt Descriptor Table (IDT)
+;   This will be used to determine if SEV-ES is enabled.  Upon execution
+;   of the CPUID instruction, a VMM Communication Exception will occur.
+;   This will tell us if SEV-ES is enabled.  We can use the current value
+;   of the GHCB MSR to determine the SEV attributes.
+;
+IDT_BASE:
+;
+; Vectors 0 - 28
+;
+%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] 106+ messages in thread

* [RFC PATCH v2 05/44] MdePkg: Add the MSR definition for the GHCB register
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (3 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
                   ` (39 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

For SEV-ES, the GHCB page address is stored in the GHCB MSR register
(0xc0010130). Define the register and the format used for register
during GHCB protocol negotiation.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Include/Register/Amd/Fam17Msr.h | 28 ++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/MdePkg/Include/Register/Amd/Fam17Msr.h b/MdePkg/Include/Register/Amd/Fam17Msr.h
index 37b935dcdb30..55a5723e164e 100644
--- a/MdePkg/Include/Register/Amd/Fam17Msr.h
+++ b/MdePkg/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
 
-- 
2.17.1


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

* [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (4 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 05/44] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-25  8:09   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
                   ` (38 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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 to break down the 2MB
region where the GHCB page lives into 4K pagetable entries.

Create a new entry in the OVMF memory layout for the new page table
page and for the SEC GHCB page. After breaking down the 2MB page, update
the GHCB page table entry to remove the encryption mask.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkg.dec                       | 10 +++
 OvmfPkg/OvmfPkgX64.fdf                    |  6 ++
 OvmfPkg/ResetVector/ResetVector.inf       |  4 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm | 79 +++++++++++++++++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb     | 12 ++++
 5 files changed, 111 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 9640360f6245..b9287a023c94 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -218,6 +218,16 @@ [PcdsFixedAtBuild]
   #  The value should be a multiple of 4KB.
   gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
 
+  ## Specify the extra page table needed to mark the GHCB as unencrypted.
+  #  The value should be a multiple of 4KB for each.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|0x0|UINT32|0x32
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|0x0|UINT32|0x33
+
+  ## Specify the GHCB base address and size.
+  #  The value should be a multiple of 4KB for each.
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x34
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x35
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 74407072563b..a567131a0591 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -76,6 +76,12 @@ [FD.MEMFD]
 0x007000|0x001000
 gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
 
+0x008000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+
+0x009000|0x001000
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 960b47cd0797..80c971354176 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -37,3 +37,7 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 40f7814c1134..7e346661f2c8 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 + \
@@ -95,6 +100,37 @@ SevExit:
 
     OneTimeCallRet CheckSevFeature
 
+; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
+; is enabled.
+;
+; Modified:  EAX, EBX, ECX, EDX
+;
+; If SEV-ES is enabled then EAX will be non-zero.
+; If SEV-ES is disabled then EAX will be zero.
+;
+CheckSevEsFeature:
+    xor       eax, eax
+
+    ; SEV-ES can't be enabled if SEV isn't, so first check the encryption
+    ; mask.
+    test      edx, edx
+    jz        NoSevEs
+
+    ; Save current value of encryption mask
+    mov       ebx, edx
+
+    ; Check if SEV-ES is enabled
+    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
+    mov       ecx, 0xc0010131
+    rdmsr
+    and       eax, 2
+
+    ; Restore encryption mask
+    mov       edx, ebx
+
+NoSevEs:
+    OneTimeCallRet CheckSevEsFeature
+
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
@@ -159,6 +195,49 @@ pageTableEntriesLoop:
     mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
     loop    pageTableEntriesLoop
 
+    OneTimeCall   CheckSevEsFeature
+    test    eax, eax
+    jz      SetCr3
+
+    ;
+    ; The initial GHCB will live at 0x809000 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 encrypted,
+    ; except for the GHCB.
+    ;
+    mov     ecx, 4
+    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
+
+    ;
+    ; Page Table Entries (512 * 4KB entries => 2MB)
+    ;
+    mov     ecx, 512
+pageTableEntries4kLoop:
+    mov     eax, ecx
+    dec     eax
+    shl     eax, 12
+    add     eax, 0x800000
+    add     eax, PAGE_4K_PDE_ATTR
+    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
+    mov     [ecx * 8 + GHCB_PT_ADDR - 4], edx
+    loop    pageTableEntries4kLoop
+
+    ;
+    ; Clear the encryption bit from the GHCB entry (index 9 in the
+    ; new PTE table: (0x809000 - 0x800000) >> 12)).
+    ;
+    mov     ecx, 9
+    xor     edx, edx
+    mov     [ecx * 8 + GHCB_PT_ADDR + 4], edx
+
+    mov     ecx, GHCB_SIZE / 4
+    xor     eax, eax
+clearGhcbMemoryLoop:
+    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
+    loop    clearGhcbMemoryLoop
+
+SetCr3:
     ;
     ; Set CR3 now that the paging structures are available
     ;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 3b213cd05ab2..8909fc9313f4 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -53,7 +53,19 @@
     %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
   %endif
 
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
+    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
+  %endif
+
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
+    %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
+  %endif
+
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
+
+  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
+  %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
+  %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
 %include "Ia32/Flat32ToFlat64.asm"
   %define SEV_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/PageTables64.asm"
-- 
2.17.1


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

* [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (5 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-25  8:27   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
                   ` (37 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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, Anthony Perard,
	Julien Grall

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

Protect the memory used by an SEV-ES guest when S3 is supported. This
includes the page table used to break down the 2MB page that contains
the GHCB so that it can be marked un-encrypted, as well as the GHCB
area.

Regarding the lifecycle of the GHCB-related memory areas:
  PcdOvmfSecGhcbPageTableBase
  PcdOvmfSecGhcbBase

(a) when and how it is initialized after first boot of the VM

  If SEV-ES is enabled, the GHCB-related areas are initialized during
  the SEC phase [OvmfPkg/ResetVector/Ia32/PageTables64.asm].

(b) how it is protected from memory allocations during DXE

  If S3 and SEV-ES are enabled, then InitializeRamRegions()
  [OvmfPkg/PlatformPei/MemDetect.c] protects the range with an AcpiNVS
  memory allocation HOB, in PEI.

(c) how it is protected from the OS

  If S3 is enabled, then (1b) reserves it from the OS too.

  If S3 is disabled, then the range needs no protection.

(d) how it is accessed on the S3 resume path

  It is rewritten same as in (1a), which is fine because (1b) reserved it.

(e) how it is accessed on the warm reset path

  It is rewritten same as in (1a).

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien.grall@arm.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/PlatformPei/PlatformPei.inf |  4 ++++
 OvmfPkg/PlatformPei/MemDetect.c     | 23 +++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 2736347a2e03..a9e424a6012a 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -84,6 +84,10 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
   gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d451989f31c9..cd2e3abb7c9b 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -32,6 +32,7 @@ Module Name:
 #include <Library/ResourcePublicationLib.h>
 #include <Library/MtrrLib.h>
 #include <Library/QemuFwCfgLib.h>
+#include <Library/MemEncryptSevLib.h>
 
 #include "Platform.h"
 #include "Cmos.h"
@@ -805,6 +806,28 @@ InitializeRamRegions (
       (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
       EfiACPIMemoryNVS
       );
+
+    if (MemEncryptSevEsIsEnabled ()) {
+      //
+      // If SEV-ES is active, reserve the GHCB-related memory area. This
+      // includes the extra page table used to break down the 2MB page
+      // mapping into 4KB page entries where the GHCB resides and the
+      // GHCB area itself.
+      //
+      // Since this memory range will be used by the Reset Vector on S3
+      // resume, it must be reserved as ACPI NVS.
+      //
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableBase),
+        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableSize),
+        EfiACPIMemoryNVS
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbBase),
+        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbSize),
+        EfiACPIMemoryNVS
+        );
+    }
 #endif
   }
 
-- 
2.17.1


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

* [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (6 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-26  8:00   ` [edk2-devel] " Laszlo Ersek
  2019-10-02 10:23   ` Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 09/44] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
                   ` (36 subsequent siblings)
  44 siblings, 2 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

Allocate memory for the GHCB pages during SEV initialization for use
during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
clear the encryption mask from the current page table entries. Upon
successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
 OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
 OvmfPkg/OvmfPkgX64.dsc              |  2 ++
 OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
 OvmfPkg/PlatformPei/AmdSev.c        | 36 ++++++++++++++++++++++++++++-
 5 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 0ce5c01722ef..4369cf6d55e5 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -560,6 +560,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index e7455e35a55d..a74f5028068e 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -572,6 +572,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 0b8305cd10a2..fd714d386e75 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -571,6 +571,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
 
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index a9e424a6012a..62abc99f4622 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -105,6 +105,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 7ae2f26a2ba7..30c0e4af7252 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -16,6 +16,9 @@
 #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"
 
@@ -30,7 +33,10 @@ AmdSevEsInitialize (
   VOID
   )
 {
-  RETURN_STATUS     PcdStatus;
+  VOID              *GhcbBase;
+  PHYSICAL_ADDRESS  GhcbBasePa;
+  UINTN             GhcbPageCount;
+  RETURN_STATUS     PcdStatus, DecryptStatus;
 
   if (!MemEncryptSevEsIsEnabled ()) {
     return;
@@ -38,6 +44,34 @@ AmdSevEsInitialize (
 
   PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
   ASSERT_RETURN_ERROR (PcdStatus);
+
+  //
+  // Allocate GHCB pages.
+  //
+  GhcbPageCount = mMaxCpuCount;
+  GhcbBase = AllocatePages (GhcbPageCount);
+  ASSERT (GhcbBase);
+
+  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
+
+  DecryptStatus = MemEncryptSevClearPageEncMask (
+    0,
+    GhcbBasePa,
+    GhcbPageCount,
+    TRUE
+    );
+  ASSERT_RETURN_ERROR (DecryptStatus);
+
+  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);
 }
 
 /**
-- 
2.17.1


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

* [RFC PATCH v2 09/44] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (7 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
                   ` (35 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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, Jian J Wang,
	Hao A Wu, Dandan Bi

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

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

GHCB pages must be mapped as shared pages, so modify the process of
creating identity mapped pagetable entries so that GHCB entries are
created without the encryption bit set.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.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 ++++++++++++++-----
 5 files changed, 62 insertions(+), 16 deletions(-)

diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index 98bc17fc9d1f..5e6b78e295e6 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -111,6 +111,8 @@ [Pcd.IA32,Pcd.X64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable                  ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize                            ## CONSUMES
 
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
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 516cf908bc88..32a81d1f3c21 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -181,6 +181,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.
@@ -190,7 +192,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) {
@@ -209,6 +213,12 @@ ToSplitPageTable (
     }
   }
 
+  if (GhcbBase) {
+    if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
+      return TRUE;
+    }
+  }
+
   return FALSE;
 }
 /**
@@ -322,6 +332,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
@@ -329,7 +341,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;
@@ -355,7 +369,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) ||
@@ -383,6 +402,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
@@ -390,7 +411,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;
@@ -413,11 +436,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
@@ -616,6 +639,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.
 
@@ -623,7 +648,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;
@@ -809,8 +836,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
@@ -840,11 +867,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
-- 
2.17.1


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

* [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (8 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 09/44] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-26  8:17   ` [edk2-devel] " Laszlo Ersek
  2019-10-02 11:51   ` Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
                   ` (34 subsequent siblings)
  44 siblings, 2 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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 (and
that is done), 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.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgX64.fdf                | 2 +-
 OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
 OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index a567131a0591..84716952052d 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -79,7 +79,7 @@ [FD.MEMFD]
 0x008000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
 
-0x009000|0x001000
+0x009000|0x002000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
 
 0x010000|0x010000
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 30c0e4af7252..699bb8b11557 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -48,7 +48,7 @@ AmdSevEsInitialize (
   //
   // Allocate GHCB pages.
   //
-  GhcbPageCount = mMaxCpuCount;
+  GhcbPageCount = mMaxCpuCount * 2;
   GhcbBase = AllocatePages (GhcbPageCount);
   ASSERT (GhcbBase);
 
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 8909fc9313f4..d7c0ab3ada00 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -57,7 +57,7 @@
     %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
   %endif
 
-  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
     %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
   %endif
 
-- 
2.17.1


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

* [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (9 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-10-02 12:05   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 12/44] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
                   ` (33 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
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 699bb8b11557..d6733447bdf2 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -37,6 +37,8 @@ AmdSevEsInitialize (
   PHYSICAL_ADDRESS  GhcbBasePa;
   UINTN             GhcbPageCount;
   RETURN_STATUS     PcdStatus, DecryptStatus;
+  IA32_DESCRIPTOR   Gdtr;
+  VOID              *Gdt;
 
   if (!MemEncryptSevEsIsEnabled ()) {
     return;
@@ -72,6 +74,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 = AllocatePages (EFI_SIZE_TO_PAGES (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] 106+ messages in thread

* [RFC PATCH v2 12/44] MdePkg: Add a structure definition for the GHCB
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (10 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 13/44] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
                   ` (32 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

The GHCB is used by an SEV-ES guest for communicating between the guest
and the hypervisor. Create the GHCB definition as defined by the GHCB
protocol definition.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Include/Register/Amd/Ghcb.h | 105 +++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h

diff --git a/MdePkg/Include/Register/Amd/Ghcb.h b/MdePkg/Include/Register/Amd/Ghcb.h
new file mode 100644
index 000000000000..cd3c98091208
--- /dev/null
+++ b/MdePkg/Include/Register/Amd/Ghcb.h
@@ -0,0 +1,105 @@
+
+#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;
+
+#endif
-- 
2.17.1


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

* [RFC PATCH v2 13/44] MdePkg/BaseLib: Add support for the VMGEXIT instruction
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (11 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 12/44] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 14/44] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
                   ` (31 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Provide the necessary support to execute the VMGEXIT instruction, which
is "rep; vmmcall".

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Library/BaseLib/BaseLib.inf       |  2 ++
 MdePkg/Include/Library/BaseLib.h         | 14 +++++++++++
 MdePkg/Library/BaseLib/Ia32/GccInline.c  | 17 +++++++++++++
 MdePkg/Library/BaseLib/X64/GccInline.c   | 17 +++++++++++++
 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm | 31 +++++++++++++++++++++++
 MdePkg/Library/BaseLib/X64/VmgExit.nasm  | 32 ++++++++++++++++++++++++
 6 files changed, 113 insertions(+)
 create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
 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..14b3f5721101 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -152,6 +152,7 @@ [Sources.Ia32]
   Ia32/ARShiftU64.c | MSFT
   Ia32/EnableCache.c | MSFT
   Ia32/DisableCache.c | MSFT
+  Ia32/VmgExit.nasm | MSFT
 
 
   Ia32/GccInline.c | GCC
@@ -286,6 +287,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/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/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/Ia32/VmgExit.nasm b/MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
new file mode 100644
index 000000000000..babc1bf437f2
--- /dev/null
+++ b/MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
@@ -0,0 +1,31 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+;   VmgExit.Asm
+;
+; Abstract:
+;
+;   AsmVmgExit function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmVmgExit (
+;   VOID
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExit)
+ASM_PFX(AsmVmgExit):
+    rep; vmmcall
+    ret
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
new file mode 100644
index 000000000000..173e12c36054
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
@@ -0,0 +1,32 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; 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] 106+ messages in thread

* [RFC PATCH v2 14/44] UefiCpuPkg: Implement library support for VMGEXIT
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (12 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 13/44] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 15/44] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
                   ` (30 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

To support issuing a VMGEXIT instruction, create a library that can be
used to perform GHCB and VMGEXIT related operations and to issue the
actual VMGEXIT instruction when using the GHCB.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/UefiCpuPkg.dec                    |  3 +
 UefiCpuPkg/UefiCpuPkg.dsc                    |  5 ++
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf | 33 +++++++++
 UefiCpuPkg/Include/Library/VmgExitLib.h      | 74 +++++++++++++++++++
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c   | 75 ++++++++++++++++++++
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni | 15 ++++
 6 files changed, 205 insertions(+)
 create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.h
 create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
 create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633c6..5d2bd5b7c0eb 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -53,6 +53,9 @@ [LibraryClasses.IA32, LibraryClasses.X64]
   ##
   MpInitLib|Include/Library/MpInitLib.h
 
+  ##  @libraryclass  Provides function to support VMGEXIT processing.
+  VmgExitLib|Include/Library/VmgExitLib.h
+
 [Guids]
   gUefiCpuPkgTokenSpaceGuid      = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
   gMsegSmramGuid                 = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978f1..3ab96f6f986f 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -63,6 +63,7 @@ [LibraryClasses.common.SEC]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.PEIM]
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
@@ -74,6 +75,7 @@ [LibraryClasses.common.PEIM]
 [LibraryClasses.IA32.PEIM, LibraryClasses.X64.PEIM]
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.DXE_DRIVER]
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
@@ -81,12 +83,14 @@ [LibraryClasses.common.DXE_DRIVER]
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.DXE_SMM_DRIVER]
   SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
   MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.UEFI_APPLICATION]
   UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
@@ -143,6 +147,7 @@ [Components.IA32, Components.X64]
       SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
   }
   UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [BuildOptions]
   *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
new file mode 100644
index 000000000000..f1c1af93b297
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -0,0 +1,33 @@
+## @file
+#  VMGEXIT Support Library.
+#
+#  Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VmgExitLib
+  MODULE_UNI_FILE                = VmgExitLib.uni
+  FILE_GUID                      = 3cd7368f-ef9b-4a9b-9571-2ed93813677e
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = VmgExitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  VmgExitLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
+
diff --git a/UefiCpuPkg/Include/Library/VmgExitLib.h b/UefiCpuPkg/Include/Library/VmgExitLib.h
new file mode 100644
index 000000000000..4b3c6908f1c1
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
@@ -0,0 +1,74 @@
+/** @file
+  Public header file for the VMGEXIT Support library class.
+
+  This library class defines some routines used when invoking the VMGEXIT
+  instruction in support of SEV-ES.
+
+  Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VMG_EXIT_LIB_H__
+#define __VMG_EXIT_LIB_H__
+
+#include <Register/Amd/Ghcb.h>
+
+
+/**
+  Perform VMGEXIT.
+
+  Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and
+  then handles the return actions.
+
+  @param[in]  GHCB       A pointer to the GHCB
+  @param[in]  ExitCode   VMGEXIT code to be assigned to the SwExitCode field of
+                         the GHCB.
+  @param[in]  ExitInfo1  VMGEXIT information to be assigned to the SwExitInfo1
+                         field of the GHCB.
+  @param[in]  ExitInfo2  VMGEXIT information to be assigned to the SwExitInfo2
+                         field of the GHCB.
+
+  @retval  0       VMGEXIT succeeded.
+  @retval  Others  VMGEXIT processing did not succeed. Exception number to
+                   be issued.
+
+**/
+UINTN
+EFIAPI
+VmgExit (
+  GHCB                *Ghcb,
+  UINT64              ExitCode,
+  UINT64              ExitInfo1,
+  UINT64              ExitInfo2
+  );
+
+/**
+  Perform pre-VMGEXIT initialization/preparation.
+
+  Performs the necessary steps in preparation for invoking VMGEXIT.
+
+  @param[in]  GHCB       A pointer to the GHCB
+
+**/
+VOID
+EFIAPI
+VmgInit (
+  GHCB                *Ghcb
+  );
+
+/**
+  Perform post-VMGEXIT cleanup.
+
+  Performs the necessary steps to cleanup after invoking VMGEXIT.
+
+  @param[in]  GHCB       A pointer to the GHCB
+
+**/
+VOID
+EFIAPI
+VmgDone (
+  GHCB                *Ghcb
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
new file mode 100644
index 000000000000..f7e2571cd726
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
@@ -0,0 +1,75 @@
+/** @file
+  VMGEXIT Support Library.
+
+  Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Register/Amd/Ghcb.h>
+#include <Library/BaseMemoryLib.h>
+
+STATIC
+UINTN
+VmgExitErrorCheck (
+  GHCB                *Ghcb
+  )
+{
+  GHCB_EXIT_INFO   ExitInfo;
+  UINTN            Reason, Action;
+
+  if (!Ghcb->SaveArea.SwExitInfo1) {
+    return 0;
+  }
+
+  ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
+  Action = ExitInfo.Elements.Lower32Bits;
+  if (Action == 1) {
+    Reason = ExitInfo.Elements.Upper32Bits;
+
+    switch (Reason) {
+    case UD_EXCEPTION:
+    case GP_EXCEPTION:
+      return Reason;
+    }
+  }
+
+  ASSERT (0);
+  return GP_EXCEPTION;
+}
+
+UINTN
+EFIAPI
+VmgExit (
+  GHCB                *Ghcb,
+  UINT64              ExitCode,
+  UINT64              ExitInfo1,
+  UINT64              ExitInfo2
+  )
+{
+  Ghcb->SaveArea.SwExitCode = ExitCode;
+  Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
+  Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
+  AsmVmgExit ();
+
+  return VmgExitErrorCheck (Ghcb);
+}
+
+VOID
+EFIAPI
+VmgInit (
+  GHCB                *Ghcb
+  )
+{
+  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
+}
+
+VOID
+EFIAPI
+VmgDone (
+  GHCB                *Ghcb
+  )
+{
+}
+
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
new file mode 100644
index 000000000000..65db52a05576
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// VMGEXIT support library instance.
+//
+// VMGEXIT support library instance.
+//
+// Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "VMGEXIT Support Library."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "VMGEXIT Support Library."
+
-- 
2.17.1


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

* [RFC PATCH v2 15/44] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (13 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 14/44] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC Lendacky, Thomas
                   ` (29 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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, Maurice Ma,
	Guo Dong, Benjamin You

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

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc                       |  5 +++
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  5 +++
 OvmfPkg/OvmfPkgX64.dsc                        |  5 +++
 UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |  2 +
 UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |  2 +
 .../DxeCpuExceptionHandlerLib.inf             |  5 +++
 .../PeiCpuExceptionHandlerLib.inf             |  5 +++
 .../SecPeiCpuExceptionHandlerLib.inf          |  5 +++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   | 19 ++++++++
 .../CpuExceptionCommon.h                      |  2 +
 .../CpuExceptionCommon.c                      |  2 +-
 .../Ia32/AMDSevVcCommon.c                     | 13 ++++++
 .../PeiDxeAMDSevVcHandler.c                   | 22 +++++++++
 .../PeiDxeSmmCpuException.c                   | 16 +++++++
 .../SecAMDSevVcHandler.c                      | 45 +++++++++++++++++++
 .../SecPeiCpuException.c                      | 16 +++++++
 .../X64/AMDSevVcCommon.c                      | 28 ++++++++++++
 17 files changed, 196 insertions(+), 1 deletion(-)
 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

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 4369cf6d55e5..61f9594b6925 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -232,6 +232,7 @@ [LibraryClasses.common.SEC]
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.PEI_CORE]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
@@ -270,6 +271,7 @@ [LibraryClasses.common.PEIM]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
@@ -295,6 +297,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
@@ -345,6 +348,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
   QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !if $(SMM_REQUIRE) == TRUE
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
 !else
@@ -388,6 +392,7 @@ [LibraryClasses.common.DXE_SMM_DRIVER]
   DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !ifdef $(SOURCE_DEBUG_ENABLE)
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a74f5028068e..5fcbf8868a19 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -237,6 +237,7 @@ [LibraryClasses.common.SEC]
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.PEI_CORE]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
@@ -275,6 +276,7 @@ [LibraryClasses.common.PEIM]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
@@ -300,6 +302,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
@@ -350,6 +353,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
   QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !if $(SMM_REQUIRE) == TRUE
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
 !else
@@ -393,6 +397,7 @@ [LibraryClasses.common.DXE_SMM_DRIVER]
   DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !ifdef $(SOURCE_DEBUG_ENABLE)
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index fd714d386e75..40d1caddafc1 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -237,6 +237,7 @@ [LibraryClasses.common.SEC]
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.PEI_CORE]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
@@ -275,6 +276,7 @@ [LibraryClasses.common.PEIM]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
@@ -300,6 +302,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
@@ -350,6 +353,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
   QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !if $(SMM_REQUIRE) == TRUE
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
 !else
@@ -393,6 +397,7 @@ [LibraryClasses.common.DXE_SMM_DRIVER]
   DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 !ifdef $(SOURCE_DEBUG_ENABLE)
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
 !endif
diff --git a/UefiPayloadPkg/UefiPayloadPkgIa32.dsc b/UefiPayloadPkg/UefiPayloadPkgIa32.dsc
index 11cf17ca0647..8428da45a45a 100644
--- a/UefiPayloadPkg/UefiPayloadPkgIa32.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkgIa32.dsc
@@ -233,6 +233,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.DXE_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
@@ -244,6 +245,7 @@ [LibraryClasses.common.DXE_DRIVER]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
diff --git a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
index 5b7994a62cda..b88aa8ede04f 100644
--- a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
@@ -233,6 +233,7 @@ [LibraryClasses.common.DXE_CORE]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.DXE_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
@@ -244,6 +245,7 @@ [LibraryClasses.common.DXE_DRIVER]
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index e41383573043..dc328e230de3 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -26,17 +26,21 @@ [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
   CpuExceptionCommon.c
   PeiDxeSmmCpuException.c
   DxeException.c
+  PeiDxeAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
@@ -57,3 +61,4 @@ [LibraryClasses]
   PeCoffGetEntryPointLib
   MemoryAllocationLib
   DebugLib
+  VmgExitLib
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index f31423ac0f91..37dbbdb35711 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -26,17 +26,21 @@ [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
   CpuExceptionCommon.c
   PeiCpuException.c
   PeiDxeSmmCpuException.c
+  PeiDxeAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -52,6 +56,7 @@ [LibraryClasses]
   HobLib
   MemoryAllocationLib
   SynchronizationLib
+  VmgExitLib
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard    # CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 6d25cafe2ca3..8d6dd5295ff6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -26,16 +26,20 @@ [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
   CpuExceptionCommon.c
   SecPeiCpuException.c
+  SecAMDSevVcHandler.c
+  AMDSevVcCommon.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -48,3 +52,4 @@ [LibraryClasses]
   PrintLib
   LocalApicLib
   PeCoffGetEntryPointLib
+  VmgExitLib
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
new file mode 100644
index 000000000000..94f9e6e5122d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -0,0 +1,19 @@
+
+#ifndef _AMD_SEV_VC_COMMON_H_
+#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/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/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/PeiDxeAMDSevVcHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
new file mode 100644
index 000000000000..d32de9efb09e
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -0,0 +1,22 @@
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Amd/Msr.h>
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+UINTN
+DoVcException (
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  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);
+}
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..e2a78be56c80
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -0,0 +1,45 @@
+
+#include <Library/BaseLib.h>
+#include <Register/Amd/Msr.h>
+#include "CpuExceptionCommon.h"
+#include "AMDSevVcCommon.h"
+
+
+#define GHCB_INIT 0x809000
+
+UINTN
+DoVcException(
+  EFI_SYSTEM_CONTEXT  Context
+  )
+{
+  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/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.
   //
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
new file mode 100644
index 000000000000..a56dcffe1d5d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -0,0 +1,28 @@
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/VmgExitLib.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] 106+ messages in thread

* [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (14 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 15/44] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-10-02 12:24   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 17/44] UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec phase Lendacky, Thomas
                   ` (28 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

The SEC phase of OVMF will need access to the MemEncryptSevLib library,
so make the library available during SEC.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
index 7c44d0952815..755d49cc22dc 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
@@ -14,7 +14,7 @@ [Defines]
   FILE_GUID                      = c1594631-3888-4be4-949f-9c630dbc842b
   MODULE_TYPE                    = BASE
   VERSION_STRING                 = 1.0
-  LIBRARY_CLASS                  = MemEncryptSevLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+  LIBRARY_CLASS                  = MemEncryptSevLib|SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
 
 #
 # The following information is for reference only and not required by the build
-- 
2.17.1


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

* [RFC PATCH v2 17/44] UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec phase
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (15 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
                   ` (27 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Sec/SecMain.inf |  1 +
 OvmfPkg/Sec/SecMain.c   | 29 ++++++++++++++++-------------
 2 files changed, 17 insertions(+), 13 deletions(-)

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/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 3914355cd17b..7f1dfb2e57c1 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);
 
   DEBUG ((EFI_D_INFO,
@@ -751,19 +767,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
-- 
2.17.1


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

* [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (16 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 17/44] UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec phase Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-10-02 12:31   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:52 ` [RFC PATCH v2 19/44] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
                   ` (26 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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 when running as an SEV-ES guest.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Sec/SecMain.inf |  1 +
 OvmfPkg/Sec/SecMain.c   | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 7f53845f5436..fdf00e5d8be3 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -51,6 +51,7 @@ [LibraryClasses]
   ExtractGuidedSectionLib
   LocalApicLib
   CpuExceptionHandlerLib
+  MemEncryptSevLib
 
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 7f1dfb2e57c1..20716d484ab0 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -25,6 +25,7 @@
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
+#include <Library/MemEncryptSevLib.h>
 
 #include <Ppi/TemporaryRamSupport.h>
 
@@ -755,6 +756,15 @@ SecCoreStartupWithStack (
 
   ProcessLibraryConstructorList (NULL, NULL);
 
+  //
+  // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
+  // caching in order to speed up the boot. Enable caching early for
+  // an SEV-ES guest.
+  //
+  if (MemEncryptSevEsIsEnabled()) {
+    AsmEnableCache ();
+  }
+
   DEBUG ((EFI_D_INFO,
     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
     (UINT32)(UINTN)BootFv,
-- 
2.17.1


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

* [RFC PATCH v2 19/44] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (17 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 20/44] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
                   ` (25 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 434 +++++++++++++++++-
 1 file changed, 433 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index a56dcffe1d5d..16091fe38f83 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -4,6 +4,425 @@
 #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
+BOOLEAN
+GhcbIsRegValid (
+  GHCB                *Ghcb,
+  GHCB_REGISTER       Reg
+  )
+{
+  UINT32  RegIndex = Reg / 8;
+  UINT32  RegBit   = Reg & 0x07;
+
+  return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
+}
+
+STATIC
+VOID
+GhcbSetRegValid (
+  GHCB                *Ghcb,
+  GHCB_REGISTER       Reg
+  )
+{
+  UINT32  RegIndex = Reg / 8;
+  UINT32  RegBit   = Reg & 0x07;
+
+  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
+}
+
+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;
+    }
+  }
+}
+
+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)) {
+  // IN immediate opcodes
+  case 0xE4:
+  case 0xE5:
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
+    break;
+
+  // OUT immediate opcodes
+  case 0xE6:
+  case 0xE7:
+    InstructionData->ImmediateSize = 1;
+    InstructionData->End++;
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
+    break;
+
+  // IN register opcodes
+  case 0xEC:
+  case 0xED:
+    ExitInfo |= IOIO_TYPE_IN;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  // OUT register opcodes
+  case 0xEE:
+  case 0xEF:
+    ExitInfo |= IOIO_TYPE_OUT;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  default:
+    return 0;
+  }
+
+  switch (*(InstructionData->OpCodes)) {
+  case 0xE4:
+  case 0xE6:
+  case 0xEC:
+  case 0xEE:
+    // Single-byte opcodes
+    ExitInfo |= IOIO_DATA_8;
+    break;
+
+  default:
+    // Length determined by instruction parsing
+    ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
+                                                          : IOIO_DATA_32;
+  }
+
+  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,
@@ -11,6 +430,8 @@ DoVcCommon (
   )
 {
   EFI_SYSTEM_CONTEXT_X64   *Regs = Context.SystemContextX64;
+  SEV_ES_INSTRUCTION_DATA  InstructionData;
+  NAE_EXIT                 NaeExit;
   UINTN                    ExitCode;
   UINTN                    Status;
 
@@ -18,8 +439,19 @@ DoVcCommon (
 
   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);
-- 
2.17.1


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

* [RFC PATCH v2 20/44] UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (18 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 19/44] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 21/44] MdePkg: Add support for the XGETBV instruction Lendacky, Thomas
                   ` (24 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 82 ++++++++++++++++---
 1 file changed, 70 insertions(+), 12 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 16091fe38f83..ce5514fd0fb6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -305,6 +305,22 @@ IoioExitInfo (
   UINT64  ExitInfo = 0;
 
   switch (*(InstructionData->OpCodes)) {
+  // INS opcodes
+  case 0x6C:
+  case 0x6D:
+    ExitInfo |= IOIO_TYPE_INS;
+    ExitInfo |= IOIO_SEG_ES;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
+  // OUTS opcodes
+  case 0x6E:
+  case 0x6F:
+    ExitInfo |= IOIO_TYPE_OUTS;
+    ExitInfo |= IOIO_SEG_DS;
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
+    break;
+
   // IN immediate opcodes
   case 0xE4:
   case 0xE5:
@@ -342,6 +358,8 @@ IoioExitInfo (
   }
 
   switch (*(InstructionData->OpCodes)) {
+  case 0x6C:
+  case 0x6E:
   case 0xE4:
   case 0xE6:
   case 0xEC:
@@ -388,8 +406,9 @@ IoioExit (
   SEV_ES_INSTRUCTION_DATA  *InstructionData
   )
 {
-  UINT64  ExitInfo1;
-  UINTN   Status;
+  UINT64   ExitInfo1, ExitInfo2;
+  UINTN    Status;
+  BOOLEAN  String;
 
   ExitInfo1 = IoioExitInfo (Regs, InstructionData);
   if (!ExitInfo1) {
@@ -407,17 +426,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] 106+ messages in thread

* [RFC PATCH v2 21/44] MdePkg: Add support for the XGETBV instruction
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (19 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 20/44] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 22/44] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events Lendacky, Thomas
                   ` (23 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

Under SEV-ES, a CPUID instruction requires the current value of the XCR0
register. In order to retrieve that value, the XGETBV instruction needs
to be executed.

Provide the necessary support to execute the XGETBV instruction.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Library/BaseLib/BaseLib.inf      |  2 ++
 MdePkg/Include/Library/BaseLib.h        | 16 ++++++++++++
 MdePkg/Library/BaseLib/Ia32/GccInline.c | 28 ++++++++++++++++++++
 MdePkg/Library/BaseLib/X64/GccInline.c  | 30 ++++++++++++++++++++++
 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm | 31 ++++++++++++++++++++++
 MdePkg/Library/BaseLib/X64/XGetBv.nasm  | 34 +++++++++++++++++++++++++
 6 files changed, 141 insertions(+)
 create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
 create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm

diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 14b3f5721101..ea3e284bf8bf 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -153,6 +153,7 @@ [Sources.Ia32]
   Ia32/EnableCache.c | MSFT
   Ia32/DisableCache.c | MSFT
   Ia32/VmgExit.nasm | MSFT
+  Ia32/XGetBv.nasm | MSFT
 
 
   Ia32/GccInline.c | GCC
@@ -288,6 +289,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..362bc2e05dbc 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/Ia32/GccInline.c b/MdePkg/Library/BaseLib/Ia32/GccInline.c
index 55d2e12bcdc9..9db5e48d9899 100644
--- a/MdePkg/Library/BaseLib/Ia32/GccInline.c
+++ b/MdePkg/Library/BaseLib/Ia32/GccInline.c
@@ -1780,3 +1780,31 @@ AsmVmgExit (
 }
 
 
+/**
+  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
+  )
+{
+  UINT64 Data;
+
+  __asm__ __volatile__ (
+    "xgetbv"
+    : "=A" (Data)
+    : "c"  (Index)
+    );
+
+  return Data;
+}
+
+
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 17539caa0798..0169382978ac 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1815,3 +1815,33 @@ AsmVmgExit (
 }
 
 
+/**
+  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),
+      "=d" (HighData)
+    : "c"  (Index)
+    );
+
+  return (((UINT64)HighData) << 32) | LowData;
+}
+
+
diff --git a/MdePkg/Library/BaseLib/Ia32/XGetBv.nasm b/MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
new file mode 100644
index 000000000000..8d14ba03d4a8
--- /dev/null
+++ b/MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
@@ -0,0 +1,31 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+;   XGetBv.Asm
+;
+; Abstract:
+;
+;   AsmXgetBv function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; UINT64
+; EFIAPI
+; AsmXGetBv (
+;   IN UINT32  Index
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmXGetBv)
+ASM_PFX(AsmXGetBv):
+    mov     ecx, [esp + 4]
+    xgetbv
+    ret
diff --git a/MdePkg/Library/BaseLib/X64/XGetBv.nasm b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
new file mode 100644
index 000000000000..239ecb58ab13
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
@@ -0,0 +1,34 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+;   XGetBv.Asm
+;
+; Abstract:
+;
+;   AsmXgetBv function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    DEFAULT REL
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; UINT64
+; 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] 106+ messages in thread

* [RFC PATCH v2 22/44] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (20 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 21/44] MdePkg: Add support for the XGETBV instruction Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 23/44] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
                   ` (22 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 .../X64/AMDSevVcCommon.c                      | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index ce5514fd0fb6..29119ba863d3 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -4,6 +4,8 @@
 #include <Library/DebugLib.h>
 #include "AMDSevVcCommon.h"
 
+#define CR4_OSXSAVE (1 << 18)
+
 typedef enum {
   LongMode64Bit        = 0,
   LongModeCompat32Bit,
@@ -481,6 +483,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,
@@ -497,6 +538,10 @@ DoVcCommon (
 
   ExitCode = Regs->ExceptionData;
   switch (ExitCode) {
+  case SvmExitCpuid:
+    NaeExit = CpuidExit;
+    break;
+
   case SvmExitIoioProt:
     NaeExit = IoioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 23/44] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (21 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 22/44] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 24/44] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
                   ` (21 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 29119ba863d3..748883419752 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -278,6 +278,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)
@@ -546,6 +594,10 @@ DoVcCommon (
     NaeExit = IoioExit;
     break;
 
+  case SvmExitMsr:
+    NaeExit = MsrExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH v2 24/44] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (22 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 23/44] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 25/44] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
                   ` (20 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 748883419752..aac460c388e3 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -79,8 +79,8 @@ typedef struct {
     UINT8  Scale;
   } Sib;
 
-  UINTN  RegData;
-  UINTN  RmData;
+  INTN  RegData;
+  INTN  RmData;
 } SEV_ES_INSTRUCTION_OPCODE_EXT;
 
 typedef struct {
@@ -152,6 +152,198 @@ GhcbSetRegValid (
   Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
 }
 
+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 (
@@ -262,6 +454,91 @@ InitInstructionData (
   DecodePrefixes (Regs, InstructionData);
 }
 
+STATIC
+UINTN
+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 (
@@ -598,6 +875,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitNpf:
+    NaeExit = MmioExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH v2 25/44] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (23 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 24/44] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 26/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
                   ` (19 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 aac460c388e3..f8966cc3eca0 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -555,6 +555,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 (
@@ -875,6 +893,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitWbinvd:
+    NaeExit = WbinvdExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 26/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (24 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 25/44] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 27/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
                   ` (18 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 f8966cc3eca0..1f6a1f9a30ce 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -865,6 +865,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,
@@ -881,6 +907,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] 106+ messages in thread

* [RFC PATCH v2 27/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (25 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 26/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 28/44] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
                   ` (17 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 1f6a1f9a30ce..a6534e1a59bb 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -865,6 +865,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 (
@@ -911,6 +940,10 @@ DoVcCommon (
     NaeExit = RdtscExit;
     break;
 
+  case SvmExitRdpmc:
+    NaeExit = RdpmcExit;
+    break;
+
   case SvmExitCpuid:
     NaeExit = CpuidExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 28/44] UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (26 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 27/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 29/44] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
                   ` (16 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 a6534e1a59bb..a4a840401398 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -826,6 +826,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 (
@@ -948,6 +966,10 @@ DoVcCommon (
     NaeExit = CpuidExit;
     break;
 
+  case SvmExitInvd:
+    NaeExit = InvdExit;
+    break;
+
   case SvmExitIoioProt:
     NaeExit = IoioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 29/44] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (27 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 28/44] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 30/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
                   ` (15 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 a4a840401398..e9449deaa98b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -573,6 +573,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 (
@@ -978,6 +1009,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitVmmCall:
+    NaeExit = VmmCallExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 30/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (28 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 29/44] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:52 ` [RFC PATCH v2 31/44] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
                   ` (14 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 e9449deaa98b..c8efc5c4c106 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -573,6 +573,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 (
@@ -1013,6 +1043,10 @@ DoVcCommon (
     NaeExit = VmmCallExit;
     break;
 
+  case SvmExitRdtscp:
+    NaeExit = RdtscpExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 31/44] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (29 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 30/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
@ 2019-09-19 19:52 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 32/44] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
                   ` (13 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:52 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 c8efc5c4c106..824175a80b9b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -555,6 +555,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 (
@@ -1051,6 +1078,10 @@ DoVcCommon (
     NaeExit = WbinvdExit;
     break;
 
+  case SvmExitMonitor:
+    NaeExit = MonitorExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 32/44] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (30 preceding siblings ...)
  2019-09-19 19:52 ` [RFC PATCH v2 31/44] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 33/44] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
                   ` (12 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

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

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 824175a80b9b..8cb595e5a625 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -555,6 +555,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 (
@@ -1082,6 +1107,10 @@ DoVcCommon (
     NaeExit = MonitorExit;
     break;
 
+  case SvmExitMwait:
+    NaeExit = MwaitExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v2 33/44] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (31 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 32/44] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 34/44] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
                   ` (11 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
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 8cb595e5a625..39e005618715 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -6,6 +6,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,
@@ -1051,6 +1057,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,
@@ -1067,6 +1127,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] 106+ messages in thread

* [RFC PATCH v2 34/44] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (32 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 33/44] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 35/44] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
                   ` (10 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

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 PcdSevEsActive. This flag can then be used to determine if
SEV-ES is active.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          | 2 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 1 +
 4 files changed, 5 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 37b3f64e578a..557507e9a466 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -68,4 +68,5 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive                    ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 82b77b63ea87..f26ffd5a2ef5 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
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive                    ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 107872b3679c..1dfe9a9cd756 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -260,6 +260,8 @@ struct _CPU_MP_DATA {
   // driver.
   //
   BOOLEAN                        WakeUpByInitSipiSipi;
+
+  BOOLEAN                        SevEsActive;
 };
 
 extern EFI_GUID mCpuInitMpLibHobGuid;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index d6f84c6f45c0..3e20900ec7bc 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1657,6 +1657,7 @@ MpInitLibInitialize (
     CpuMpData->MicrocodePatchAddress    = OldCpuMpData->MicrocodePatchAddress;
   }
   InitializeSpinLock(&CpuMpData->MpLock);
+  CpuMpData->SevEsActive      = PcdGetBool (PcdSevEsActive);
 
   //
   // Make sure no memory usage outside of the allocated buffer.
-- 
2.17.1


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

* [RFC PATCH v2 35/44] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (33 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 34/44] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 36/44] UefiCpuPkg: Add " Lendacky, Thomas
                   ` (9 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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, Jian J Wang,
	Hao A Wu, Dandan Bi

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

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

SEV-ES guest AP boot support needs to transition from 64-bit long mode
into 16-bit real mode. This will require a 16-bit code segment descriptor.
Reserve one of the spare segment descriptors (0x28) for this purpose.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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
-- 
2.17.1


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

* [RFC PATCH v2 36/44] UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (34 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 35/44] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-19 19:53 ` [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing Lendacky, Thomas
                   ` (8 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

A hypervisor is not allowed to update an SEV-ES guests register state,
so when booting an SEV-ES guest AP, the hypervisor is not allowed to
set the RIP to the guest requested value. Instead, an SEV-ES AP must be
transition from 64-bit long mode to 16-bit real mode in response to an
INIT-SIPI-SIPI sequence. This requires a 16-bit code segment descriptor.
For PEI, create this descriptor in the reset vector GDT table. For DXE,
create this descriptor from the newly reserved entry at location 0x28.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/CpuDxe/CpuGdt.h                          | 4 ++--
 UefiCpuPkg/CpuDxe/CpuGdt.c                          | 8 ++++----
 UefiCpuPkg/ResetVector/Vtf0/Ia16/Real16ToFlat32.asm | 9 +++++++++
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.h b/UefiCpuPkg/CpuDxe/CpuGdt.h
index e5c36f37b96a..80e224b47fcd 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;
@@ -49,7 +49,7 @@ struct _GDT_ENTRIES {
 #define LINEAR_CODE_SEL   OFFSET_OF (GDT_ENTRIES, LinearCode)
 #define SYS_DATA_SEL      OFFSET_OF (GDT_ENTRIES, SysData)
 #define SYS_CODE_SEL      OFFSET_OF (GDT_ENTRIES, SysCode)
-#define SPARE4_SEL        OFFSET_OF (GDT_ENTRIES, Spare4)
+#define SYS_CODE16_SEL    OFFSET_OF (GDT_ENTRIES, SysCode16)
 #define LINEAR_DATA64_SEL OFFSET_OF (GDT_ENTRIES, LinearData64)
 #define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64)
 #define SPARE5_SEL        OFFSET_OF (GDT_ENTRIES, Spare5)
diff --git a/UefiCpuPkg/CpuDxe/CpuGdt.c b/UefiCpuPkg/CpuDxe/CpuGdt.c
index 87fd6955f24b..6a80829be884 100644
--- a/UefiCpuPkg/CpuDxe/CpuGdt.c
+++ b/UefiCpuPkg/CpuDxe/CpuGdt.c
@@ -70,14 +70,14 @@ 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
+    0x09A,          // present, ring 0, code, execute/read
+    0x08F,          // page-granular, 16-bit
     0x0,            // base 31:24
   },
   //
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] 106+ messages in thread

* [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (35 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 36/44] UefiCpuPkg: Add " Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-10-02 14:54   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:53 ` [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
                   ` (7 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

A hypervisor is not allowed to update an SEV-ES guests register state,
so when booting an SEV-ES guest AP, the hypervisor is not allowed to
set the RIP to the guest requested value. Instead an SEV-ES AP must be
re-directed from within the guest to the actual requested staring location
as specified in the INIT-SIPI-SIPI sequence.

Provide reset vector code that contains support to jump to the desired
RIP location after having been started. This is required for only the
very first AP reset.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 80 ++++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
new file mode 100644
index 000000000000..1ac8b7ca7e85
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -0,0 +1,80 @@
+;------------------------------------------------------------------------------
+; @file
+; First code executed by processor after resetting.
+; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
+;
+; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+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
+;
+; standardProcessorSevEsReset:    (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:
+
-- 
2.17.1


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

* [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (36 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-10-02 15:15   ` [edk2-devel] " Laszlo Ersek
  2019-09-19 19:53 ` [RFC PATCH v2 40/44] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
                   ` (6 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

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
(PcdSevEsActive) 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.

The new 16-bit protected mode GDT entry is used 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.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   2 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  58 +++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  70 ++++-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 235 ++++++++++++++++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |  19 ++
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |   2 +-
 UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |   2 +-
 .../Library/MpInitLib/Ia32/MpFuncs.nasm       |  15 ++
 UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |   4 +-
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 239 ++++++++++++++++++
 11 files changed, 634 insertions(+), 14 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 557507e9a466..ad5f33451aa3 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -51,6 +51,7 @@ [LibraryClasses]
   UefiBootServicesTableLib
   DebugAgentLib
   SynchronizationLib
+  VmgExitLib
 
 [Protocols]
   gEfiTimerArchProtocolGuid                     ## SOMETIMES_CONSUMES
@@ -69,4 +70,5 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive                    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index f26ffd5a2ef5..4d4799aaa932 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -50,6 +50,7 @@ [LibraryClasses]
   UefiCpuLib
   SynchronizationLib
   PeiServicesLib
+  VmgExitLib
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber        ## CONSUMES
@@ -60,6 +61,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive                    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 1dfe9a9cd756..4cfb93ee4f77 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;
@@ -189,6 +194,8 @@ typedef struct {
   // Enable5LevelPaging indicates whether 5-level paging is enabled in long mode.
   //
   BOOLEAN               Enable5LevelPaging;
+  BOOLEAN               SevEsActive;
+  UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
 #pragma pack()
@@ -236,6 +243,7 @@ struct _CPU_MP_DATA {
   UINT8                          ApLoopMode;
   UINT8                          ApTargetCState;
   UINT16                         PmCodeSegment;
+  UINT16                         Pm16CodeSegment;
   CPU_AP_DATA                    *CpuData;
   volatile MP_CPU_EXCHANGE_INFO  *MpCpuExchangeInfo;
 
@@ -262,8 +270,45 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        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;
 
 /**
@@ -369,6 +414,19 @@ GetModeTransitionBuffer (
   IN UINTN                BufferSize
   );
 
+/**
+  Return the address of the SEV-ES AP jump table.
+
+  This buffer is required in order for an SEV-ES guest to transition from
+  UEFI into an OS.
+
+  @retval other   Return SEV-ES AP jump table buffer
+**/
+UINTN
+GetSevEsAPMemory (
+  VOID
+  );
+
 /**
   This function will be called by BSP to wakeup AP.
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index b17e287bbf49..8df5b6d919e6 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,39 @@ GetModeTransitionBuffer (
   return (UINTN)StartAddress;
 }
 
+/**
+  Return the address of the SEV-ES AP jump table.
+
+  This buffer is required in order for an SEV-ES guest to transition from
+  UEFI into an OS.
+
+  @retval other   Return SEV-ES AP jump table 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 +254,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 +306,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 +368,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 3e20900ec7bc..43aa9c0a4950 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -7,6 +7,9 @@
 **/
 
 #include "MpLib.h"
+#include <Library/VmgExitLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
 
 EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
 
@@ -288,6 +291,14 @@ GetApLoopMode (
       //
       ApLoopMode = ApInHltLoop;
     }
+
+    if (PcdGetBool (PcdSevEsActive)) {
+      //
+      // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
+      // protocol for starting APs
+      //
+      ApLoopMode = ApInHltLoop;
+    }
   }
 
   if (ApLoopMode != ApInMwaitLoop) {
@@ -555,6 +566,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 +827,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 ();
       }
     }
@@ -827,6 +961,9 @@ FillExchangeInfoData (
   ExchangeInfo->Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
+  ExchangeInfo->SevEsActive     = CpuMpData->SevEsActive;
+  ExchangeInfo->GhcbBase        = CpuMpData->GhcbBase;
+
   //
   // Get the BSP's data of GDT and IDT
   //
@@ -853,8 +990,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 +
@@ -907,7 +1045,8 @@ BackupAndPrepareWakeupBuffer(
   CopyMem (
     (VOID *) CpuMpData->WakeupBuffer,
     (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
-    CpuMpData->AddressMap.RendezvousFunnelSize
+    CpuMpData->AddressMap.RendezvousFunnelSize +
+      CpuMpData->AddressMap.SwitchToRealSize
     );
 }
 
@@ -928,6 +1067,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.
 
@@ -941,16 +1114,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);
 }
@@ -965,7 +1144,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 the SEV-ES AP jump table buffer.
+
+  @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;
+  }
 }
 
 /**
@@ -1002,6 +1204,7 @@ WakeUpAP (
       CpuMpData->InitFlag   != ApInitDone) {
     ResetVectorRequired = TRUE;
     AllocateResetVector (CpuMpData);
+    AllocateSevEsAPMemory (CpuMpData);
     FillExchangeInfoData (CpuMpData);
     SaveLocalApicTimerSetting (CpuMpData);
   }
@@ -1038,6 +1241,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
       //
@@ -1563,7 +1775,7 @@ MpInitLibInitialize (
   ASSERT (MaxLogicalProcessorNumber != 0);
 
   AsmGetAddressMap (&AddressMap);
-  ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+  ApResetVectorSize = GetApResetVectorSize (&AddressMap);
   ApStackSize = PcdGet32(PcdCpuApStackSize);
   ApLoopMode  = GetApLoopMode (&MonitorFilterSize);
 
@@ -1658,6 +1870,8 @@ MpInitLibInitialize (
   }
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsActive      = PcdGetBool (PcdSevEsActive);
+  CpuMpData->SevEsAPBuffer    = (UINTN) -1;
+  CpuMpData->GhcbBase         = PcdGet64 (PcdGhcbBase);
 
   //
   // Make sure no memory usage outside of the allocated buffer.
@@ -1724,6 +1938,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 3999603c3efc..56956a615b6b 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -279,6 +279,25 @@ GetModeTransitionBuffer (
   return 0;
 }
 
+/**
+  Return the address of the SEV-ES AP jump table.
+
+  This buffer is required in order for an SEV-ES guest to transition from
+  UEFI into an OS.
+
+  @retval other   Return SEV-ES AP jump table buffer
+**/
+UINTN
+GetSevEsAPMemory (
+  VOID
+  )
+{
+  //
+  // PEI phase doesn't need to do such transition. 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/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
index efb1bc2bf7cb..4f5a7c859a56 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
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 58ef369342a7..245f323f977b 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
@@ -41,3 +41,5 @@ ModeTransitionSegmentLocation       equ  LockLocation + 98h
 ModeHighMemoryLocation              equ  LockLocation + 9Ah
 ModeHighSegmentLocation             equ  LockLocation + 9Eh
 Enable5LevelPagingLocation          equ  LockLocation + 0A0h
+SevEsActiveLocation                 equ  LockLocation + 0A1h
+GhcbBaseLocation                    equ  LockLocation + 0A2h
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 87f2523e856f..bbc7432740ff 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -184,9 +184,97 @@ Releaselock:
     add        edi, StackStartAddressLocation
     add        rax, qword [edi]
     mov        rsp, rax
+
+    lea        edi, [esi + SevEsActiveLocation]
+    cmp        byte [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        byte [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
@@ -253,12 +341,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)--
@@ -324,6 +558,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
 
 ;-------------------------------------------------------------------------------------
-- 
2.17.1


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

* [RFC PATCH v2 40/44] MdePkg: Add a finalization function to the CPU protocol
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (37 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
@ 2019-09-19 19:53 ` Lendacky, Thomas
  2019-09-20 13:16 ` [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
                   ` (5 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-19 19:53 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>

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

Expand the CPU protocol to include a finalization function that can be
used to perform any final AP processing or AP environment setup before
transferring control over to an OS.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Include/Protocol/Cpu.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/MdePkg/Include/Protocol/Cpu.h b/MdePkg/Include/Protocol/Cpu.h
index e392f4cd9a13..1603797edd1c 100644
--- a/MdePkg/Include/Protocol/Cpu.h
+++ b/MdePkg/Include/Protocol/Cpu.h
@@ -258,6 +258,22 @@ EFI_STATUS
   );
 
 
+/**
+  This function is used to perform any CPU finalization operations needed
+  before exiting boot services.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return None
+
+**/
+typedef
+VOID
+(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
 /// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
@@ -287,6 +303,8 @@ struct _EFI_CPU_ARCH_PROTOCOL {
   /// a read-only field.
   ///
   UINT32                              DmaBufferAlignment;
+
+  EFI_CPU_FINALIZE                    Finalize;
 };
 
 extern EFI_GUID gEfiCpuArchProtocolGuid;
-- 
2.17.1


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

* [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (38 preceding siblings ...)
  2019-09-19 19:53 ` [RFC PATCH v2 40/44] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
@ 2019-09-20 13:16 ` Lendacky, Thomas
  2019-10-02 14:38   ` [edk2-devel] " Laszlo Ersek
  2019-09-20 13:16 ` [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
                   ` (4 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 13:16 UTC (permalink / raw)
  To: devel@edk2.groups.io

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

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

After having transitioned from UEFI to the OS, the OS will need to boot
the APs. For an SEV-ES guest, the APs will have been parked by UEFI using
GHCB pages allocated by UEFI. The hypervisor will write to the GHCB
SW_EXITINFO2 field of the GHCB when the AP is booted. As a result, the
GHCB pages must be marked reserved so that the OS does not attempt to use
them and experience memory corruption because of the hypervisor write.

Change the GHCB allocation from the default boot services memory to
reserved memory.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index d6733447bdf2..53eeb59702ae 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -49,9 +49,11 @@ AmdSevEsInitialize (
 
   //
   // Allocate GHCB pages.
+  //   Since the pages must survive across the UEFI to OS transition
+  //   make them reserved.
   //
   GhcbPageCount = mMaxCpuCount * 2;
-  GhcbBase = AllocatePages (GhcbPageCount);
+  GhcbBase = AllocateReservedPages (GhcbPageCount);
   ASSERT (GhcbBase);
 
   GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
-- 
2.17.1


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

* [RFC PATCH v2 41/44] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (40 preceding siblings ...)
  2019-09-20 13:16 ` [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
@ 2019-09-20 13:16 ` Lendacky, Thomas
  2019-09-20 13:16 ` [RFC PATCH v2 43/44] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
                   ` (2 subsequent siblings)
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 13:16 UTC (permalink / raw)
  To: devel@edk2.groups.io

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

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

Provide an MP finalization function that can be called from the CPU
protocol finalization function.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/Include/Library/MpInitLib.h  | 14 ++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.h    | 11 +++++++++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 18 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c    | 23 +++++++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 16 ++++++++++++++++
 5 files changed, 82 insertions(+)

diff --git a/UefiCpuPkg/Include/Library/MpInitLib.h b/UefiCpuPkg/Include/Library/MpInitLib.h
index 31eb227f1209..f9beeefca78e 100644
--- a/UefiCpuPkg/Include/Library/MpInitLib.h
+++ b/UefiCpuPkg/Include/Library/MpInitLib.h
@@ -378,4 +378,18 @@ MpInitLibStartupAllCPUs (
   IN  VOID                      *ProcedureArgument      OPTIONAL
   );
 
+/**
+  This service allows users of MpLib to make any finalization changes
+  before transferring control out of UEFI
+
+  @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 4cfb93ee4f77..5966510d4a1b 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -654,5 +654,16 @@ EnableDebugAgent (
   VOID
   );
 
+/**
+  Perform MpLib finalization before transferring control out of UEFI
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+
+**/
+EFI_STATUS
+MpFinalize (
+  IN CPU_MP_DATA   *CpuMpData
+  );
+
 #endif
 
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 8df5b6d919e6..16603ef3f20e 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -884,3 +884,21 @@ MpInitLibEnableDisableAP (
 
   return Status;
 }
+
+/**
+  MP finalization
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+**/
+EFI_STATUS
+MpFinalize (
+  IN CPU_MP_DATA   *CpuMpData
+  )
+{
+  //
+  // DXE phase will do this transition, but just return EFI_SUCCESS for now.
+  //
+  return EFI_SUCCESS;
+}
+
+
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 43aa9c0a4950..7fd478f735fb 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1728,6 +1728,29 @@ CheckAllAPs (
   return EFI_NOT_READY;
 }
 
+/**
+  MP finalization
+
+  This service allows users of MpLib to make any finalization changes
+  before transferring control out of UEFI.
+
+  This service must be invoked before exiting boot services.
+
+  @retval  EFI_SUCCESS           MP finalization succeeds.
+
+**/
+EFI_STATUS
+EFIAPI
+MpLibFinalize (
+  VOID
+  )
+{
+  CPU_MP_DATA              *CpuMpData;
+
+  CpuMpData = GetCpuMpData ();
+  return MpFinalize (CpuMpData);
+}
+
 /**
   MP Initialize Library initialization.
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 56956a615b6b..793d26b1bf12 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -604,4 +604,20 @@ MpInitLibEnableDisableAP (
   return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
 }
 
+/**
+  MP finalization
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+**/
+EFI_STATUS
+MpFinalize (
+  IN CPU_MP_DATA   *CpuMpData
+  )
+{
+  //
+  // PEI phase shouldn't do such a transition. So simply return EFI_SUCCESS.
+  //
+  return EFI_SUCCESS;
+}
+
 
-- 
2.17.1


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

* [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (39 preceding siblings ...)
  2019-09-20 13:16 ` [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
@ 2019-09-20 13:16 ` Lendacky, Thomas
  2019-12-12  8:24   ` Ni, Ray
  2019-09-20 13:16 ` [RFC PATCH v2 41/44] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
                   ` (3 subsequent siblings)
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 13:16 UTC (permalink / raw)
  To: devel@edk2.groups.io

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

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

Before UEFI transfers control to the OS, it must park the AP. This is
done using the AsmRelocateApLoop function to transition into 32-bit
non-paging mode. For an SEV-ES guest, a few additional things must be
done:
  - AsmRelocateApLoop must be updated to support SEV-ES. This means
    performing a VMGEXIT AP Reset Hold instead of an MWAIT or HLT loop.
  - Since the AP must transition to real mode, a small routine is copied
    to the WakeupBuffer area. Since the WakeupBuffer will be used by
    the AP during OS booting, it must be placed in reserved memory.
    Additionally, the AP stack must be located where it can be accessed
    in real mode.
  - Once the AP is in real mode it will transfer control to the
    destination specified by the OS in the SEV-ES AP Jump Table. The
    SEV-ES AP Jump Table address is communicated to the OS using the BSP
    GHCB MSR.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |   8 +-
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  54 ++++++-
 UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 134 ++++++++++++++++--
 3 files changed, 176 insertions(+), 20 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 5966510d4a1b..2d38a0e85a40 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -277,7 +277,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 {
@@ -331,8 +332,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
   );
 
 /**
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 16603ef3f20e..cf53b5026aa4 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;
@@ -86,6 +85,13 @@ GetWakeupBuffer (
 {
   EFI_STATUS              Status;
   EFI_PHYSICAL_ADDRESS    StartAddress;
+  EFI_MEMORY_TYPE         MemoryType;
+
+  if (PcdGetBool (PcdSevEsActive)) {
+    MemoryType = EfiReservedMemoryType;
+  } else {
+    MemoryType = EfiBootServicesData;
+  }
 
   //
   // Try to allocate buffer below 1M for waking vector.
@@ -98,7 +104,7 @@ GetWakeupBuffer (
   StartAddress = 0x88000;
   Status = gBS->AllocatePages (
                   AllocateMaxAddress,
-                  EfiBootServicesData,
+                  MemoryType,
                   EFI_SIZE_TO_PAGES (WakeupBufferSize),
                   &StartAddress
                   );
@@ -331,17 +337,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
@@ -895,9 +910,34 @@ MpFinalize (
   IN CPU_MP_DATA   *CpuMpData
   )
 {
-  //
-  // DXE phase will do this transition, but just return EFI_SUCCESS for now.
-  //
+  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/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index bbc7432740ff..3cb0cd5bb306 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -465,6 +465,10 @@ BITS 16
     ;     - IP for Real Mode (two bytes)
     ;     - CS for Real Mode (two bytes)
     ;
+    ; This label is also used with AsmRelocateApLoop. During MP finalization,
+    ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
+    ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
+    ;
 PM16Mode:
     mov        eax, cr0                    ; Read CR0
     btr        eax, 0                      ; Set PE=0
@@ -487,32 +491,95 @@ 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
+    ;   - Must be done while in 64-bit long mode so that writes to
+    ;     the GHCB memory will be unencrypted.
+    ;   - No NAE events can be generated once this is set otherwise
+    ;     the AP_RESET_HOLD 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_RESET_HOLD
+    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
@@ -525,6 +592,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
@@ -538,10 +607,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] 106+ messages in thread

* [RFC PATCH v2 43/44] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (41 preceding siblings ...)
  2019-09-20 13:16 ` [RFC PATCH v2 41/44] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
@ 2019-09-20 13:16 ` Lendacky, Thomas
  2019-09-20 13:16 ` [RFC PATCH v2 44/44] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
  2019-09-20 19:24 ` [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 13:16 UTC (permalink / raw)
  To: devel@edk2.groups.io

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

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

Provide support for the MP finalization routine within DXE. This
finalization function will invoke the MpInitLib MpLibFinalize() function
to perform the steps necessary to park an AP and be able to successfully
boot it under an OS.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.h | 12 ++++++++++++
 UefiCpuPkg/CpuDxe/CpuDxe.c | 21 ++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
index a6762f1a0b78..d071a32135b2 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.h
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
@@ -232,6 +232,18 @@ CpuSetMemoryAttributes (
   IN UINT64                     Attributes
   );
 
+/**
+  Perform any MpLib final actions before transitioning out of UEFI.
+
+  @param  This                   Protocol instance structure
+
+**/
+VOID
+EFIAPI
+CpuFinalize (
+  IN EFI_CPU_ARCH_PROTOCOL      *This
+  );
+
 /**
   Initialize Global Descriptor Table.
 
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c
index 7d7270e10b4a..bee44c0dd488 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.c
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.c
@@ -93,7 +93,8 @@ EFI_CPU_ARCH_PROTOCOL  gCpu = {
   CpuGetTimerValue,
   CpuSetMemoryAttributes,
   1,                          // NumberOfTimers
-  4                           // DmaBufferAlignment
+  4,                          // DmaBufferAlignment
+  CpuFinalize
 };
 
 //
@@ -499,6 +500,24 @@ CpuSetMemoryAttributes (
   return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
 }
 
+/**
+  Implementation of CpuFinalize() service of CPU Architecture Protocol.
+
+  This function performs any MpLib library finalization to perform required
+  actions before exiting boot services.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+**/
+VOID
+EFIAPI
+CpuFinalize (
+  IN EFI_CPU_ARCH_PROTOCOL     *This
+  )
+{
+  MpLibFinalize ();
+}
+
 /**
   Initializes the valid bits mask and valid address mask for MTRRs.
 
-- 
2.17.1


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

* [RFC PATCH v2 44/44] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (42 preceding siblings ...)
  2019-09-20 13:16 ` [RFC PATCH v2 43/44] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
@ 2019-09-20 13:16 ` Lendacky, Thomas
  2019-09-20 19:24 ` [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
  44 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 13:16 UTC (permalink / raw)
  To: devel@edk2.groups.io

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

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

Invoke the CPU finalization function when exiting boot services. This
allows for DXE and the MP Library to properly setup and park APs for an
SEV-ES guest so that it can be booted in the OS.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 5 +++++
 1 file changed, 5 insertions(+)

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
   //
-- 
2.17.1


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

* Re: [RFC PATCH v2 00/44] SEV-ES guest support
  2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
                   ` (43 preceding siblings ...)
  2019-09-20 13:16 ` [RFC PATCH v2 44/44] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
@ 2019-09-20 19:24 ` Lendacky, Thomas
  2019-09-24  1:55   ` [edk2-devel] " Dong, Eric
  44 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-20 19:24 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, Benjamin You,
	Dandan Bi, Guo Dong, Hao A Wu, Jian J Wang, Maurice Ma

On 9/19/19 2:52 PM, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> This patch series provides support for running EDK2/OVMF under SEV-ES.

I wanted to provide the full series so that everyone can see what is
involved with the support.

Providing multiple, smaller series of patches might be easier to review.
If that is desired, any suggestions/recommendations on how to best
approach that would be great.

Thanks,
Tom

> 
> 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
> 
> ---
> 
> These patches are based on commit:
> ada905ab5c0e ("MdeModulePkg DxeCore: Fix for missing Memory Attributes Table (MAT) update")
> 
> A version of the tree can be found at:
> https://github.com/AMDESE/ovmf/tree/sev-es-v7
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Benjamin You <benjamin.you@intel.com>
> Cc: Dandan Bi <dandan.bi@intel.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Guo Dong <guo.dong@intel.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Maurice Ma <maurice.ma@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> 
> Changes since v1:
> - Patches reworked to be more specific to the component/area being updated
>    and order of definition/usage
> - Created a library for VMGEXIT-related functions to replace use of inline
>    functions
> - Allocation method for GDT changed from AllocatePool to AllocatePages
> - Early caching only enabled for SEV-ES guests
> - Ensure AP loop mode set to halt loop mode for SEV-ES guests
> - Reserved SEC GHCB-related memory areas when S3 is enabled
> 
> Tom Lendacky (44):
>    MdePkg: Create PCDs to be used in support of SEV-ES
>    OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
>    OvmfPkg: Add support to perform SEV-ES initialization
>    OvmfPkg/ResetVector: Add support for a 32-bit SEV check
>    MdePkg: Add the MSR definition for the GHCB register
>    OvmfPkg: Create a GHCB page for use during Sec phase
>    OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
>    OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
>    MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
>    OvmfPkg: A per-CPU variable area for #VC usage
>    OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
>    MdePkg: Add a structure definition for the GHCB
>    MdePkg/BaseLib: Add support for the VMGEXIT instruction
>    UefiCpuPkg: Implement library support for VMGEXIT
>    UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
>    OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
>    UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec
>      phase
>    OvmfPkg/Sec: Enable cache early to speed up booting
>    UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
>    UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
>      events
>    MdePkg: Add support for the XGETBV instruction
>    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/MpInitLib: Update CPU MP data with a flag to indicate if
>      SEV-ES is active
>    MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
>    UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
>    OvmfPkg: Add support for SEV-ES AP reset vector re-directing
>    UefiCpuPkg: Allow AP booting under SEV-ES
>    OvmfPkg: Move the GHCB allocations into reserved memory
>    MdePkg: Add a finalization function to the CPU protocol
>    UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
>    UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
>    UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support
>      SEV-ES
>    MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
> 
>   MdeModulePkg/MdeModulePkg.dec                 |   15 +
>   OvmfPkg/OvmfPkg.dec                           |   10 +
>   UefiCpuPkg/UefiCpuPkg.dec                     |    3 +
>   OvmfPkg/OvmfPkgIa32.dsc                       |   10 +
>   OvmfPkg/OvmfPkgIa32X64.dsc                    |   10 +
>   OvmfPkg/OvmfPkgX64.dsc                        |   10 +
>   UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
>   UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
>   UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
>   OvmfPkg/OvmfPkgX64.fdf                        |    6 +
>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
>   MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
>   .../BaseMemEncryptSevLib.inf                  |    2 +-
>   OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
>   OvmfPkg/ResetVector/ResetVector.inf           |    6 +
>   OvmfPkg/Sec/SecMain.inf                       |    2 +
>   .../DxeCpuExceptionHandlerLib.inf             |    5 +
>   .../PeiCpuExceptionHandlerLib.inf             |    5 +
>   .../SecPeiCpuExceptionHandlerLib.inf          |    5 +
>   UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    3 +
>   UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    3 +
>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
>   .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
>   MdePkg/Include/Library/BaseLib.h              |   30 +
>   MdePkg/Include/Protocol/Cpu.h                 |   18 +
>   MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
>   MdePkg/Include/Register/Amd/Ghcb.h            |  105 ++
>   OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
>   UefiCpuPkg/CpuDxe/CpuDxe.h                    |   12 +
>   UefiCpuPkg/CpuDxe/CpuGdt.h                    |    4 +-
>   UefiCpuPkg/Include/Library/MpInitLib.h        |   14 +
>   UefiCpuPkg/Include/Library/VmgExitLib.h       |   74 +
>   .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
>   .../CpuExceptionCommon.h                      |    2 +
>   UefiCpuPkg/Library/MpInitLib/MpLib.h          |   77 +-
>   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       |   45 +
>   MdePkg/Library/BaseLib/X64/GccInline.c        |   47 +
>   .../MemEncryptSevLibInternal.c                |   77 +-
>   OvmfPkg/PlatformPei/AmdSev.c                  |   78 ++
>   OvmfPkg/PlatformPei/MemDetect.c               |   23 +
>   OvmfPkg/Sec/SecMain.c                         |   39 +-
>   UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
>   UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
>   .../CpuExceptionCommon.c                      |    2 +-
>   .../Ia32/AMDSevVcCommon.c                     |   13 +
>   .../PeiDxeAMDSevVcHandler.c                   |   22 +
>   .../PeiDxeSmmCpuException.c                   |   16 +
>   .../SecAMDSevVcHandler.c                      |   45 +
>   .../SecPeiCpuException.c                      |   16 +
>   .../X64/AMDSevVcCommon.c                      | 1200 +++++++++++++++++
>   UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
>   UefiCpuPkg/Library/MpInitLib/MpLib.c          |  259 +++-
>   UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |   75 ++
>   UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
>   MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   31 +
>   MdePkg/Library/BaseLib/Ia32/XGetBv.nasm       |   31 +
>   MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   32 +
>   MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   34 +
>   OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   80 ++
>   OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  256 +++-
>   OvmfPkg/ResetVector/ResetVector.nasmb         |   13 +
>   .../X64/ExceptionHandlerAsm.nasm              |   15 +
>   UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    2 +-
>   .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
>   UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
>   UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  373 ++++-
>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
>   .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
>   73 files changed, 3600 insertions(+), 97 deletions(-)
>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>   create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h
>   create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.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 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
>   create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
>   create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
>   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
>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
> 

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

* Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
  2019-09-20 19:24 ` [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
@ 2019-09-24  1:55   ` Dong, Eric
  2019-09-24 14:31     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Dong, Eric @ 2019-09-24  1:55 UTC (permalink / raw)
  To: thomas.lendacky@amd.com, Ni, Ray
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Singh, Brijesh, You, Benjamin, Bi, Dandan, Dong, Guo,
	Wu, Hao A, Wang, Jian J, Ma, Maurice, devel@edk2.groups.io,
	Dong, Eric

Hi Tom,

Thanks for you to contribute such a big changes. Seems like this is a big changes for current code, can you help to do a design review in TianoCore Design Meeting? It will be helpful for us to understand the code change and review it.

Ray is the owner of that meeting, you can contact him for the arrangement of your topic.

Thanks,
Eric

> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Lendacky, Thomas
> Sent: Saturday, September 21, 2019 3:25 AM
> 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>; You, Benjamin
> <benjamin.you@intel.com>; Bi, Dandan <dandan.bi@intel.com>; Dong, Guo
> <guo.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Ma, Maurice <maurice.ma@intel.com>
> Subject: Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
> 
> On 9/19/19 2:52 PM, Lendacky, Thomas wrote:
> > From: Tom Lendacky <thomas.lendacky@amd.com>
> >
> > This patch series provides support for running EDK2/OVMF under SEV-ES.
> 
> I wanted to provide the full series so that everyone can see what is involved
> with the support.
> 
> Providing multiple, smaller series of patches might be easier to review.
> If that is desired, any suggestions/recommendations on how to best approach
> that would be great.
> 
> Thanks,
> Tom
> 
> >
> > 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
> >
> > ---
> >
> > These patches are based on commit:
> > ada905ab5c0e ("MdeModulePkg DxeCore: Fix for missing Memory Attributes
> > Table (MAT) update")
> >
> > A version of the tree can be found at:
> > https://github.com/AMDESE/ovmf/tree/sev-es-v7
> >
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Benjamin You <benjamin.you@intel.com>
> > Cc: Dandan Bi <dandan.bi@intel.com>
> > Cc: Eric Dong <eric.dong@intel.com>
> > Cc: Guo Dong <guo.dong@intel.com>
> > Cc: Hao A Wu <hao.a.wu@intel.com>
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Jordan Justen <jordan.l.justen@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Liming Gao <liming.gao@intel.com>
> > Cc: Maurice Ma <maurice.ma@intel.com>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> >
> > Changes since v1:
> > - Patches reworked to be more specific to the component/area being
> updated
> >    and order of definition/usage
> > - Created a library for VMGEXIT-related functions to replace use of inline
> >    functions
> > - Allocation method for GDT changed from AllocatePool to AllocatePages
> > - Early caching only enabled for SEV-ES guests
> > - Ensure AP loop mode set to halt loop mode for SEV-ES guests
> > - Reserved SEC GHCB-related memory areas when S3 is enabled
> >
> > Tom Lendacky (44):
> >    MdePkg: Create PCDs to be used in support of SEV-ES
> >    OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
> >    OvmfPkg: Add support to perform SEV-ES initialization
> >    OvmfPkg/ResetVector: Add support for a 32-bit SEV check
> >    MdePkg: Add the MSR definition for the GHCB register
> >    OvmfPkg: Create a GHCB page for use during Sec phase
> >    OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
> >    OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
> >    MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page
> tables
> >    OvmfPkg: A per-CPU variable area for #VC usage
> >    OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
> >    MdePkg: Add a structure definition for the GHCB
> >    MdePkg/BaseLib: Add support for the VMGEXIT instruction
> >    UefiCpuPkg: Implement library support for VMGEXIT
> >    UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
> >    OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during
> SEC
> >    UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec
> >      phase
> >    OvmfPkg/Sec: Enable cache early to speed up booting
> >    UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
> >    UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
> >      events
> >    MdePkg: Add support for the XGETBV instruction
> >    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/MpInitLib: Update CPU MP data with a flag to indicate if
> >      SEV-ES is active
> >    MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
> >    UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
> >    OvmfPkg: Add support for SEV-ES AP reset vector re-directing
> >    UefiCpuPkg: Allow AP booting under SEV-ES
> >    OvmfPkg: Move the GHCB allocations into reserved memory
> >    MdePkg: Add a finalization function to the CPU protocol
> >    UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
> >    UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
> >    UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support
> >      SEV-ES
> >    MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
> >
> >   MdeModulePkg/MdeModulePkg.dec                 |   15 +
> >   OvmfPkg/OvmfPkg.dec                           |   10 +
> >   UefiCpuPkg/UefiCpuPkg.dec                     |    3 +
> >   OvmfPkg/OvmfPkgIa32.dsc                       |   10 +
> >   OvmfPkg/OvmfPkgIa32X64.dsc                    |   10 +
> >   OvmfPkg/OvmfPkgX64.dsc                        |   10 +
> >   UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
> >   UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
> >   UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
> >   OvmfPkg/OvmfPkgX64.fdf                        |    6 +
> >   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
> >   MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
> >   .../BaseMemEncryptSevLib.inf                  |    2 +-
> >   OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
> >   OvmfPkg/ResetVector/ResetVector.inf           |    6 +
> >   OvmfPkg/Sec/SecMain.inf                       |    2 +
> >   .../DxeCpuExceptionHandlerLib.inf             |    5 +
> >   .../PeiCpuExceptionHandlerLib.inf             |    5 +
> >   .../SecPeiCpuExceptionHandlerLib.inf          |    5 +
> >   UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    3 +
> >   UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    3 +
> >   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
> >   .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
> >   MdePkg/Include/Library/BaseLib.h              |   30 +
> >   MdePkg/Include/Protocol/Cpu.h                 |   18 +
> >   MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
> >   MdePkg/Include/Register/Amd/Ghcb.h            |  105 ++
> >   OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
> >   UefiCpuPkg/CpuDxe/CpuDxe.h                    |   12 +
> >   UefiCpuPkg/CpuDxe/CpuGdt.h                    |    4 +-
> >   UefiCpuPkg/Include/Library/MpInitLib.h        |   14 +
> >   UefiCpuPkg/Include/Library/VmgExitLib.h       |   74 +
> >   .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
> >   .../CpuExceptionCommon.h                      |    2 +
> >   UefiCpuPkg/Library/MpInitLib/MpLib.h          |   77 +-
> >   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       |   45 +
> >   MdePkg/Library/BaseLib/X64/GccInline.c        |   47 +
> >   .../MemEncryptSevLibInternal.c                |   77 +-
> >   OvmfPkg/PlatformPei/AmdSev.c                  |   78 ++
> >   OvmfPkg/PlatformPei/MemDetect.c               |   23 +
> >   OvmfPkg/Sec/SecMain.c                         |   39 +-
> >   UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
> >   UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
> >   .../CpuExceptionCommon.c                      |    2 +-
> >   .../Ia32/AMDSevVcCommon.c                     |   13 +
> >   .../PeiDxeAMDSevVcHandler.c                   |   22 +
> >   .../PeiDxeSmmCpuException.c                   |   16 +
> >   .../SecAMDSevVcHandler.c                      |   45 +
> >   .../SecPeiCpuException.c                      |   16 +
> >   .../X64/AMDSevVcCommon.c                      | 1200 +++++++++++++++++
> >   UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
> >   UefiCpuPkg/Library/MpInitLib/MpLib.c          |  259 +++-
> >   UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
> >   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |   75 ++
> >   UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
> >   MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   31 +
> >   MdePkg/Library/BaseLib/Ia32/XGetBv.nasm       |   31 +
> >   MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   32 +
> >   MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   34 +
> >   OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   80 ++
> >   OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  256 +++-
> >   OvmfPkg/ResetVector/ResetVector.nasmb         |   13 +
> >   .../X64/ExceptionHandlerAsm.nasm              |   15 +
> >   UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    2 +-
> >   .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
> >   UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
> >   UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  373 ++++-
> >   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
> >   .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
> >   73 files changed, 3600 insertions(+), 97 deletions(-)
> >   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
> >   create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h
> >   create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.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 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
> >   create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
> >   create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
> >   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
> >   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
> >
> 
> 


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

* Re: [edk2-devel] [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  2019-09-19 19:52 ` [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
@ 2019-09-24 11:53   ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-24 11:53 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Create a function that can be used to determine if the VM is running
> as an SEV-ES guest.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> 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;
>  }
> 

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

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

* Re: [edk2-devel] [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization
  2019-09-19 19:52 ` [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
@ 2019-09-24 11:59   ` Laszlo Ersek
  2019-09-24 14:43     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-24 11:59 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> When SEV-ES is active, then SEV is also active. Add support to the SEV
> initialization function to also check for SEV-ES being active. If SEV-ES
> is active, set the SEV-ES active PCD (PcdSevEsActive).
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgIa32.dsc             |  3 +++
>  OvmfPkg/OvmfPkgIa32X64.dsc          |  3 +++
>  OvmfPkg/OvmfPkgX64.dsc              |  3 +++
>  OvmfPkg/PlatformPei/PlatformPei.inf |  1 +
>  OvmfPkg/PlatformPei/AmdSev.c        | 26 ++++++++++++++++++++++++++
>  5 files changed, 36 insertions(+)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 6ab730018694..0ce5c01722ef 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -558,6 +558,9 @@ [PcdsDynamicDefault]
>    # Set memory encryption mask
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>  
> +  # Set SEV-ES defaults
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index f163aa267132..e7455e35a55d 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -570,6 +570,9 @@ [PcdsDynamicDefault]
>    # Set memory encryption mask
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>  
> +  # Set SEV-ES defaults
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index fa98f16a3fb3..0b8305cd10a2 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -569,6 +569,9 @@ [PcdsDynamicDefault]
>    # Set memory encryption mask
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>  
> +  # Set SEV-ES defaults
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index d9fd9c8f05b3..2736347a2e03 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -100,6 +100,7 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive

(1) Can you add this next to
"gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask"?

>  
>  [FixedPcd]
>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 2ae8126ccf8a..7ae2f26a2ba7 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -19,6 +19,27 @@
>  
>  #include "Platform.h"
>  
> +/**
> +
> +  Initialize SEV-ES support if running an SEV-ES guest.

(2) s/an/in an/? (Just asking)

> +
> +  **/
> +STATIC
> +VOID
> +AmdSevEsInitialize (
> +  VOID
> +  )
> +{
> +  RETURN_STATUS     PcdStatus;
> +
> +  if (!MemEncryptSevEsIsEnabled ()) {
> +    return;
> +  }
> +
> +  PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);

(3) Please write TRUE, not 1.

> +  ASSERT_RETURN_ERROR (PcdStatus);
> +}
> +
>  /**
>  
>    Function checks if SEV support is available, if present then it sets
> @@ -89,4 +110,9 @@ AmdSevInitialize (
>        EfiBootServicesData                // MemoryType
>        );
>    }
> +
> +  //
> +  // Check and perform SEV-ES initialization if required.
> +  //
> +  AmdSevEsInitialize ();
>  }
> 

With (1) and (3) fixed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-19 19:52 ` [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-09-24 13:42   ` Laszlo Ersek
  2019-09-24 13:50     ` Laszlo Ersek
  2019-09-24 18:57     ` Lendacky, Thomas
  0 siblings, 2 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-24 13:42 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> During BSP startup, the reset vector code will issue a CPUID instruction
> while in 32-bit mode. When running as an SEV-ES guest, this will trigger
> a #VC exception.

(1) In the assembly source code, please annotate both CPUID instructions
under CheckSevFeature, such as

  ; raises #VC when in an SEV-ES guest

> 
> Add exception handling support to the early reset vector code to catch
> these exceptions.  Also, since the guest is in 32-bit mode at this point,
> writes to the GHCB will be encrypted and thus not able to be read by the
> hypervisor, so use the GHCB CPUID request/response protocol to obtain the
> requested CPUID function values and provide these to the guest.
> 
> The exception handling support is active during the SEV check and uses the
> OVMF temporary RAM space for a stack. After the SEV check is complete, the
> exception handling support is removed and the stack pointer cleared.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/ResetVector/ResetVector.inf       |   2 +
>  OvmfPkg/ResetVector/Ia32/PageTables64.asm | 177 +++++++++++++++++++++-
>  OvmfPkg/ResetVector/ResetVector.nasmb     |   1 +
>  3 files changed, 179 insertions(+), 1 deletion(-)
> 
> 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..40f7814c1134 100644
> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> @@ -33,10 +33,21 @@ BITS    32
>  
>  ; Check if Secure Encrypted Virtualization (SEV) feature is enabled
>  ;
> -; If SEV is enabled then EAX will be at least 32
> +; Modified:  EAX, EBX, ECX, EDX, ESP
> +;
> +; If SEV is enabled then EAX will be at least 32.
>  ; If SEV is disabled then EAX will be zero.
>  ;
>  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

(2) Can we %define SEV_TOP_OF_STACK in this file, or does it have to be
in "ResetVector.nasmb"?

(3) Do we have an estimate how much stack we need? This would be a
constraint on PcdOvmfSecPeiTempRamSize. The limit would be nice to
document (perhaps in a comment somewhere).

> +    mov       eax, ADDR_OF(Idtr)
> +    lidt      [cs:eax]
> +
>      ; Check if we have a valid (0x8000_001F) CPUID leaf
>      mov       eax, 0x80000000
>      cpuid
> @@ -73,6 +84,15 @@ NoSev:
>      xor       eax, eax
>  
>  SevExit:
> +    ;
> +    ; Clear exception handlers and stack
> +    ;
> +    push      eax
> +    mov       eax, ADDR_OF(IdtrClear)
> +    lidt      [cs:eax]
> +    pop       eax
> +    mov       esp, 0
> +

I'm not sure the resultant IDT and ESP contents are the same as before
(pre-patch), but I guess these values should be OK too.

>      OneTimeCallRet CheckSevFeature
>  
>  ;
> @@ -146,3 +166,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

(4) Can you steal the DebugLog / PrintStringSi code from
"OvmfPkg/QemuVideoDxe/VbeShim.asm", and print a simple message to the
QEMU debug port, whenever you jump to SevEsIdtCommon?

This is basically an ASSERT(). It should have a message, if possible.
(I'm not sure if the OUT instruction will work with SEV-ES at this
stage, i.e. in 32-bit mode.)

> +
> +    ;
> +    ; 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

(5) Can we %define macros for these offsets? (Including the size
constant 32.)

> +
> +    ; Save CPUID function and initial register request
> +    mov     [esp + 28], eax
> +    xor     eax, eax
> +    mov     [esp + 24], eax

(6) The comment "CPUID register" (at offset 24), and the other comment
"initial register", are pretty confusing. Can you please document:

- the mapping: 0->EAX, ... 3->EDX,
- and the fact that the dword at [esp + 24] is the loop variable?

> +
> +    ; 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

(7) Please %define GHCBInfoCpuIdRequest or something similar for the
value 4.

> +    mov     edx, [esp + 28]
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +
> +    ; Issue VMGEXIT (rep; vmmcall)
> +    db      0xf3
> +    db      0x0f
> +    db      0x01
> +    db      0xd9

(8) Can you please file an RFE at <https://bugzilla.nasm.us/>, for
supporting this instruction, and add the link here, as a comment? I've
been fighting an uphill battle against DB-encoded instructions in edk2
assembly code.

> +
> +    ;
> +    ; 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

(9) Please %define GHCBInfoCpuIdResponse for value 5.

> +    jne     SevEsIdtCommon

(10) Please see (4). The message could be, "no GHCBInfoCpuIdResponse
received", or similar.

> +
> +    ; Save returned value
> +    shr     eax, 30
> +    and     eax, 0x3

(11) Do we need the AND after the SHR? I think the new high order bits
from the SHR should be zero.

> +    shl     eax, 2
> +    mov     ecx, esp
> +    add     ecx, eax
> +    mov     [ecx], edx

(12) The beauty of the lean and mean x86 instruction set:

       mov     [esp + eax * 4], edx

(I tested just this one instruction with nasm + ndisasm; the encoding is
0x89, 0x14, 0x84.)

> +
> +    ; 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

(13) Please see (5).

> +    add     word [esp], 2           ; Skip over the CPUID instruction

OK, this seems safe. CPUID has only one encoding (0x0F, 0xA2), and we
checked SW_EXITCODE = 0x72 at the top.

> +    iret
> +
> +ALIGN   2
> +
> +Idtr:
> +    dw      IDT_END - IDT_BASE - 1  ; Limit
> +    dd      ADDR_OF(IDT_BASE)       ; Base
> +
> +IdtrClear:
> +    dw      0                       ; Limit
> +    dd      0                       ; Base
> +
> +ALIGN   16
> +
> +;
> +; The Interrupt Descriptor Table (IDT)
> +;   This will be used to determine if SEV-ES is enabled.  Upon execution
> +;   of the CPUID instruction, a VMM Communication Exception will occur.
> +;   This will tell us if SEV-ES is enabled.  We can use the current value
> +;   of the GHCB MSR to determine the SEV attributes.
> +;
> +IDT_BASE:
> +;
> +; Vectors 0 - 28
> +;
> +%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:

(14) Above, we have two explicit jumps to SevEsIdtCommon, and I've asked
for meaningful assertion messages there.

For the uninteresting exception vectors 0-28 and 30-31, can we use a
handler that is not directly SevEsIdtCommon, but logs a message, and
then jumps to SevEsIdtCommon? (It could even be implemented as a
"prefix" of SevEsIdtCommon, and then no jump would be required.)

> 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
>  
> 

(I've commented on this under (2).)

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-24 13:42   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-24 13:50     ` Laszlo Ersek
  2019-09-24 18:57     ` Lendacky, Thomas
  1 sibling, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-24 13:50 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/24/19 15:42, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:

>> +    mov       esp, SEV_TOP_OF_STACK

> (3) Do we have an estimate how much stack we need? This would be a
> constraint on PcdOvmfSecPeiTempRamSize. The limit would be nice to
> document (perhaps in a comment somewhere).

Ah I've just been reminded by [RFC PATCH v2 06/44]:

we could use "%if" + "%error" to catch (at compile time) if the stack is
too small.

(Not sure if this is overly useful; it might not be, if the stack demand
is negligible.)

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
  2019-09-24  1:55   ` [edk2-devel] " Dong, Eric
@ 2019-09-24 14:31     ` Lendacky, Thomas
  2019-09-25 22:31       ` Ni, Ray
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-24 14:31 UTC (permalink / raw)
  To: Dong, Eric, Ni, Ray
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Singh, Brijesh, You, Benjamin, Bi, Dandan, Dong, Guo,
	Wu, Hao A, Wang, Jian J, Ma, Maurice, devel@edk2.groups.io

On 9/23/19 8:55 PM, Dong, Eric wrote:
> Hi Tom,

Hi Eric,

> 
> Thanks for you to contribute such a big changes. Seems like this is a big changes for current code, can you help to do a design review in TianoCore Design Meeting? It will be helpful for us to understand the code change and review it.
> 
> Ray is the owner of that meeting, you can contact him for the arrangement of your topic.

Thanks for the info, Eric.

Ray, I see on the TianoCore wiki that I should contact Stephano to be
added to the meeting agenda. Should I follow those directions?

Thanks,
Tom

> 
> Thanks,
> Eric
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
>> Lendacky, Thomas
>> Sent: Saturday, September 21, 2019 3:25 AM
>> 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>; You, Benjamin
>> <benjamin.you@intel.com>; Bi, Dandan <dandan.bi@intel.com>; Dong, Guo
>> <guo.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J
>> <jian.j.wang@intel.com>; Ma, Maurice <maurice.ma@intel.com>
>> Subject: Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
>>
>> On 9/19/19 2:52 PM, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> This patch series provides support for running EDK2/OVMF under SEV-ES.
>>
>> I wanted to provide the full series so that everyone can see what is involved
>> with the support.
>>
>> Providing multiple, smaller series of patches might be easier to review.
>> If that is desired, any suggestions/recommendations on how to best approach
>> that would be great.
>>
>> Thanks,
>> Tom
>>
>>>
>>> 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
>>>
>>> ---
>>>
>>> These patches are based on commit:
>>> ada905ab5c0e ("MdeModulePkg DxeCore: Fix for missing Memory Attributes
>>> Table (MAT) update")
>>>
>>> A version of the tree can be found at:
>>> https://github.com/AMDESE/ovmf/tree/sev-es-v7
>>>
>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>> Cc: Benjamin You <benjamin.you@intel.com>
>>> Cc: Dandan Bi <dandan.bi@intel.com>
>>> Cc: Eric Dong <eric.dong@intel.com>
>>> Cc: Guo Dong <guo.dong@intel.com>
>>> Cc: Hao A Wu <hao.a.wu@intel.com>
>>> Cc: Jian J Wang <jian.j.wang@intel.com>
>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Liming Gao <liming.gao@intel.com>
>>> Cc: Maurice Ma <maurice.ma@intel.com>
>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>> Cc: Ray Ni <ray.ni@intel.com>
>>>
>>> Changes since v1:
>>> - Patches reworked to be more specific to the component/area being
>> updated
>>>    and order of definition/usage
>>> - Created a library for VMGEXIT-related functions to replace use of inline
>>>    functions
>>> - Allocation method for GDT changed from AllocatePool to AllocatePages
>>> - Early caching only enabled for SEV-ES guests
>>> - Ensure AP loop mode set to halt loop mode for SEV-ES guests
>>> - Reserved SEC GHCB-related memory areas when S3 is enabled
>>>
>>> Tom Lendacky (44):
>>>    MdePkg: Create PCDs to be used in support of SEV-ES
>>>    OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
>>>    OvmfPkg: Add support to perform SEV-ES initialization
>>>    OvmfPkg/ResetVector: Add support for a 32-bit SEV check
>>>    MdePkg: Add the MSR definition for the GHCB register
>>>    OvmfPkg: Create a GHCB page for use during Sec phase
>>>    OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
>>>    OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
>>>    MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page
>> tables
>>>    OvmfPkg: A per-CPU variable area for #VC usage
>>>    OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
>>>    MdePkg: Add a structure definition for the GHCB
>>>    MdePkg/BaseLib: Add support for the VMGEXIT instruction
>>>    UefiCpuPkg: Implement library support for VMGEXIT
>>>    UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
>>>    OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during
>> SEC
>>>    UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec
>>>      phase
>>>    OvmfPkg/Sec: Enable cache early to speed up booting
>>>    UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
>>>    UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
>>>      events
>>>    MdePkg: Add support for the XGETBV instruction
>>>    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/MpInitLib: Update CPU MP data with a flag to indicate if
>>>      SEV-ES is active
>>>    MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
>>>    UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
>>>    OvmfPkg: Add support for SEV-ES AP reset vector re-directing
>>>    UefiCpuPkg: Allow AP booting under SEV-ES
>>>    OvmfPkg: Move the GHCB allocations into reserved memory
>>>    MdePkg: Add a finalization function to the CPU protocol
>>>    UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
>>>    UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
>>>    UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support
>>>      SEV-ES
>>>    MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
>>>
>>>   MdeModulePkg/MdeModulePkg.dec                 |   15 +
>>>   OvmfPkg/OvmfPkg.dec                           |   10 +
>>>   UefiCpuPkg/UefiCpuPkg.dec                     |    3 +
>>>   OvmfPkg/OvmfPkgIa32.dsc                       |   10 +
>>>   OvmfPkg/OvmfPkgIa32X64.dsc                    |   10 +
>>>   OvmfPkg/OvmfPkgX64.dsc                        |   10 +
>>>   UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
>>>   UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
>>>   UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
>>>   OvmfPkg/OvmfPkgX64.fdf                        |    6 +
>>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
>>>   MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
>>>   .../BaseMemEncryptSevLib.inf                  |    2 +-
>>>   OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
>>>   OvmfPkg/ResetVector/ResetVector.inf           |    6 +
>>>   OvmfPkg/Sec/SecMain.inf                       |    2 +
>>>   .../DxeCpuExceptionHandlerLib.inf             |    5 +
>>>   .../PeiCpuExceptionHandlerLib.inf             |    5 +
>>>   .../SecPeiCpuExceptionHandlerLib.inf          |    5 +
>>>   UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    3 +
>>>   UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    3 +
>>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
>>>   .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
>>>   MdePkg/Include/Library/BaseLib.h              |   30 +
>>>   MdePkg/Include/Protocol/Cpu.h                 |   18 +
>>>   MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
>>>   MdePkg/Include/Register/Amd/Ghcb.h            |  105 ++
>>>   OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
>>>   UefiCpuPkg/CpuDxe/CpuDxe.h                    |   12 +
>>>   UefiCpuPkg/CpuDxe/CpuGdt.h                    |    4 +-
>>>   UefiCpuPkg/Include/Library/MpInitLib.h        |   14 +
>>>   UefiCpuPkg/Include/Library/VmgExitLib.h       |   74 +
>>>   .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
>>>   .../CpuExceptionCommon.h                      |    2 +
>>>   UefiCpuPkg/Library/MpInitLib/MpLib.h          |   77 +-
>>>   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       |   45 +
>>>   MdePkg/Library/BaseLib/X64/GccInline.c        |   47 +
>>>   .../MemEncryptSevLibInternal.c                |   77 +-
>>>   OvmfPkg/PlatformPei/AmdSev.c                  |   78 ++
>>>   OvmfPkg/PlatformPei/MemDetect.c               |   23 +
>>>   OvmfPkg/Sec/SecMain.c                         |   39 +-
>>>   UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
>>>   UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
>>>   .../CpuExceptionCommon.c                      |    2 +-
>>>   .../Ia32/AMDSevVcCommon.c                     |   13 +
>>>   .../PeiDxeAMDSevVcHandler.c                   |   22 +
>>>   .../PeiDxeSmmCpuException.c                   |   16 +
>>>   .../SecAMDSevVcHandler.c                      |   45 +
>>>   .../SecPeiCpuException.c                      |   16 +
>>>   .../X64/AMDSevVcCommon.c                      | 1200 +++++++++++++++++
>>>   UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
>>>   UefiCpuPkg/Library/MpInitLib/MpLib.c          |  259 +++-
>>>   UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
>>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |   75 ++
>>>   UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
>>>   MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   31 +
>>>   MdePkg/Library/BaseLib/Ia32/XGetBv.nasm       |   31 +
>>>   MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   32 +
>>>   MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   34 +
>>>   OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   80 ++
>>>   OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  256 +++-
>>>   OvmfPkg/ResetVector/ResetVector.nasmb         |   13 +
>>>   .../X64/ExceptionHandlerAsm.nasm              |   15 +
>>>   UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    2 +-
>>>   .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
>>>   UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
>>>   UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  373 ++++-
>>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
>>>   .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
>>>   73 files changed, 3600 insertions(+), 97 deletions(-)
>>>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>>   create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h
>>>   create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.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 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
>>>   create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
>>>   create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
>>>   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
>>>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
>>>
>>
>> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization
  2019-09-24 11:59   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-24 14:43     ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-24 14:43 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 9/24/19 6:59 AM, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> When SEV-ES is active, then SEV is also active. Add support to the SEV
>> initialization function to also check for SEV-ES being active. If SEV-ES
>> is active, set the SEV-ES active PCD (PcdSevEsActive).
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgIa32.dsc             |  3 +++
>>  OvmfPkg/OvmfPkgIa32X64.dsc          |  3 +++
>>  OvmfPkg/OvmfPkgX64.dsc              |  3 +++
>>  OvmfPkg/PlatformPei/PlatformPei.inf |  1 +
>>  OvmfPkg/PlatformPei/AmdSev.c        | 26 ++++++++++++++++++++++++++
>>  5 files changed, 36 insertions(+)
>>
>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>> index 6ab730018694..0ce5c01722ef 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -558,6 +558,9 @@ [PcdsDynamicDefault]
>>    # Set memory encryption mask
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>>  
>> +  # Set SEV-ES defaults
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index f163aa267132..e7455e35a55d 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -570,6 +570,9 @@ [PcdsDynamicDefault]
>>    # Set memory encryption mask
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>>  
>> +  # Set SEV-ES defaults
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index fa98f16a3fb3..0b8305cd10a2 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -569,6 +569,9 @@ [PcdsDynamicDefault]
>>    # Set memory encryption mask
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
>>  
>> +  # Set SEV-ES defaults
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index d9fd9c8f05b3..2736347a2e03 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -100,6 +100,7 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
> 
> (1) Can you add this next to
> "gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask"?

Will do.

> 
>>  
>>  [FixedPcd]
>>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 2ae8126ccf8a..7ae2f26a2ba7 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -19,6 +19,27 @@
>>  
>>  #include "Platform.h"
>>  
>> +/**
>> +
>> +  Initialize SEV-ES support if running an SEV-ES guest.
> 
> (2) s/an/in an/? (Just asking)

Yup. I'll change that to "running as an SEV-ES guest".

> 
>> +
>> +  **/
>> +STATIC
>> +VOID
>> +AmdSevEsInitialize (
>> +  VOID
>> +  )
>> +{
>> +  RETURN_STATUS     PcdStatus;
>> +
>> +  if (!MemEncryptSevEsIsEnabled ()) {
>> +    return;
>> +  }
>> +
>> +  PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
> 
> (3) Please write TRUE, not 1.

Will do.

Thanks,
Tom

> 
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +}
>> +
>>  /**
>>  
>>    Function checks if SEV support is available, if present then it sets
>> @@ -89,4 +110,9 @@ AmdSevInitialize (
>>        EfiBootServicesData                // MemoryType
>>        );
>>    }
>> +
>> +  //
>> +  // Check and perform SEV-ES initialization if required.
>> +  //
>> +  AmdSevEsInitialize ();
>>  }
>>
> 
> With (1) and (3) fixed:
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-24 13:42   ` [edk2-devel] " Laszlo Ersek
  2019-09-24 13:50     ` Laszlo Ersek
@ 2019-09-24 18:57     ` Lendacky, Thomas
  2019-09-25 14:45       ` Laszlo Ersek
  2019-09-30 19:29       ` Laszlo Ersek
  1 sibling, 2 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-24 18:57 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 9/24/19 8:42 AM, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> During BSP startup, the reset vector code will issue a CPUID instruction
>> while in 32-bit mode. When running as an SEV-ES guest, this will trigger
>> a #VC exception.
> 
> (1) In the assembly source code, please annotate both CPUID instructions
> under CheckSevFeature, such as
> 
>   ; raises #VC when in an SEV-ES guest

Will do.

> 
>>
>> Add exception handling support to the early reset vector code to catch
>> these exceptions.  Also, since the guest is in 32-bit mode at this point,
>> writes to the GHCB will be encrypted and thus not able to be read by the
>> hypervisor, so use the GHCB CPUID request/response protocol to obtain the
>> requested CPUID function values and provide these to the guest.
>>
>> The exception handling support is active during the SEV check and uses the
>> OVMF temporary RAM space for a stack. After the SEV check is complete, the
>> exception handling support is removed and the stack pointer cleared.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/ResetVector/ResetVector.inf       |   2 +
>>  OvmfPkg/ResetVector/Ia32/PageTables64.asm | 177 +++++++++++++++++++++-
>>  OvmfPkg/ResetVector/ResetVector.nasmb     |   1 +
>>  3 files changed, 179 insertions(+), 1 deletion(-)
>>
>> 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..40f7814c1134 100644
>> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> @@ -33,10 +33,21 @@ BITS    32
>>  
>>  ; Check if Secure Encrypted Virtualization (SEV) feature is enabled
>>  ;
>> -; If SEV is enabled then EAX will be at least 32
>> +; Modified:  EAX, EBX, ECX, EDX, ESP
>> +;
>> +; If SEV is enabled then EAX will be at least 32.
>>  ; If SEV is disabled then EAX will be zero.
>>  ;
>>  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
> 
> (2) Can we %define SEV_TOP_OF_STACK in this file, or does it have to be
> in "ResetVector.nasmb"?

It looks like it has to be in ResetVector.nasmb for some reason. If I move
it into this file, it fails:

Ia32/PageTables64.asm:76: error: expecting `)'

> 
> (3) Do we have an estimate how much stack we need? This would be a
> constraint on PcdOvmfSecPeiTempRamSize. The limit would be nice to
> document (perhaps in a comment somewhere).

It's a fairly small amount of stack space, about 44 bytes (12 bytes for
the IRET frame and 32 bytes for the #VC "local" variables). The temporary
RAM size is 64K, so we're fine. I'll document the stack usage at the start
of the SevEsIdtVmmComm exception handler.

> 
>> +    mov       eax, ADDR_OF(Idtr)
>> +    lidt      [cs:eax]
>> +
>>      ; Check if we have a valid (0x8000_001F) CPUID leaf
>>      mov       eax, 0x80000000
>>      cpuid
>> @@ -73,6 +84,15 @@ NoSev:
>>      xor       eax, eax
>>  
>>  SevExit:
>> +    ;
>> +    ; Clear exception handlers and stack
>> +    ;
>> +    push      eax
>> +    mov       eax, ADDR_OF(IdtrClear)
>> +    lidt      [cs:eax]
>> +    pop       eax
>> +    mov       esp, 0
>> +
> 
> I'm not sure the resultant IDT and ESP contents are the same as before
> (pre-patch), but I guess these values should be OK too.

At this stage of the boot, both the IDT and ESP values are zero. They
haven't been set up this early in the boot.

> 
>>      OneTimeCallRet CheckSevFeature
>>  
>>  ;
>> @@ -146,3 +166,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
> 
> (4) Can you steal the DebugLog / PrintStringSi code from
> "OvmfPkg/QemuVideoDxe/VbeShim.asm", and print a simple message to the
> QEMU debug port, whenever you jump to SevEsIdtCommon?
> 
> This is basically an ASSERT(). It should have a message, if possible.
> (I'm not sure if the OUT instruction will work with SEV-ES at this
> stage, i.e. in 32-bit mode.)

Right, there isn't a way to share the OUT instruction information with
the hypervisor at this point because we are running in 32-bit mode (this
might be nice to add to the GHCB protocol, similar to the CPUID support,
I'll have to think about that).

Since we can't output a message, I can do something along the line of
using the GHCB protocol to request the hypervisor to terminate the guest.
Would that be better?

> 
>> +
>> +    ;
>> +    ; 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
> 
> (5) Can we %define macros for these offsets? (Including the size
> constant 32.)

Will do.

> 
>> +
>> +    ; Save CPUID function and initial register request
>> +    mov     [esp + 28], eax
>> +    xor     eax, eax
>> +    mov     [esp + 24], eax
> 
> (6) The comment "CPUID register" (at offset 24), and the other comment
> "initial register", are pretty confusing. Can you please document:
> 
> - the mapping: 0->EAX, ... 3->EDX,
> - and the fact that the dword at [esp + 24] is the loop variable?

Yup, can do.

> 
>> +
>> +    ; 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
> 
> (7) Please %define GHCBInfoCpuIdRequest or something similar for the
> value 4.

Ok. I'll remove all of the hardcoded values and %define them.

> 
>> +    mov     edx, [esp + 28]
>> +    mov     ecx, 0xc0010130
>> +    wrmsr
>> +
>> +    ; Issue VMGEXIT (rep; vmmcall)
>> +    db      0xf3
>> +    db      0x0f
>> +    db      0x01
>> +    db      0xd9
> 
> (8) Can you please file an RFE at <https://bugzilla.nasm.us/>, for
> supporting this instruction, and add the link here, as a comment? I've
> been fighting an uphill battle against DB-encoded instructions in edk2
> assembly code.

Yes, let me look into that.

> 
>> +
>> +    ;
>> +    ; 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
> 
> (9) Please %define GHCBInfoCpuIdResponse for value 5.
> 
>> +    jne     SevEsIdtCommon
> 
> (10) Please see (4). The message could be, "no GHCBInfoCpuIdResponse
> received", or similar.

Sure, if I find a way to issue messages at this point.

> 
>> +
>> +    ; Save returned value
>> +    shr     eax, 30
>> +    and     eax, 0x3
> 
> (11) Do we need the AND after the SHR? I think the new high order bits
> from the SHR should be zero.

No, we don't actually need the AND, just a habit to show the size of the
area. But since we're at the top of the register range (bits 30 and 31)
it's not really necessary. I'll remove it.

> 
>> +    shl     eax, 2
>> +    mov     ecx, esp
>> +    add     ecx, eax
>> +    mov     [ecx], edx
> 
> (12) The beauty of the lean and mean x86 instruction set:
> 
>        mov     [esp + eax * 4], edx
> 
> (I tested just this one instruction with nasm + ndisasm; the encoding is
> 0x89, 0x14, 0x84.)

Ah, yes. Will do.

> 
>> +
>> +    ; 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
> 
> (13) Please see (5).
> 
>> +    add     word [esp], 2           ; Skip over the CPUID instruction
> 
> OK, this seems safe. CPUID has only one encoding (0x0F, 0xA2), and we
> checked SW_EXITCODE = 0x72 at the top.

In this case, yes. Since we're covering a small piece of code and we
generated the instructions I think we can rely on that. Later on, that's
where the instruction parsing comes in.

> 
>> +    iret
>> +
>> +ALIGN   2
>> +
>> +Idtr:
>> +    dw      IDT_END - IDT_BASE - 1  ; Limit
>> +    dd      ADDR_OF(IDT_BASE)       ; Base
>> +
>> +IdtrClear:
>> +    dw      0                       ; Limit
>> +    dd      0                       ; Base
>> +
>> +ALIGN   16
>> +
>> +;
>> +; The Interrupt Descriptor Table (IDT)
>> +;   This will be used to determine if SEV-ES is enabled.  Upon execution
>> +;   of the CPUID instruction, a VMM Communication Exception will occur.
>> +;   This will tell us if SEV-ES is enabled.  We can use the current value
>> +;   of the GHCB MSR to determine the SEV attributes.
>> +;
>> +IDT_BASE:
>> +;
>> +; Vectors 0 - 28
>> +;
>> +%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:
> 
> (14) Above, we have two explicit jumps to SevEsIdtCommon, and I've asked
> for meaningful assertion messages there.
> 
> For the uninteresting exception vectors 0-28 and 30-31, can we use a
> handler that is not directly SevEsIdtCommon, but logs a message, and
> then jumps to SevEsIdtCommon? (It could even be implemented as a
> "prefix" of SevEsIdtCommon, and then no jump would be required.)

If I come up with a way to get a message out, we can look at that. I'll
need to see if it is too late to update the GHCB protocol specification
to add an OUT protocol to support messages when in 32-bit.

I think I can actually set just the #VC exception entry so that any other
exception just causes the guest to die, similar to what would happen if an
exception were to occur at this stage today.

Thanks for the thorough review!
Tom

> 
>> 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
>>  
>>
> 
> (I've commented on this under (2).)
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-09-19 19:52 ` [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-09-25  8:09   ` Laszlo Ersek
  2019-09-25 17:36     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-25  8:09 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> 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 to break down the 2MB
> region where the GHCB page lives into 4K pagetable entries.
> 
> Create a new entry in the OVMF memory layout for the new page table
> page and for the SEC GHCB page. After breaking down the 2MB page, update
> the GHCB page table entry to remove the encryption mask.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkg.dec                       | 10 +++
>  OvmfPkg/OvmfPkgX64.fdf                    |  6 ++
>  OvmfPkg/ResetVector/ResetVector.inf       |  4 ++
>  OvmfPkg/ResetVector/Ia32/PageTables64.asm | 79 +++++++++++++++++++++++
>  OvmfPkg/ResetVector/ResetVector.nasmb     | 12 ++++
>  5 files changed, 111 insertions(+)
> 
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 9640360f6245..b9287a023c94 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -218,6 +218,16 @@ [PcdsFixedAtBuild]
>    #  The value should be a multiple of 4KB.
>    gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>  
> +  ## Specify the extra page table needed to mark the GHCB as unencrypted.
> +  #  The value should be a multiple of 4KB for each.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|0x0|UINT32|0x32
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|0x0|UINT32|0x33
> +
> +  ## Specify the GHCB base address and size.
> +  #  The value should be a multiple of 4KB for each.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x34
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x35
> +
>  [PcdsDynamic, PcdsDynamicEx]
>    gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 74407072563b..a567131a0591 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -76,6 +76,12 @@ [FD.MEMFD]
>  0x007000|0x001000
>  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>  
> +0x008000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
> +
> +0x009000|0x001000
> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> +
>  0x010000|0x010000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>  
> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
> index 960b47cd0797..80c971354176 100644
> --- a/OvmfPkg/ResetVector/ResetVector.inf
> +++ b/OvmfPkg/ResetVector/ResetVector.inf
> @@ -37,3 +37,7 @@ [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> index 40f7814c1134..7e346661f2c8 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 + \
> @@ -95,6 +100,37 @@ SevExit:
>  
>      OneTimeCallRet CheckSevFeature
>  
> +; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
> +; is enabled.
> +;
> +; Modified:  EAX, EBX, ECX, EDX

(1) I think we should remove EDX from this list. It is restored at the
end of the routine. And, in pageTableEntries4kLoop, we rely on EDX
containing the encryption mask.

> +;
> +; If SEV-ES is enabled then EAX will be non-zero.
> +; If SEV-ES is disabled then EAX will be zero.
> +;
> +CheckSevEsFeature:
> +    xor       eax, eax
> +
> +    ; SEV-ES can't be enabled if SEV isn't, so first check the encryption
> +    ; mask.
> +    test      edx, edx
> +    jz        NoSevEs
> +
> +    ; Save current value of encryption mask
> +    mov       ebx, edx
> +
> +    ; Check if SEV-ES is enabled
> +    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
> +    mov       ecx, 0xc0010131
> +    rdmsr
> +    and       eax, 2
> +
> +    ; Restore encryption mask
> +    mov       edx, ebx
> +
> +NoSevEs:
> +    OneTimeCallRet CheckSevEsFeature
> +
>  ;
>  ; Modified:  EAX, EBX, ECX, EDX
>  ;
> @@ -159,6 +195,49 @@ pageTableEntriesLoop:
>      mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
>      loop    pageTableEntriesLoop
>  
> +    OneTimeCall   CheckSevEsFeature
> +    test    eax, eax
> +    jz      SetCr3
> +
> +    ;
> +    ; The initial GHCB will live at 0x809000 and needs to be un-encrypted.

(2) Can you replace 0x809000 with GHCB_BASE, in the comment?

> +    ; 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 encrypted,
> +    ; except for the GHCB.
> +    ;
> +    mov     ecx, 4

(3) Can we please:
- remove the remark "index 4 in the first 1GB page",
- and replace the constant 4 with (GHCB_BASE >> 21), in the instruction?

> +    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
> +    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
> +
> +    ;
> +    ; Page Table Entries (512 * 4KB entries => 2MB)
> +    ;
> +    mov     ecx, 512
> +pageTableEntries4kLoop:
> +    mov     eax, ecx
> +    dec     eax
> +    shl     eax, 12
> +    add     eax, 0x800000
> +    add     eax, PAGE_4K_PDE_ATTR
> +    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
> +    mov     [ecx * 8 + GHCB_PT_ADDR - 4], edx

(4) I find it easier to understand if we stick with the pattern seen in
the previous loop, namely [(ecx * 8 + GHCB_PT_ADDR - 8) + 4].

> +    loop    pageTableEntries4kLoop

(5) Can you please replace the constant 0x800000 with the following
expression:

 GHCB_BASE & 0xffe0_0000

(NASM supports the underscore too)

> +
> +    ;
> +    ; Clear the encryption bit from the GHCB entry (index 9 in the
> +    ; new PTE table: (0x809000 - 0x800000) >> 12)).
> +    ;
> +    mov     ecx, 9

(6) I'd suggest removing the parenthesized part of the comment, with the
constants. Instead, we should be able to explain the logic in the mov
instruction itself:

  mov ecx, (GHCB_BASE & 0x1f_ffff) >> 12

> +    xor     edx, edx
> +    mov     [ecx * 8 + GHCB_PT_ADDR + 4], edx

(7) It would be nice to preserve the encryption mask in EDX, as an
invariant; we've relied on it in the present patch too.

I suggest we do:

  mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0

Assembled / disassembled as the following 11 bytes:

00000000  C704CD0480800000  mov dword [ecx*8+0x808004],0x0
         -000000


Alternatively, we could hoist the "xor eax, eax" from just below, and
then store eax, not edx, to the most significant dword.

> +
> +    mov     ecx, GHCB_SIZE / 4
> +    xor     eax, eax
> +clearGhcbMemoryLoop:
> +    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
> +    loop    clearGhcbMemoryLoop
> +
> +SetCr3:
>      ;
>      ; Set CR3 now that the paging structures are available
>      ;
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 3b213cd05ab2..8909fc9313f4 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -53,7 +53,19 @@
>      %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>    %endif
>  
> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
> +    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
> +  %endif
> +
> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
> +    %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
> +  %endif
> +
>    %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
> +
> +  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
> +  %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
> +  %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
>  %include "Ia32/Flat32ToFlat64.asm"
>    %define SEV_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
>  %include "Ia32/PageTables64.asm"
> 

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
  2019-09-19 19:52 ` [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
@ 2019-09-25  8:27   ` Laszlo Ersek
  2019-09-25 17:52     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-25  8:27 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh, Anthony Perard, Julien Grall

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Protect the memory used by an SEV-ES guest when S3 is supported. This
> includes the page table used to break down the 2MB page that contains
> the GHCB so that it can be marked un-encrypted, as well as the GHCB
> area.
> 
> Regarding the lifecycle of the GHCB-related memory areas:
>   PcdOvmfSecGhcbPageTableBase
>   PcdOvmfSecGhcbBase
> 
> (a) when and how it is initialized after first boot of the VM
> 
>   If SEV-ES is enabled, the GHCB-related areas are initialized during
>   the SEC phase [OvmfPkg/ResetVector/Ia32/PageTables64.asm].
> 
> (b) how it is protected from memory allocations during DXE
> 
>   If S3 and SEV-ES are enabled, then InitializeRamRegions()
>   [OvmfPkg/PlatformPei/MemDetect.c] protects the range with an AcpiNVS
>   memory allocation HOB, in PEI.

(1) Please keep (and update, as needed) the paragraph about the "S3
disabled" case. The matching part of the whitepaper says, in (1b),

"""
If S3 was disabled, then this range is not protected. DXE's own page
tables are first built while still in PEI (see HandOffToDxeCore()
[MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c]). Those tables are
located in permanent PEI memory. After CR3 is switched over to them
(which occurs before jumping to the DXE core entry point), we don't have
to preserve the initial tables.
"""

I guess we don't have to be as verbose as this. But, in case we're going
to build a new GHCB for the DXE phase, and therefore we can simply
forget about the early GHCB structures (with S3 disabled), we should
mention that briefly.

> 
> (c) how it is protected from the OS
> 
>   If S3 is enabled, then (1b) reserves it from the OS too.

(2) s/1b/b/

> 
>   If S3 is disabled, then the range needs no protection.

Right, so this seems to be consistent with what I'm requesting under (1).

> 
> (d) how it is accessed on the S3 resume path
> 
>   It is rewritten same as in (1a), which is fine because (1b) reserved it.

(3) s/1a/a/; s/1b/b/

(Also, the original refers to (1c) rather than (1b), and that's not a
typo; but this variant looks just as fine.)

> 
> (e) how it is accessed on the warm reset path
> 
>   It is rewritten same as in (1a).

(4) s/1a/a/

> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/PlatformPei/PlatformPei.inf |  4 ++++
>  OvmfPkg/PlatformPei/MemDetect.c     | 23 +++++++++++++++++++++++
>  2 files changed, 27 insertions(+)
> 
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index 2736347a2e03..a9e424a6012a 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -84,6 +84,10 @@ [Pcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>    gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize

(5) Can you please keep these additions close to
PcdOvmfSecPageTablesBase / PcdOvmfSecPageTablesSize?

> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
> index d451989f31c9..cd2e3abb7c9b 100644
> --- a/OvmfPkg/PlatformPei/MemDetect.c
> +++ b/OvmfPkg/PlatformPei/MemDetect.c
> @@ -32,6 +32,7 @@ Module Name:
>  #include <Library/ResourcePublicationLib.h>
>  #include <Library/MtrrLib.h>
>  #include <Library/QemuFwCfgLib.h>
> +#include <Library/MemEncryptSevLib.h>
>  
>  #include "Platform.h"
>  #include "Cmos.h"
> @@ -805,6 +806,28 @@ InitializeRamRegions (
>        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
>        EfiACPIMemoryNVS
>        );
> +
> +    if (MemEncryptSevEsIsEnabled ()) {
> +      //
> +      // If SEV-ES is active, reserve the GHCB-related memory area. This
> +      // includes the extra page table used to break down the 2MB page
> +      // mapping into 4KB page entries where the GHCB resides and the
> +      // GHCB area itself.
> +      //
> +      // Since this memory range will be used by the Reset Vector on S3
> +      // resume, it must be reserved as ACPI NVS.
> +      //
> +      BuildMemoryAllocationHob (
> +        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableBase),
> +        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableSize),
> +        EfiACPIMemoryNVS
> +        );
> +      BuildMemoryAllocationHob (
> +        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbBase),
> +        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbSize),
> +        EfiACPIMemoryNVS
> +        );
> +    }
>  #endif
>    }
>  
> 

With the requested updates:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-24 18:57     ` Lendacky, Thomas
@ 2019-09-25 14:45       ` Laszlo Ersek
  2019-09-30 19:29       ` Laszlo Ersek
  1 sibling, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-25 14:45 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 09/24/19 20:57, Lendacky, Thomas wrote:
> On 9/24/19 8:42 AM, Laszlo Ersek wrote:
>> On 09/19/19 21:52, Lendacky, Thomas wrote:

>>> +    mov       esp, SEV_TOP_OF_STACK
>>
>> (2) Can we %define SEV_TOP_OF_STACK in this file, or does it have to be
>> in "ResetVector.nasmb"?
> 
> It looks like it has to be in ResetVector.nasmb for some reason. If I move
> it into this file, it fails:
> 
> Ia32/PageTables64.asm:76: error: expecting `)'

Huh. Strange. Not a problem to lose sleep over, though.


>>> +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
>>
>> (4) Can you steal the DebugLog / PrintStringSi code from
>> "OvmfPkg/QemuVideoDxe/VbeShim.asm", and print a simple message to the
>> QEMU debug port, whenever you jump to SevEsIdtCommon?
>>
>> This is basically an ASSERT(). It should have a message, if possible.
>> (I'm not sure if the OUT instruction will work with SEV-ES at this
>> stage, i.e. in 32-bit mode.)
> 
> Right, there isn't a way to share the OUT instruction information with
> the hypervisor at this point because we are running in 32-bit mode (this
> might be nice to add to the GHCB protocol, similar to the CPUID support,
> I'll have to think about that).
> 
> Since we can't output a message, I can do something along the line of
> using the GHCB protocol to request the hypervisor to terminate the guest.
> Would that be better?

I think that would be great; from publication#56421, it looks like the
guest can pass a (reason code set, reason code) pair along with the
termination request, and QEMU could display that.

We could assign reason code set 1 to QEMU (if a reason code set has not
been assigned yet), and then we could use different reason codes (in
code set 1) for the various SevEsIdtCommon jumps. (I don't think we need
to distinguish the exception vectors from each other -- as long as a
user can tell us that the guest died due to *some* exception, we can
write debug patches to tell those apart; we'll know where to start.)

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-09-25  8:09   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-25 17:36     ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-25 17:36 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 9/25/19 3:09 AM, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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 to break down the 2MB
>> region where the GHCB page lives into 4K pagetable entries.
>>
>> Create a new entry in the OVMF memory layout for the new page table
>> page and for the SEC GHCB page. After breaking down the 2MB page, update
>> the GHCB page table entry to remove the encryption mask.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkg.dec                       | 10 +++
>>  OvmfPkg/OvmfPkgX64.fdf                    |  6 ++
>>  OvmfPkg/ResetVector/ResetVector.inf       |  4 ++
>>  OvmfPkg/ResetVector/Ia32/PageTables64.asm | 79 +++++++++++++++++++++++
>>  OvmfPkg/ResetVector/ResetVector.nasmb     | 12 ++++
>>  5 files changed, 111 insertions(+)
>>
>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
>> index 9640360f6245..b9287a023c94 100644
>> --- a/OvmfPkg/OvmfPkg.dec
>> +++ b/OvmfPkg/OvmfPkg.dec
>> @@ -218,6 +218,16 @@ [PcdsFixedAtBuild]
>>    #  The value should be a multiple of 4KB.
>>    gUefiOvmfPkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x31
>>  
>> +  ## Specify the extra page table needed to mark the GHCB as unencrypted.
>> +  #  The value should be a multiple of 4KB for each.
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|0x0|UINT32|0x32
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|0x0|UINT32|0x33
>> +
>> +  ## Specify the GHCB base address and size.
>> +  #  The value should be a multiple of 4KB for each.
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0x0|UINT32|0x34
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0x0|UINT32|0x35
>> +
>>  [PcdsDynamic, PcdsDynamicEx]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index 74407072563b..a567131a0591 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -76,6 +76,12 @@ [FD.MEMFD]
>>  0x007000|0x001000
>>  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
>>  
>> +0x008000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>> +
>> +0x009000|0x001000
>> +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> +
>>  0x010000|0x010000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>>  
>> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
>> index 960b47cd0797..80c971354176 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.inf
>> +++ b/OvmfPkg/ResetVector/ResetVector.inf
>> @@ -37,3 +37,7 @@ [Pcd]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
>> index 40f7814c1134..7e346661f2c8 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 + \
>> @@ -95,6 +100,37 @@ SevExit:
>>  
>>      OneTimeCallRet CheckSevFeature
>>  
>> +; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
>> +; is enabled.
>> +;
>> +; Modified:  EAX, EBX, ECX, EDX
> 
> (1) I think we should remove EDX from this list. It is restored at the
> end of the routine. And, in pageTableEntries4kLoop, we rely on EDX
> containing the encryption mask.

Yup, I'll remove that one.

> 
>> +;
>> +; If SEV-ES is enabled then EAX will be non-zero.
>> +; If SEV-ES is disabled then EAX will be zero.
>> +;
>> +CheckSevEsFeature:
>> +    xor       eax, eax
>> +
>> +    ; SEV-ES can't be enabled if SEV isn't, so first check the encryption
>> +    ; mask.
>> +    test      edx, edx
>> +    jz        NoSevEs
>> +
>> +    ; Save current value of encryption mask
>> +    mov       ebx, edx
>> +
>> +    ; Check if SEV-ES is enabled
>> +    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
>> +    mov       ecx, 0xc0010131
>> +    rdmsr
>> +    and       eax, 2
>> +
>> +    ; Restore encryption mask
>> +    mov       edx, ebx
>> +
>> +NoSevEs:
>> +    OneTimeCallRet CheckSevEsFeature
>> +
>>  ;
>>  ; Modified:  EAX, EBX, ECX, EDX
>>  ;
>> @@ -159,6 +195,49 @@ pageTableEntriesLoop:
>>      mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
>>      loop    pageTableEntriesLoop
>>  
>> +    OneTimeCall   CheckSevEsFeature
>> +    test    eax, eax
>> +    jz      SetCr3
>> +
>> +    ;
>> +    ; The initial GHCB will live at 0x809000 and needs to be un-encrypted.
> 
> (2) Can you replace 0x809000 with GHCB_BASE, in the comment?

Yes, will do.

> 
>> +    ; 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 encrypted,
>> +    ; except for the GHCB.
>> +    ;
>> +    mov     ecx, 4
> 
> (3) Can we please:
> - remove the remark "index 4 in the first 1GB page",
> - and replace the constant 4 with (GHCB_BASE >> 21), in the instruction?

Yes, will do throughout in regards to GHCB_BASE. It was my intention to
use GHCB_BASE throughout when I created it, but it looks like forgot to
make those changes.

> 
>> +    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
>> +    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
>> +
>> +    ;
>> +    ; Page Table Entries (512 * 4KB entries => 2MB)
>> +    ;
>> +    mov     ecx, 512
>> +pageTableEntries4kLoop:
>> +    mov     eax, ecx
>> +    dec     eax
>> +    shl     eax, 12
>> +    add     eax, 0x800000
>> +    add     eax, PAGE_4K_PDE_ATTR
>> +    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
>> +    mov     [ecx * 8 + GHCB_PT_ADDR - 4], edx
> 
> (4) I find it easier to understand if we stick with the pattern seen in
> the previous loop, namely [(ecx * 8 + GHCB_PT_ADDR - 8) + 4].

Ok, I'll change that to match.

> 
>> +    loop    pageTableEntries4kLoop
> 
> (5) Can you please replace the constant 0x800000 with the following
> expression:
> 
>  GHCB_BASE & 0xffe0_0000
> 
> (NASM supports the underscore too)
> 
>> +
>> +    ;
>> +    ; Clear the encryption bit from the GHCB entry (index 9 in the
>> +    ; new PTE table: (0x809000 - 0x800000) >> 12)).
>> +    ;
>> +    mov     ecx, 9
> 
> (6) I'd suggest removing the parenthesized part of the comment, with the
> constants. Instead, we should be able to explain the logic in the mov
> instruction itself:
> 
>   mov ecx, (GHCB_BASE & 0x1f_ffff) >> 12
> 
>> +    xor     edx, edx
>> +    mov     [ecx * 8 + GHCB_PT_ADDR + 4], edx
> 
> (7) It would be nice to preserve the encryption mask in EDX, as an
> invariant; we've relied on it in the present patch too.
> 
> I suggest we do:
> 
>   mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
> 
> Assembled / disassembled as the following 11 bytes:
> 
> 00000000  C704CD0480800000  mov dword [ecx*8+0x808004],0x0
>          -000000

Ok, will do.

> 
> 
> Alternatively, we could hoist the "xor eax, eax" from just below, and
> then store eax, not edx, to the most significant dword.

I'd rather not, just in case there are some changes in the future and
suddenly eax is no longer zero afterwards - unlikely, but it is safe.

I'll use your suggestion from above.

Thanks,
Tom

> 
>> +
>> +    mov     ecx, GHCB_SIZE / 4
>> +    xor     eax, eax
>> +clearGhcbMemoryLoop:
>> +    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
>> +    loop    clearGhcbMemoryLoop
>> +
>> +SetCr3:
>>      ;
>>      ; Set CR3 now that the paging structures are available
>>      ;
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 3b213cd05ab2..8909fc9313f4 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -53,7 +53,19 @@
>>      %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>>    %endif
>>  
>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
>> +    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>> +  %endif
>> +
>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
>> +    %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>> +  %endif
>> +
>>    %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
>> +
>> +  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
>> +  %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
>> +  %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
>>  %include "Ia32/Flat32ToFlat64.asm"
>>    %define SEV_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
>>  %include "Ia32/PageTables64.asm"
>>
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
  2019-09-25  8:27   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-25 17:52     ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-25 17:52 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, Anthony Perard, Julien Grall

On 9/25/19 3:27 AM, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> Protect the memory used by an SEV-ES guest when S3 is supported. This
>> includes the page table used to break down the 2MB page that contains
>> the GHCB so that it can be marked un-encrypted, as well as the GHCB
>> area.
>>
>> Regarding the lifecycle of the GHCB-related memory areas:
>>   PcdOvmfSecGhcbPageTableBase
>>   PcdOvmfSecGhcbBase
>>
>> (a) when and how it is initialized after first boot of the VM
>>
>>   If SEV-ES is enabled, the GHCB-related areas are initialized during
>>   the SEC phase [OvmfPkg/ResetVector/Ia32/PageTables64.asm].
>>
>> (b) how it is protected from memory allocations during DXE
>>
>>   If S3 and SEV-ES are enabled, then InitializeRamRegions()
>>   [OvmfPkg/PlatformPei/MemDetect.c] protects the range with an AcpiNVS
>>   memory allocation HOB, in PEI.
> 
> (1) Please keep (and update, as needed) the paragraph about the "S3
> disabled" case. The matching part of the whitepaper says, in (1b),
> 
> """
> If S3 was disabled, then this range is not protected. DXE's own page
> tables are first built while still in PEI (see HandOffToDxeCore()
> [MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c]). Those tables are
> located in permanent PEI memory. After CR3 is switched over to them
> (which occurs before jumping to the DXE core entry point), we don't have
> to preserve the initial tables.
> """
> 
> I guess we don't have to be as verbose as this. But, in case we're going
> to build a new GHCB for the DXE phase, and therefore we can simply
> forget about the early GHCB structures (with S3 disabled), we should
> mention that briefly.
> 

Ok, will do.  Not sure how I missed including the second paragraph under
"b".

>>
>> (c) how it is protected from the OS
>>
>>   If S3 is enabled, then (1b) reserves it from the OS too.
> 
> (2) s/1b/b/

Yup, I'll fix it here and in the other locations identified.

Thanks,
Tom

> 
>>
>>   If S3 is disabled, then the range needs no protection.
> 
> Right, so this seems to be consistent with what I'm requesting under (1).
> 
>>
>> (d) how it is accessed on the S3 resume path
>>
>>   It is rewritten same as in (1a), which is fine because (1b) reserved it.
> 
> (3) s/1a/a/; s/1b/b/
> 
> (Also, the original refers to (1c) rather than (1b), and that's not a
> typo; but this variant looks just as fine.)
> 
>>
>> (e) how it is accessed on the warm reset path
>>
>>   It is rewritten same as in (1a).
> 
> (4) s/1a/a/
> 
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Cc: Anthony Perard <anthony.perard@citrix.com>
>> Cc: Julien Grall <julien.grall@arm.com>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/PlatformPei/PlatformPei.inf |  4 ++++
>>  OvmfPkg/PlatformPei/MemDetect.c     | 23 +++++++++++++++++++++++
>>  2 files changed, 27 insertions(+)
>>
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index 2736347a2e03..a9e424a6012a 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -84,6 +84,10 @@ [Pcd]
>>    gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>    gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> 
> (5) Can you please keep these additions close to
> PcdOvmfSecPageTablesBase / PcdOvmfSecPageTablesSize?
> 
>> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
>> index d451989f31c9..cd2e3abb7c9b 100644
>> --- a/OvmfPkg/PlatformPei/MemDetect.c
>> +++ b/OvmfPkg/PlatformPei/MemDetect.c
>> @@ -32,6 +32,7 @@ Module Name:
>>  #include <Library/ResourcePublicationLib.h>
>>  #include <Library/MtrrLib.h>
>>  #include <Library/QemuFwCfgLib.h>
>> +#include <Library/MemEncryptSevLib.h>
>>  
>>  #include "Platform.h"
>>  #include "Cmos.h"
>> @@ -805,6 +806,28 @@ InitializeRamRegions (
>>        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
>>        EfiACPIMemoryNVS
>>        );
>> +
>> +    if (MemEncryptSevEsIsEnabled ()) {
>> +      //
>> +      // If SEV-ES is active, reserve the GHCB-related memory area. This
>> +      // includes the extra page table used to break down the 2MB page
>> +      // mapping into 4KB page entries where the GHCB resides and the
>> +      // GHCB area itself.
>> +      //
>> +      // Since this memory range will be used by the Reset Vector on S3
>> +      // resume, it must be reserved as ACPI NVS.
>> +      //
>> +      BuildMemoryAllocationHob (
>> +        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableBase),
>> +        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbPageTableSize),
>> +        EfiACPIMemoryNVS
>> +        );
>> +      BuildMemoryAllocationHob (
>> +        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecGhcbBase),
>> +        (UINT64)(UINTN) PcdGet32 (PcdOvmfSecGhcbSize),
>> +        EfiACPIMemoryNVS
>> +        );
>> +    }
>>  #endif
>>    }
>>  
>>
> 
> With the requested updates:
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
  2019-09-24 14:31     ` Lendacky, Thomas
@ 2019-09-25 22:31       ` Ni, Ray
  0 siblings, 0 replies; 106+ messages in thread
From: Ni, Ray @ 2019-09-25 22:31 UTC (permalink / raw)
  To: devel@edk2.groups.io, thomas.lendacky@amd.com, Dong, Eric
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Singh, Brijesh, You, Benjamin, Bi, Dandan, Dong, Guo,
	Wu, Hao A, Wang, Jian J, Ma, Maurice

Tom - Yes please.

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lendacky, Thomas
> Sent: Tuesday, September 24, 2019 7:31 AM
> To: Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>
> 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>;
> Singh, Brijesh <brijesh.singh@amd.com>; You, Benjamin <benjamin.you@intel.com>; Bi, Dandan <dandan.bi@intel.com>;
> Dong, Guo <guo.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; Ma, Maurice
> <maurice.ma@intel.com>; devel@edk2.groups.io
> Subject: Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
> 
> On 9/23/19 8:55 PM, Dong, Eric wrote:
> > Hi Tom,
> 
> Hi Eric,
> 
> >
> > Thanks for you to contribute such a big changes. Seems like this is a big changes for current code, can you help to do a
> design review in TianoCore Design Meeting? It will be helpful for us to understand the code change and review it.
> >
> > Ray is the owner of that meeting, you can contact him for the arrangement of your topic.
> 
> Thanks for the info, Eric.
> 
> Ray, I see on the TianoCore wiki that I should contact Stephano to be
> added to the meeting agenda. Should I follow those directions?
> 
> Thanks,
> Tom
> 
> >
> > Thanks,
> > Eric
> >
> >> -----Original Message-----
> >> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> >> Lendacky, Thomas
> >> Sent: Saturday, September 21, 2019 3:25 AM
> >> 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>; You, Benjamin
> >> <benjamin.you@intel.com>; Bi, Dandan <dandan.bi@intel.com>; Dong, Guo
> >> <guo.dong@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J
> >> <jian.j.wang@intel.com>; Ma, Maurice <maurice.ma@intel.com>
> >> Subject: Re: [edk2-devel] [RFC PATCH v2 00/44] SEV-ES guest support
> >>
> >> On 9/19/19 2:52 PM, Lendacky, Thomas wrote:
> >>> From: Tom Lendacky <thomas.lendacky@amd.com>
> >>>
> >>> This patch series provides support for running EDK2/OVMF under SEV-ES.
> >>
> >> I wanted to provide the full series so that everyone can see what is involved
> >> with the support.
> >>
> >> Providing multiple, smaller series of patches might be easier to review.
> >> If that is desired, any suggestions/recommendations on how to best approach
> >> that would be great.
> >>
> >> Thanks,
> >> Tom
> >>
> >>>
> >>> 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
> >>>
> >>> ---
> >>>
> >>> These patches are based on commit:
> >>> ada905ab5c0e ("MdeModulePkg DxeCore: Fix for missing Memory Attributes
> >>> Table (MAT) update")
> >>>
> >>> A version of the tree can be found at:
> >>> https://github.com/AMDESE/ovmf/tree/sev-es-v7
> >>>
> >>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >>> Cc: Benjamin You <benjamin.you@intel.com>
> >>> Cc: Dandan Bi <dandan.bi@intel.com>
> >>> Cc: Eric Dong <eric.dong@intel.com>
> >>> Cc: Guo Dong <guo.dong@intel.com>
> >>> Cc: Hao A Wu <hao.a.wu@intel.com>
> >>> Cc: Jian J Wang <jian.j.wang@intel.com>
> >>> Cc: Jordan Justen <jordan.l.justen@intel.com>
> >>> Cc: Laszlo Ersek <lersek@redhat.com>
> >>> Cc: Liming Gao <liming.gao@intel.com>
> >>> Cc: Maurice Ma <maurice.ma@intel.com>
> >>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >>> Cc: Ray Ni <ray.ni@intel.com>
> >>>
> >>> Changes since v1:
> >>> - Patches reworked to be more specific to the component/area being
> >> updated
> >>>    and order of definition/usage
> >>> - Created a library for VMGEXIT-related functions to replace use of inline
> >>>    functions
> >>> - Allocation method for GDT changed from AllocatePool to AllocatePages
> >>> - Early caching only enabled for SEV-ES guests
> >>> - Ensure AP loop mode set to halt loop mode for SEV-ES guests
> >>> - Reserved SEC GHCB-related memory areas when S3 is enabled
> >>>
> >>> Tom Lendacky (44):
> >>>    MdePkg: Create PCDs to be used in support of SEV-ES
> >>>    OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
> >>>    OvmfPkg: Add support to perform SEV-ES initialization
> >>>    OvmfPkg/ResetVector: Add support for a 32-bit SEV check
> >>>    MdePkg: Add the MSR definition for the GHCB register
> >>>    OvmfPkg: Create a GHCB page for use during Sec phase
> >>>    OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
> >>>    OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
> >>>    MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page
> >> tables
> >>>    OvmfPkg: A per-CPU variable area for #VC usage
> >>>    OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
> >>>    MdePkg: Add a structure definition for the GHCB
> >>>    MdePkg/BaseLib: Add support for the VMGEXIT instruction
> >>>    UefiCpuPkg: Implement library support for VMGEXIT
> >>>    UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
> >>>    OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during
> >> SEC
> >>>    UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec
> >>>      phase
> >>>    OvmfPkg/Sec: Enable cache early to speed up booting
> >>>    UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
> >>>    UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
> >>>      events
> >>>    MdePkg: Add support for the XGETBV instruction
> >>>    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/MpInitLib: Update CPU MP data with a flag to indicate if
> >>>      SEV-ES is active
> >>>    MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
> >>>    UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
> >>>    OvmfPkg: Add support for SEV-ES AP reset vector re-directing
> >>>    UefiCpuPkg: Allow AP booting under SEV-ES
> >>>    OvmfPkg: Move the GHCB allocations into reserved memory
> >>>    MdePkg: Add a finalization function to the CPU protocol
> >>>    UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
> >>>    UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
> >>>    UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support
> >>>      SEV-ES
> >>>    MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
> >>>
> >>>   MdeModulePkg/MdeModulePkg.dec                 |   15 +
> >>>   OvmfPkg/OvmfPkg.dec                           |   10 +
> >>>   UefiCpuPkg/UefiCpuPkg.dec                     |    3 +
> >>>   OvmfPkg/OvmfPkgIa32.dsc                       |   10 +
> >>>   OvmfPkg/OvmfPkgIa32X64.dsc                    |   10 +
> >>>   OvmfPkg/OvmfPkgX64.dsc                        |   10 +
> >>>   UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
> >>>   UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
> >>>   UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
> >>>   OvmfPkg/OvmfPkgX64.fdf                        |    6 +
> >>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
> >>>   MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
> >>>   .../BaseMemEncryptSevLib.inf                  |    2 +-
> >>>   OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
> >>>   OvmfPkg/ResetVector/ResetVector.inf           |    6 +
> >>>   OvmfPkg/Sec/SecMain.inf                       |    2 +
> >>>   .../DxeCpuExceptionHandlerLib.inf             |    5 +
> >>>   .../PeiCpuExceptionHandlerLib.inf             |    5 +
> >>>   .../SecPeiCpuExceptionHandlerLib.inf          |    5 +
> >>>   UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    3 +
> >>>   UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    3 +
> >>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
> >>>   .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
> >>>   MdePkg/Include/Library/BaseLib.h              |   30 +
> >>>   MdePkg/Include/Protocol/Cpu.h                 |   18 +
> >>>   MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
> >>>   MdePkg/Include/Register/Amd/Ghcb.h            |  105 ++
> >>>   OvmfPkg/Include/Library/MemEncryptSevLib.h    |   12 +
> >>>   UefiCpuPkg/CpuDxe/CpuDxe.h                    |   12 +
> >>>   UefiCpuPkg/CpuDxe/CpuGdt.h                    |    4 +-
> >>>   UefiCpuPkg/Include/Library/MpInitLib.h        |   14 +
> >>>   UefiCpuPkg/Include/Library/VmgExitLib.h       |   74 +
> >>>   .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   19 +
> >>>   .../CpuExceptionCommon.h                      |    2 +
> >>>   UefiCpuPkg/Library/MpInitLib/MpLib.h          |   77 +-
> >>>   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       |   45 +
> >>>   MdePkg/Library/BaseLib/X64/GccInline.c        |   47 +
> >>>   .../MemEncryptSevLibInternal.c                |   77 +-
> >>>   OvmfPkg/PlatformPei/AmdSev.c                  |   78 ++
> >>>   OvmfPkg/PlatformPei/MemDetect.c               |   23 +
> >>>   OvmfPkg/Sec/SecMain.c                         |   39 +-
> >>>   UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
> >>>   UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
> >>>   .../CpuExceptionCommon.c                      |    2 +-
> >>>   .../Ia32/AMDSevVcCommon.c                     |   13 +
> >>>   .../PeiDxeAMDSevVcHandler.c                   |   22 +
> >>>   .../PeiDxeSmmCpuException.c                   |   16 +
> >>>   .../SecAMDSevVcHandler.c                      |   45 +
> >>>   .../SecPeiCpuException.c                      |   16 +
> >>>   .../X64/AMDSevVcCommon.c                      | 1200 +++++++++++++++++
> >>>   UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
> >>>   UefiCpuPkg/Library/MpInitLib/MpLib.c          |  259 +++-
> >>>   UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
> >>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |   75 ++
> >>>   UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
> >>>   MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   31 +
> >>>   MdePkg/Library/BaseLib/Ia32/XGetBv.nasm       |   31 +
> >>>   MdePkg/Library/BaseLib/X64/VmgExit.nasm       |   32 +
> >>>   MdePkg/Library/BaseLib/X64/XGetBv.nasm        |   34 +
> >>>   OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |   80 ++
> >>>   OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  256 +++-
> >>>   OvmfPkg/ResetVector/ResetVector.nasmb         |   13 +
> >>>   .../X64/ExceptionHandlerAsm.nasm              |   15 +
> >>>   UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |    2 +-
> >>>   .../Library/MpInitLib/Ia32/MpFuncs.nasm       |   15 +
> >>>   UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc    |    4 +-
> >>>   UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm |  373 ++++-
> >>>   UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
> >>>   .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
> >>>   73 files changed, 3600 insertions(+), 97 deletions(-)
> >>>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
> >>>   create mode 100644 MdePkg/Include/Register/Amd/Ghcb.h
> >>>   create mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.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 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
> >>>   create mode 100644 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
> >>>   create mode 100644 MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
> >>>   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
> >>>   create mode 100644 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
> >>>
> >>
> >>
> >
> 
> 


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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-19 19:52 ` [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-09-26  8:00   ` Laszlo Ersek
  2019-09-26 14:00     ` Lendacky, Thomas
  2019-10-02 10:23   ` Laszlo Ersek
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-26  8:00 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 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Allocate memory for the GHCB pages during SEV initialization for use
> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
> clear the encryption mask from the current page table entries. Upon
> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).

skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
bit lost. I'm missing a parallel between the "early X64 page tables" and
the GHCB-related pages.

The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
until the DXE IPL builds new ones for the DXE phase. The latter also
*seemed* to be set up in SEC, and I thought they'd be used throughout
PEI -- I assumed the next place we'd need to massage GHCB pages would be
similarly in the DXE IPL, or thereabouts.

However, in this patch, we seem to allocate new pages for GHCB, and the
commit message implies they are supposed to be used during PEI. That
diverges from how long the "early X64 page tables" are used.

I guess this difference could be justified, especially because we do MP
stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
only consider the BSP.)

But then, the question becomes: what exactly do we need the GHCB page
allocated in SEC for? From the blurb, it seems that the GHCB allows the
guest to selectively (actively) share information with the hypervisor --
such as (parts of?) the register file, which the hypervisor cannot
directly access, for a SEV-ES guest.

But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
the GHCB, but that seems to be it. Do we write anything non-zero to that
block, ever?

Thanks
Laszlo

> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
>  OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
>  OvmfPkg/OvmfPkgX64.dsc              |  2 ++
>  OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
>  OvmfPkg/PlatformPei/AmdSev.c        | 36 ++++++++++++++++++++++++++++-
>  5 files changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 0ce5c01722ef..4369cf6d55e5 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -560,6 +560,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index e7455e35a55d..a74f5028068e 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -572,6 +572,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 0b8305cd10a2..fd714d386e75 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -571,6 +571,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index a9e424a6012a..62abc99f4622 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -105,6 +105,8 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
>  
>  [FixedPcd]
>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 7ae2f26a2ba7..30c0e4af7252 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -16,6 +16,9 @@
>  #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"
>  
> @@ -30,7 +33,10 @@ AmdSevEsInitialize (
>    VOID
>    )
>  {
> -  RETURN_STATUS     PcdStatus;
> +  VOID              *GhcbBase;
> +  PHYSICAL_ADDRESS  GhcbBasePa;
> +  UINTN             GhcbPageCount;
> +  RETURN_STATUS     PcdStatus, DecryptStatus;
>  
>    if (!MemEncryptSevEsIsEnabled ()) {
>      return;
> @@ -38,6 +44,34 @@ AmdSevEsInitialize (
>  
>    PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
>    ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  //
> +  // Allocate GHCB pages.
> +  //
> +  GhcbPageCount = mMaxCpuCount;
> +  GhcbBase = AllocatePages (GhcbPageCount);
> +  ASSERT (GhcbBase);
> +
> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> +  DecryptStatus = MemEncryptSevClearPageEncMask (
> +    0,
> +    GhcbBasePa,
> +    GhcbPageCount,
> +    TRUE
> +    );
> +  ASSERT_RETURN_ERROR (DecryptStatus);
> +
> +  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);
>  }
>  
>  /**
> 


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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-19 19:52 ` [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
@ 2019-09-26  8:17   ` Laszlo Ersek
  2019-09-26 14:46     ` Lendacky, Thomas
  2019-10-02 11:51   ` Laszlo Ersek
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-26  8:17 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>
> 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 (and
> that is done), 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.
>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index a567131a0591..84716952052d 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -79,7 +79,7 @@ [FD.MEMFD]
>  0x008000|0x001000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>
> -0x009000|0x001000
> +0x009000|0x002000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>
>  0x010000|0x010000
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 30c0e4af7252..699bb8b11557 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>    //
>    // Allocate GHCB pages.
>    //
> -  GhcbPageCount = mMaxCpuCount;
> +  GhcbPageCount = mMaxCpuCount * 2;
>    GhcbBase = AllocatePages (GhcbPageCount);
>    ASSERT (GhcbBase);
>
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 8909fc9313f4..d7c0ab3ada00 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -57,7 +57,7 @@
>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>    %endif
>
> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>    %endif
>
>

In connection to my question at [1]:

* Why do we add the extra page to SEC as well?

  I thought that, after patch 4 ("OvmfPkg/ResetVector: Add support for a
  32-bit SEV check"), we were all set for handling #VC, for the time of
  the initial SEV check; furthermore, that only CPUID would cause a #VC.

  If that's the case, when exactly would be the new page (at 0x80_a000)
  be used?

* Assuming we really need PcdOvmfSecGhcbSize = 0x002000, it is now
  theoretically possible that the 8KB area straddles a 2MB page
  boundary.

  Obviously we don't want to accommodate that corner case, but we should
  catch it. I think we should enforce -- with an %if / %error --
  something like:

  (FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) ==
  ((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21)

  That sanity check is likely best to squash into patch 6 ("OvmfPkg:
  Create a GHCB page for use during Sec phase").

[1] http://mid.mail-archive.com/ad289751-c1b7-c87a-41d1-9ce9838d94f1@redhat.com
    https://edk2.groups.io/g/devel/message/48080

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-26  8:00   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-26 14:00     ` Lendacky, Thomas
  2019-09-30 18:52       ` Laszlo Ersek
  2019-09-30 19:12       ` Laszlo Ersek
  0 siblings, 2 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-26 14:00 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 9/26/19 3:00 AM, Laszlo Ersek wrote:
> Hi Tom,
> 
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> Allocate memory for the GHCB pages during SEV initialization for use
>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>> clear the encryption mask from the current page table entries. Upon
>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
> 
> skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
> bit lost. I'm missing a parallel between the "early X64 page tables" and
> the GHCB-related pages.
> 
> The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
> until the DXE IPL builds new ones for the DXE phase. The latter also
> *seemed* to be set up in SEC, and I thought they'd be used throughout
> PEI -- I assumed the next place we'd need to massage GHCB pages would be
> similarly in the DXE IPL, or thereabouts.
> 
> However, in this patch, we seem to allocate new pages for GHCB, and the
> commit message implies they are supposed to be used during PEI. That
> diverges from how long the "early X64 page tables" are used.

At this stage, we need a GHCB page for every (v)CPU. So a new allocation
is done and then the pages are marked unencrypted. Once the new GHCB
pages are allocated, the original GHCB page for SEC is no longer needed
because the new allocation replaces it in the BSP. But the early page
table is still required in order to access all of the memory from the 2MB
range (0x800000 to 0x9fffff).

> 
> I guess this difference could be justified, especially because we do MP
> stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
> only consider the BSP.)
> 
> But then, the question becomes: what exactly do we need the GHCB page
> allocated in SEC for? From the blurb, it seems that the GHCB allows the

There are lots of different ways to cause a #VC. A #VC is generated for
debug statements that use port I/O, MMIO, intercept-able MSR accesses,
CPUID instructions, WBINVD instructions, etc. Many of these things happen
during SEC. With the debug serial output enabled, over 8,000 #VC
exceptions occur before allocating the new GHCB pages in
AmdSevEsInitialize().

> guest to selectively (actively) share information with the hypervisor --
> such as (parts of?) the register file, which the hypervisor cannot
> directly access, for a SEV-ES guest.
> 
> But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
> GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
> the GHCB, but that seems to be it. Do we write anything non-zero to that
> block, ever?

Yes, that happens in the SEC exception handler. When the #VC occurs, the
GHCB information is filled in and a VMGEXIT instruction is issued to exit
to the hypervisor. The hypervisor then accesses the GHCB in order to
perform the requested function.

Thanks,
Tom

> 
> Thanks
> Laszlo
> 
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
>>  OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
>>  OvmfPkg/OvmfPkgX64.dsc              |  2 ++
>>  OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
>>  OvmfPkg/PlatformPei/AmdSev.c        | 36 ++++++++++++++++++++++++++++-
>>  5 files changed, 43 insertions(+), 1 deletion(-)
>>
>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>> index 0ce5c01722ef..4369cf6d55e5 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -560,6 +560,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index e7455e35a55d..a74f5028068e 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -572,6 +572,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index 0b8305cd10a2..fd714d386e75 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -571,6 +571,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index a9e424a6012a..62abc99f4622 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -105,6 +105,8 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
>>  
>>  [FixedPcd]
>>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 7ae2f26a2ba7..30c0e4af7252 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -16,6 +16,9 @@
>>  #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"
>>  
>> @@ -30,7 +33,10 @@ AmdSevEsInitialize (
>>    VOID
>>    )
>>  {
>> -  RETURN_STATUS     PcdStatus;
>> +  VOID              *GhcbBase;
>> +  PHYSICAL_ADDRESS  GhcbBasePa;
>> +  UINTN             GhcbPageCount;
>> +  RETURN_STATUS     PcdStatus, DecryptStatus;
>>  
>>    if (!MemEncryptSevEsIsEnabled ()) {
>>      return;
>> @@ -38,6 +44,34 @@ AmdSevEsInitialize (
>>  
>>    PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
>>    ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> +  //
>> +  // Allocate GHCB pages.
>> +  //
>> +  GhcbPageCount = mMaxCpuCount;
>> +  GhcbBase = AllocatePages (GhcbPageCount);
>> +  ASSERT (GhcbBase);
>> +
>> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> +  DecryptStatus = MemEncryptSevClearPageEncMask (
>> +    0,
>> +    GhcbBasePa,
>> +    GhcbPageCount,
>> +    TRUE
>> +    );
>> +  ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> +  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);
>>  }
>>  
>>  /**
>>
> 

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-26  8:17   ` [edk2-devel] " Laszlo Ersek
@ 2019-09-26 14:46     ` Lendacky, Thomas
  2019-09-30 19:15       ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-26 14:46 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 9/26/19 3:17 AM, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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 (and
>> that is done), 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.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>>  3 files changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index a567131a0591..84716952052d 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -79,7 +79,7 @@ [FD.MEMFD]
>>  0x008000|0x001000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>>
>> -0x009000|0x001000
>> +0x009000|0x002000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>
>>  0x010000|0x010000
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 30c0e4af7252..699bb8b11557 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>>    //
>>    // Allocate GHCB pages.
>>    //
>> -  GhcbPageCount = mMaxCpuCount;
>> +  GhcbPageCount = mMaxCpuCount * 2;
>>    GhcbBase = AllocatePages (GhcbPageCount);
>>    ASSERT (GhcbBase);
>>
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 8909fc9313f4..d7c0ab3ada00 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -57,7 +57,7 @@
>>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>>    %endif
>>
>> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>>    %endif
>>
>>
> 
> In connection to my question at [1]:
> 
> * Why do we add the extra page to SEC as well?

We add the extra page because it may be referenced should a read or write
to DR7 be done during SEC. Based on the GHCB protocol, we need to cache
the value written (and not actually update the DR7 register) and return
it on read.

> 
>   I thought that, after patch 4 ("OvmfPkg/ResetVector: Add support for a
>   32-bit SEV check"), we were all set for handling #VC, for the time of
>   the initial SEV check; furthermore, that only CPUID would cause a #VC.

Patch #4 covers the small window where the SEV support check is being done
in 32-bit mode in order to build the page tables for 64-bit mode. The
exception handling support is very specific at this stage to perform just
the GHCB CPUID protocol because we are not running in 64-bit mode and so a
GHCB page can't be used because it can't be shared with the hypervisor.

> 
>   If that's the case, when exactly would be the new page (at 0x80_a000)
>   be used?

Patch #17 (UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for
Sec phase) is where the SEC exception handling is enabled which will use
the new pages at 0x80_9000 and 0x80_a000. The GHCB page has a specific
format and we can't store data in it, so another page is needed for the
DR7 data.

It would be nice if EDK2 had support for per-CPU variables so that this
extra page wouldn't be required.

And since the GHCB_BASE is used by the SEC exception handler, I probably
need to rename PcdOvmfSecGhcbBase/Size to PcdUefiCpuSecGhcbBase/Size and
define them under UefiCpuPkg and just initialize them in the OvmfPkg,
right?

> 
> * Assuming we really need PcdOvmfSecGhcbSize = 0x002000, it is now
>   theoretically possible that the 8KB area straddles a 2MB page
>   boundary.
> 
>   Obviously we don't want to accommodate that corner case, but we should
>   catch it. I think we should enforce -- with an %if / %error --
>   something like:
> 
>   (FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) ==
>   ((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21)
> 
>   That sanity check is likely best to squash into patch 6 ("OvmfPkg:
>   Create a GHCB page for use during Sec phase").

Yup, I can add that.

Thanks,
Tom

> 
> [1] http://mid.mail-archive.com/ad289751-c1b7-c87a-41d1-9ce9838d94f1@redhat.com
>     https://edk2.groups.io/g/devel/message/48080
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-26 14:00     ` Lendacky, Thomas
@ 2019-09-30 18:52       ` Laszlo Ersek
  2019-09-30 19:49         ` Lendacky, Thomas
  2019-09-30 19:12       ` Laszlo Ersek
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-30 18:52 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 09/26/19 16:00, Lendacky, Thomas wrote:
> On 9/26/19 3:00 AM, Laszlo Ersek wrote:
>> Hi Tom,
>>
>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> Allocate memory for the GHCB pages during SEV initialization for use
>>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>>> clear the encryption mask from the current page table entries. Upon
>>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
>>
>> skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
>> bit lost. I'm missing a parallel between the "early X64 page tables" and
>> the GHCB-related pages.
>>
>> The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
>> until the DXE IPL builds new ones for the DXE phase. The latter also
>> *seemed* to be set up in SEC, and I thought they'd be used throughout
>> PEI -- I assumed the next place we'd need to massage GHCB pages would be
>> similarly in the DXE IPL, or thereabouts.
>>
>> However, in this patch, we seem to allocate new pages for GHCB, and the
>> commit message implies they are supposed to be used during PEI. That
>> diverges from how long the "early X64 page tables" are used.
> 
> At this stage, we need a GHCB page for every (v)CPU. So a new allocation
> is done and then the pages are marked unencrypted. Once the new GHCB
> pages are allocated, the original GHCB page for SEC is no longer needed
> because the new allocation replaces it in the BSP. But the early page
> table is still required in order to access all of the memory from the 2MB
> range (0x800000 to 0x9fffff).
> 
>>
>> I guess this difference could be justified, especially because we do MP
>> stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
>> only consider the BSP.)
>>
>> But then, the question becomes: what exactly do we need the GHCB page
>> allocated in SEC for? From the blurb, it seems that the GHCB allows the
> 
> There are lots of different ways to cause a #VC. A #VC is generated for
> debug statements that use port I/O, MMIO, intercept-able MSR accesses,
> CPUID instructions, WBINVD instructions, etc. Many of these things happen
> during SEC. With the debug serial output enabled, over 8,000 #VC
> exceptions occur before allocating the new GHCB pages in
> AmdSevEsInitialize().
> 
>> guest to selectively (actively) share information with the hypervisor --
>> such as (parts of?) the register file, which the hypervisor cannot
>> directly access, for a SEV-ES guest.
>>
>> But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
>> GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
>> the GHCB, but that seems to be it. Do we write anything non-zero to that
>> block, ever?
> 
> Yes, that happens in the SEC exception handler. When the #VC occurs, the
> GHCB information is filled in and a VMGEXIT instruction is issued to exit
> to the hypervisor. The hypervisor then accesses the GHCB in order to
> perform the requested function.

Thanks, very helpful.

Can you please work this info into the relevant commit messages? (No
need to repost just because of that, of course.)

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-26 14:00     ` Lendacky, Thomas
  2019-09-30 18:52       ` Laszlo Ersek
@ 2019-09-30 19:12       ` Laszlo Ersek
  2019-09-30 19:51         ` Lendacky, Thomas
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-30 19: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 09/26/19 16:00, Lendacky, Thomas wrote:
> On 9/26/19 3:00 AM, Laszlo Ersek wrote:
>> Hi Tom,
>>
>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> Allocate memory for the GHCB pages during SEV initialization for use
>>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>>> clear the encryption mask from the current page table entries. Upon
>>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
>>
>> skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
>> bit lost. I'm missing a parallel between the "early X64 page tables" and
>> the GHCB-related pages.
>>
>> The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
>> until the DXE IPL builds new ones for the DXE phase. The latter also
>> *seemed* to be set up in SEC, and I thought they'd be used throughout
>> PEI -- I assumed the next place we'd need to massage GHCB pages would be
>> similarly in the DXE IPL, or thereabouts.
>>
>> However, in this patch, we seem to allocate new pages for GHCB, and the
>> commit message implies they are supposed to be used during PEI. That
>> diverges from how long the "early X64 page tables" are used.
> 
> At this stage, we need a GHCB page for every (v)CPU. So a new allocation
> is done and then the pages are marked unencrypted. Once the new GHCB
> pages are allocated, the original GHCB page for SEC is no longer needed
> because the new allocation replaces it in the BSP. But the early page
> table is still required in order to access all of the memory from the 2MB
> range (0x800000 to 0x9fffff).
> 
>>
>> I guess this difference could be justified, especially because we do MP
>> stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
>> only consider the BSP.)
>>
>> But then, the question becomes: what exactly do we need the GHCB page
>> allocated in SEC for? From the blurb, it seems that the GHCB allows the
> 
> There are lots of different ways to cause a #VC. A #VC is generated for
> debug statements that use port I/O, MMIO, intercept-able MSR accesses,
> CPUID instructions, WBINVD instructions, etc. Many of these things happen
> during SEC. With the debug serial output enabled, over 8,000 #VC
> exceptions occur before allocating the new GHCB pages in
> AmdSevEsInitialize().
> 
>> guest to selectively (actively) share information with the hypervisor --
>> such as (parts of?) the register file, which the hypervisor cannot
>> directly access, for a SEV-ES guest.
>>
>> But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
>> GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
>> the GHCB, but that seems to be it. Do we write anything non-zero to that
>> block, ever?
> 
> Yes, that happens in the SEC exception handler. When the #VC occurs, the
> GHCB information is filled in and a VMGEXIT instruction is issued to exit
> to the hypervisor. The hypervisor then accesses the GHCB in order to
> perform the requested function.

(Sorry about sending this in a separate email.)

So... Where is the #VC handler that implements this logic in SEC?

... Ah wait, now I understand why I got confused. The patch series thus
far has modified SEC code that is specific to OVMF, and then it advances
to OvmfPkg/PlatformPei. I thought we were done with SEC changes in OVMF,
and I didn't understand where the #VC handler you refer to above was.

But, looking a bit ahead in the series, I see the exception handler
being built gradually, in UefiCpuPkg, and (I guess) also enabled in
OVMF's SEC somewhere / sometime.

I wonder what the best ordering would be, for the patches in the series.
The middle seems to be alternating between UefiCpuPkg and OvmfPkg.
That's quite unusual. I don't have a clear understanding of the feature
yet, so I can't authoritatively suggest a "better" structure. As a first
guess, I would suggest constructing the building blocks in MdePkg and
UefiCpuPkg (libraries, primarily), then utilizing them in MdeModulePkg
(core drivers), then adding platform code in OvmfPkg. Also, I would
suggest copious cross-references between the patches (identified by
subjects).

I hope this is not too annoying, just trying to ask for crutches :)

I'll try to continue the review of the series this week.

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-26 14:46     ` Lendacky, Thomas
@ 2019-09-30 19:15       ` Laszlo Ersek
  2019-09-30 19:52         ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-30 19:15 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 09/26/19 16:46, Lendacky, Thomas wrote:
> On 9/26/19 3:17 AM, Laszlo Ersek wrote:
>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> 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 (and
>>> that is done), 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.
>>>
>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>>>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>>>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>>>  3 files changed, 3 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>>> index a567131a0591..84716952052d 100644
>>> --- a/OvmfPkg/OvmfPkgX64.fdf
>>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>>> @@ -79,7 +79,7 @@ [FD.MEMFD]
>>>  0x008000|0x001000
>>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>>>
>>> -0x009000|0x001000
>>> +0x009000|0x002000
>>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>>
>>>  0x010000|0x010000
>>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>>> index 30c0e4af7252..699bb8b11557 100644
>>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>>> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>>>    //
>>>    // Allocate GHCB pages.
>>>    //
>>> -  GhcbPageCount = mMaxCpuCount;
>>> +  GhcbPageCount = mMaxCpuCount * 2;
>>>    GhcbBase = AllocatePages (GhcbPageCount);
>>>    ASSERT (GhcbBase);
>>>
>>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>>> index 8909fc9313f4..d7c0ab3ada00 100644
>>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>>> @@ -57,7 +57,7 @@
>>>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>>>    %endif
>>>
>>> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
>>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>>>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>>>    %endif
>>>
>>>
>>
>> In connection to my question at [1]:
>>
>> * Why do we add the extra page to SEC as well?
> 
> We add the extra page because it may be referenced should a read or write
> to DR7 be done during SEC. Based on the GHCB protocol, we need to cache
> the value written (and not actually update the DR7 register) and return
> it on read.
> 
>>
>>   I thought that, after patch 4 ("OvmfPkg/ResetVector: Add support for a
>>   32-bit SEV check"), we were all set for handling #VC, for the time of
>>   the initial SEV check; furthermore, that only CPUID would cause a #VC.
> 
> Patch #4 covers the small window where the SEV support check is being done
> in 32-bit mode in order to build the page tables for 64-bit mode. The
> exception handling support is very specific at this stage to perform just
> the GHCB CPUID protocol because we are not running in 64-bit mode and so a
> GHCB page can't be used because it can't be shared with the hypervisor.
> 
>>
>>   If that's the case, when exactly would be the new page (at 0x80_a000)
>>   be used?
> 
> Patch #17 (UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for
> Sec phase) is where the SEC exception handling is enabled which will use
> the new pages at 0x80_9000 and 0x80_a000. The GHCB page has a specific
> format and we can't store data in it, so another page is needed for the
> DR7 data.

Thanks, that seems to confirm my understanding of your other reply.

> It would be nice if EDK2 had support for per-CPU variables so that this
> extra page wouldn't be required.
> 
> And since the GHCB_BASE is used by the SEC exception handler, I probably
> need to rename PcdOvmfSecGhcbBase/Size to PcdUefiCpuSecGhcbBase/Size and
> define them under UefiCpuPkg and just initialize them in the OvmfPkg,
> right?

Yes, that appears correct (also aligned with what I responded to your
other email) -- UefiCpuPkg would offer the feature, and platform code in
OvmfPkg would put it to use.

> 
>>
>> * Assuming we really need PcdOvmfSecGhcbSize = 0x002000, it is now
>>   theoretically possible that the 8KB area straddles a 2MB page
>>   boundary.
>>
>>   Obviously we don't want to accommodate that corner case, but we should
>>   catch it. I think we should enforce -- with an %if / %error --
>>   something like:
>>
>>   (FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) ==
>>   ((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21)
>>
>>   That sanity check is likely best to squash into patch 6 ("OvmfPkg:
>>   Create a GHCB page for use during Sec phase").
> 
> Yup, I can add that.

Thanks!
Laszlo

>>
>> [1] http://mid.mail-archive.com/ad289751-c1b7-c87a-41d1-9ce9838d94f1@redhat.com
>>     https://edk2.groups.io/g/devel/message/48080
>>
>> Thanks!
>> Laszlo
>>


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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-24 18:57     ` Lendacky, Thomas
  2019-09-25 14:45       ` Laszlo Ersek
@ 2019-09-30 19:29       ` Laszlo Ersek
  2019-09-30 19:55         ` Lendacky, Thomas
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-09-30 19:29 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 09/24/19 20:57, Lendacky, Thomas wrote:
> On 9/24/19 8:42 AM, Laszlo Ersek wrote:
>> On 09/19/19 21:52, Lendacky, Thomas wrote:

>>> +    ; Issue VMGEXIT (rep; vmmcall)
>>> +    db      0xf3
>>> +    db      0x0f
>>> +    db      0x01
>>> +    db      0xd9
>>
>> (8) Can you please file an RFE at <https://bugzilla.nasm.us/>, for
>> supporting this instruction, and add the link here, as a comment? I've
>> been fighting an uphill battle against DB-encoded instructions in edk2
>> assembly code.
> 
> Yes, let me look into that.

Actually, from peeking ahead at patch "MdePkg/BaseLib: Add support for
the VMGEXIT instruction", it looks like "rep; vmmcall" is already
understood by NASM.

Can you use that here?

... In case that sequence of mnemonics is specific to NASM's 64-bit
mode: can you bracket it with BITS 64 / BITS 32, just so we can avoid
the DBs? Something like (if necessary):

; Issue VMGEXIT
BITS 64
rep; vmmcall
BITS 32


Hmmm why don't I try this out myself...

... So, first, the semicolon (;) seems wrong in the NASM source. It
turns vmmcall into a comment, and NASM assembles only the REP prefix (to
a single 0xF3 byte).

Second, when I remove the semicolon, NASM indeed complains in 32-bit
mode "error: instruction not supported in 32-bit mode".

But the following does work:

BITS 64
rep vmmcall
BITS 32

and for it, NASM generates the bytes seen above (f3 0f 01 d9).

So I suggest:
- using this pattern in the present patch
- using this pattern in the Ia32/VmgExit.nasm source file in the
MdePkg/BaseLib patch
- removing the semicolon in the X64/VmgExit.nasm source file in the
MdePkg/BaseLib patch

Thanks!
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-30 18:52       ` Laszlo Ersek
@ 2019-09-30 19:49         ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-30 19:49 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 9/30/19 1:52 PM, Laszlo Ersek via Groups.Io wrote:
> On 09/26/19 16:00, Lendacky, Thomas wrote:
>> On 9/26/19 3:00 AM, Laszlo Ersek wrote:
>>> Hi Tom,
>>>
>>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>>
>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>>>> clear the encryption mask from the current page table entries. Upon
>>>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
>>>
>>> skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
>>> bit lost. I'm missing a parallel between the "early X64 page tables" and
>>> the GHCB-related pages.
>>>
>>> The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
>>> until the DXE IPL builds new ones for the DXE phase. The latter also
>>> *seemed* to be set up in SEC, and I thought they'd be used throughout
>>> PEI -- I assumed the next place we'd need to massage GHCB pages would be
>>> similarly in the DXE IPL, or thereabouts.
>>>
>>> However, in this patch, we seem to allocate new pages for GHCB, and the
>>> commit message implies they are supposed to be used during PEI. That
>>> diverges from how long the "early X64 page tables" are used.
>>
>> At this stage, we need a GHCB page for every (v)CPU. So a new allocation
>> is done and then the pages are marked unencrypted. Once the new GHCB
>> pages are allocated, the original GHCB page for SEC is no longer needed
>> because the new allocation replaces it in the BSP. But the early page
>> table is still required in order to access all of the memory from the 2MB
>> range (0x800000 to 0x9fffff).
>>
>>>
>>> I guess this difference could be justified, especially because we do MP
>>> stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
>>> only consider the BSP.)
>>>
>>> But then, the question becomes: what exactly do we need the GHCB page
>>> allocated in SEC for? From the blurb, it seems that the GHCB allows the
>>
>> There are lots of different ways to cause a #VC. A #VC is generated for
>> debug statements that use port I/O, MMIO, intercept-able MSR accesses,
>> CPUID instructions, WBINVD instructions, etc. Many of these things happen
>> during SEC. With the debug serial output enabled, over 8,000 #VC
>> exceptions occur before allocating the new GHCB pages in
>> AmdSevEsInitialize().
>>
>>> guest to selectively (actively) share information with the hypervisor --
>>> such as (parts of?) the register file, which the hypervisor cannot
>>> directly access, for a SEV-ES guest.
>>>
>>> But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
>>> GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
>>> the GHCB, but that seems to be it. Do we write anything non-zero to that
>>> block, ever?
>>
>> Yes, that happens in the SEC exception handler. When the #VC occurs, the
>> GHCB information is filled in and a VMGEXIT instruction is issued to exit
>> to the hypervisor. The hypervisor then accesses the GHCB in order to
>> perform the requested function.
> 
> Thanks, very helpful.
> 
> Can you please work this info into the relevant commit messages? (No
> need to repost just because of that, of course.)

Will do.

Thanks,
Tom

> 
> Thanks!
> Laszlo
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-30 19:12       ` Laszlo Ersek
@ 2019-09-30 19:51         ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-30 19:51 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 9/30/19 2:12 PM, Laszlo Ersek wrote:
> On 09/26/19 16:00, Lendacky, Thomas wrote:
>> On 9/26/19 3:00 AM, Laszlo Ersek wrote:
>>> Hi Tom,
>>>
>>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>>
>>>> Allocate memory for the GHCB pages during SEV initialization for use
>>>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>>>> clear the encryption mask from the current page table entries. Upon
>>>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
>>>
>>> skimming this patch and the next two ones for OvmfPkg (#10, #11), I'm a
>>> bit lost. I'm missing a parallel between the "early X64 page tables" and
>>> the GHCB-related pages.
>>>
>>> The former are set up (in X64 OVMF) in SEC, and are used throughout PEI
>>> until the DXE IPL builds new ones for the DXE phase. The latter also
>>> *seemed* to be set up in SEC, and I thought they'd be used throughout
>>> PEI -- I assumed the next place we'd need to massage GHCB pages would be
>>> similarly in the DXE IPL, or thereabouts.
>>>
>>> However, in this patch, we seem to allocate new pages for GHCB, and the
>>> commit message implies they are supposed to be used during PEI. That
>>> diverges from how long the "early X64 page tables" are used.
>>
>> At this stage, we need a GHCB page for every (v)CPU. So a new allocation
>> is done and then the pages are marked unencrypted. Once the new GHCB
>> pages are allocated, the original GHCB page for SEC is no longer needed
>> because the new allocation replaces it in the BSP. But the early page
>> table is still required in order to access all of the memory from the 2MB
>> range (0x800000 to 0x9fffff).
>>
>>>
>>> I guess this difference could be justified, especially because we do MP
>>> stuff in PEI. (And we need separate GHCB stuff per VCPU -- in SEC we
>>> only consider the BSP.)
>>>
>>> But then, the question becomes: what exactly do we need the GHCB page
>>> allocated in SEC for? From the blurb, it seems that the GHCB allows the
>>
>> There are lots of different ways to cause a #VC. A #VC is generated for
>> debug statements that use port I/O, MMIO, intercept-able MSR accesses,
>> CPUID instructions, WBINVD instructions, etc. Many of these things happen
>> during SEC. With the debug serial output enabled, over 8,000 #VC
>> exceptions occur before allocating the new GHCB pages in
>> AmdSevEsInitialize().
>>
>>> guest to selectively (actively) share information with the hypervisor --
>>> such as (parts of?) the register file, which the hypervisor cannot
>>> directly access, for a SEV-ES guest.
>>>
>>> But, we never seem to place such information at PcdOvmfSecGhcbBase (aka
>>> GHCB_BASE) in SEC. We program the GHCB's base address, and then we clear
>>> the GHCB, but that seems to be it. Do we write anything non-zero to that
>>> block, ever?
>>
>> Yes, that happens in the SEC exception handler. When the #VC occurs, the
>> GHCB information is filled in and a VMGEXIT instruction is issued to exit
>> to the hypervisor. The hypervisor then accesses the GHCB in order to
>> perform the requested function.
> 
> (Sorry about sending this in a separate email.)
> 
> So... Where is the #VC handler that implements this logic in SEC?
> 
> ... Ah wait, now I understand why I got confused. The patch series thus
> far has modified SEC code that is specific to OVMF, and then it advances
> to OvmfPkg/PlatformPei. I thought we were done with SEC changes in OVMF,
> and I didn't understand where the #VC handler you refer to above was.
> 
> But, looking a bit ahead in the series, I see the exception handler
> being built gradually, in UefiCpuPkg, and (I guess) also enabled in
> OVMF's SEC somewhere / sometime.
> 
> I wonder what the best ordering would be, for the patches in the series.
> The middle seems to be alternating between UefiCpuPkg and OvmfPkg.
> That's quite unusual. I don't have a clear understanding of the feature
> yet, so I can't authoritatively suggest a "better" structure. As a first
> guess, I would suggest constructing the building blocks in MdePkg and
> UefiCpuPkg (libraries, primarily), then utilizing them in MdeModulePkg
> (core drivers), then adding platform code in OvmfPkg. Also, I would
> suggest copious cross-references between the patches (identified by
> subjects).
> 
> I hope this is not too annoying, just trying to ask for crutches :)

No worries, I'll see what I can do in ordering the patches so they make
more sense to a reviewer looking at the code for the first time.

Thanks,
Tom

> 
> I'll try to continue the review of the series this week.
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-30 19:15       ` Laszlo Ersek
@ 2019-09-30 19:52         ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-30 19:52 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 9/30/19 2:15 PM, Laszlo Ersek via Groups.Io wrote:
> On 09/26/19 16:46, Lendacky, Thomas wrote:
>> On 9/26/19 3:17 AM, Laszlo Ersek wrote:
>>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>>
>>>> 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 (and
>>>> that is done), 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.
>>>>
>>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>>> ---
>>>>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>>>>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>>>>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>>>>  3 files changed, 3 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>>>> index a567131a0591..84716952052d 100644
>>>> --- a/OvmfPkg/OvmfPkgX64.fdf
>>>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>>>> @@ -79,7 +79,7 @@ [FD.MEMFD]
>>>>  0x008000|0x001000
>>>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>>>>
>>>> -0x009000|0x001000
>>>> +0x009000|0x002000
>>>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>>>
>>>>  0x010000|0x010000
>>>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>>>> index 30c0e4af7252..699bb8b11557 100644
>>>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>>>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>>>> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>>>>    //
>>>>    // Allocate GHCB pages.
>>>>    //
>>>> -  GhcbPageCount = mMaxCpuCount;
>>>> +  GhcbPageCount = mMaxCpuCount * 2;
>>>>    GhcbBase = AllocatePages (GhcbPageCount);
>>>>    ASSERT (GhcbBase);
>>>>
>>>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>>>> index 8909fc9313f4..d7c0ab3ada00 100644
>>>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>>>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>>>> @@ -57,7 +57,7 @@
>>>>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>>>>    %endif
>>>>
>>>> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
>>>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>>>>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>>>>    %endif
>>>>
>>>>
>>>
>>> In connection to my question at [1]:
>>>
>>> * Why do we add the extra page to SEC as well?
>>
>> We add the extra page because it may be referenced should a read or write
>> to DR7 be done during SEC. Based on the GHCB protocol, we need to cache
>> the value written (and not actually update the DR7 register) and return
>> it on read.
>>
>>>
>>>   I thought that, after patch 4 ("OvmfPkg/ResetVector: Add support for a
>>>   32-bit SEV check"), we were all set for handling #VC, for the time of
>>>   the initial SEV check; furthermore, that only CPUID would cause a #VC.
>>
>> Patch #4 covers the small window where the SEV support check is being done
>> in 32-bit mode in order to build the page tables for 64-bit mode. The
>> exception handling support is very specific at this stage to perform just
>> the GHCB CPUID protocol because we are not running in 64-bit mode and so a
>> GHCB page can't be used because it can't be shared with the hypervisor.
>>
>>>
>>>   If that's the case, when exactly would be the new page (at 0x80_a000)
>>>   be used?
>>
>> Patch #17 (UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for
>> Sec phase) is where the SEC exception handling is enabled which will use
>> the new pages at 0x80_9000 and 0x80_a000. The GHCB page has a specific
>> format and we can't store data in it, so another page is needed for the
>> DR7 data.
> 
> Thanks, that seems to confirm my understanding of your other reply.
> 
>> It would be nice if EDK2 had support for per-CPU variables so that this
>> extra page wouldn't be required.
>>
>> And since the GHCB_BASE is used by the SEC exception handler, I probably
>> need to rename PcdOvmfSecGhcbBase/Size to PcdUefiCpuSecGhcbBase/Size and
>> define them under UefiCpuPkg and just initialize them in the OvmfPkg,
>> right?
> 
> Yes, that appears correct (also aligned with what I responded to your
> other email) -- UefiCpuPkg would offer the feature, and platform code in
> OvmfPkg would put it to use.

Ok, let me see how I can rework this area.

Thanks,
Tom

> 
>>
>>>
>>> * Assuming we really need PcdOvmfSecGhcbSize = 0x002000, it is now
>>>   theoretically possible that the 8KB area straddles a 2MB page
>>>   boundary.
>>>
>>>   Obviously we don't want to accommodate that corner case, but we should
>>>   catch it. I think we should enforce -- with an %if / %error --
>>>   something like:
>>>
>>>   (FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) ==
>>>   ((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21)
>>>
>>>   That sanity check is likely best to squash into patch 6 ("OvmfPkg:
>>>   Create a GHCB page for use during Sec phase").
>>
>> Yup, I can add that.
> 
> Thanks!
> Laszlo
> 
>>>
>>> [1] http://mid.mail-archive.com/ad289751-c1b7-c87a-41d1-9ce9838d94f1@redhat.com
>>>     https://edk2.groups.io/g/devel/message/48080
>>>
>>> Thanks!
>>> Laszlo
>>>
> 
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-09-30 19:29       ` Laszlo Ersek
@ 2019-09-30 19:55         ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-09-30 19:55 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 9/30/19 2:29 PM, Laszlo Ersek via Groups.Io wrote:
> On 09/24/19 20:57, Lendacky, Thomas wrote:
>> On 9/24/19 8:42 AM, Laszlo Ersek wrote:
>>> On 09/19/19 21:52, Lendacky, Thomas wrote:
> 
>>>> +    ; Issue VMGEXIT (rep; vmmcall)
>>>> +    db      0xf3
>>>> +    db      0x0f
>>>> +    db      0x01
>>>> +    db      0xd9
>>>
>>> (8) Can you please file an RFE at <https://bugzilla.nasm.us/>, for
>>> supporting this instruction, and add the link here, as a comment? I've
>>> been fighting an uphill battle against DB-encoded instructions in edk2
>>> assembly code.
>>
>> Yes, let me look into that.
> 
> Actually, from peeking ahead at patch "MdePkg/BaseLib: Add support for
> the VMGEXIT instruction", it looks like "rep; vmmcall" is already
> understood by NASM.
> 
> Can you use that here?
> 
> ... In case that sequence of mnemonics is specific to NASM's 64-bit
> mode: can you bracket it with BITS 64 / BITS 32, just so we can avoid
> the DBs? Something like (if necessary):
> 
> ; Issue VMGEXIT
> BITS 64
> rep; vmmcall
> BITS 32
> 
> 
> Hmmm why don't I try this out myself...
> 
> ... So, first, the semicolon (;) seems wrong in the NASM source. It
> turns vmmcall into a comment, and NASM assembles only the REP prefix (to
> a single 0xF3 byte).

Yeah, missed that.  I'm so used to the GCC/GAS syntax.

> 
> Second, when I remove the semicolon, NASM indeed complains in 32-bit
> mode "error: instruction not supported in 32-bit mode".

Right, that was why I moved to the DBs.

> 
> But the following does work:
> 
> BITS 64
> rep vmmcall
> BITS 32
> 
> and for it, NASM generates the bytes seen above (f3 0f 01 d9).

Excellent, I'll use that.

> 
> So I suggest:
> - using this pattern in the present patch
> - using this pattern in the Ia32/VmgExit.nasm source file in the
> MdePkg/BaseLib patch
> - removing the semicolon in the X64/VmgExit.nasm source file in the
> MdePkg/BaseLib patch
> 

Will do.

Thanks,
Tom

> Thanks!
> Laszlo
> 
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-09-19 19:52 ` [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
  2019-09-26  8:00   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 10:23   ` Laszlo Ersek
  2019-10-02 14:43     ` Lendacky, Thomas
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 10:23 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

After the discussion elsewhere in this patch thread, which related to
commit messages, and patch order in the series, I can make a few coding
style comments on the patch. (No change to functionality.)

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Allocate memory for the GHCB pages during SEV initialization for use
> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
> clear the encryption mask from the current page table entries. Upon
> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
>  OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
>  OvmfPkg/OvmfPkgX64.dsc              |  2 ++
>  OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
>  OvmfPkg/PlatformPei/AmdSev.c        | 36 ++++++++++++++++++++++++++++-
>  5 files changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 0ce5c01722ef..4369cf6d55e5 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -560,6 +560,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index e7455e35a55d..a74f5028068e 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -572,6 +572,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 0b8305cd10a2..fd714d386e75 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -571,6 +571,8 @@ [PcdsDynamicDefault]
>  
>    # Set SEV-ES defaults
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>  
>  !if $(SMM_REQUIRE) == TRUE
>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
> index a9e424a6012a..62abc99f4622 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -105,6 +105,8 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
>  
>  [FixedPcd]
>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress

(1) Once you move PcdSevEsActive near the other
gEfiMdeModulePkgTokenSpaceGuid PCDs, per
<http://mid.mail-archive.com/bd38da31-0985-2ffc-b60d-f867a0218ab2@redhat.com>,
please keep these grouped with it, too.

> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 7ae2f26a2ba7..30c0e4af7252 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -16,6 +16,9 @@
>  #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>

(2) This #include list is currently sorted. Can you please keep it sorted?

>  
>  #include "Platform.h"
>  
> @@ -30,7 +33,10 @@ AmdSevEsInitialize (
>    VOID
>    )
>  {
> -  RETURN_STATUS     PcdStatus;
> +  VOID              *GhcbBase;
> +  PHYSICAL_ADDRESS  GhcbBasePa;
> +  UINTN             GhcbPageCount;
> +  RETURN_STATUS     PcdStatus, DecryptStatus;
>  
>    if (!MemEncryptSevEsIsEnabled ()) {
>      return;
> @@ -38,6 +44,34 @@ AmdSevEsInitialize (
>  
>    PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
>    ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  //
> +  // Allocate GHCB pages.
> +  //
> +  GhcbPageCount = mMaxCpuCount;
> +  GhcbBase = AllocatePages (GhcbPageCount);

Yes, AllocatePages() looks safe, per
<http://mid.mail-archive.com/4029f533-9f2a-ba71-2ba6-348187dc7684@redhat.com>.

> +  ASSERT (GhcbBase);

(3) I don't really like using *only* an ASSERT for stopping, when we run
out of resources in a place like this (i.e. where there's no way to
recover, or to report the issue nicely). I'd suggest throwing in an
explicit check and a CpuDeadLoop(), in addition to the ASSERT. Anyway,
not really important, up to you.

(4) The expression in the ASSERT() should compare GhcbBase against NULL
explicitly, however. The edk2 coding style permits the implicit "!= 0"
comparison (in controlling expressions) for BOOLEANs only.

> +
> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> +  DecryptStatus = MemEncryptSevClearPageEncMask (
> +    0,
> +    GhcbBasePa,
> +    GhcbPageCount,
> +    TRUE
> +    );
> +  ASSERT_RETURN_ERROR (DecryptStatus);
> +
> +  SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);

(5) The following would be more idiomatic:

  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));

(like you write below already)

> +
> +  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));

(6) This line is too long; please try to stick with <=80 chars per line.

(7) UINTN values (such as GhcbPageCount) should be converted to UINT64
explicitly, and then formatted with %lu.

(8) GhcbBase is a pointer-to-void; please either format it with %p, or
use GhcbBasePa. (We can rely on the latter being UINT64.)

  DEBUG ((DEBUG_INFO,
    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%lx\n",
    (UINT64)GhcbPageCount, GhcbBasePa));

> +
> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
>  }
>  
>  /**
> 

(9) If you like, you can drop the (UINT64) casts from all the
"GhcbBasePa" references; all of edk2 uses PHYSICAL_ADDRESS and
EFI_PHYSICAL_ADDRESS interchangeably, and the latter is UINT64 per spec.

With the above updated -- (3) and (9) are optional --

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-09-19 19:52 ` [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
  2019-09-26  8:17   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 11:51   ` Laszlo Ersek
  2019-10-02 16:06     ` Lendacky, Thomas
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 11:51 UTC (permalink / raw)
  To: devel, thomas.lendacky, Singh, Brijesh
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni

A few more comments:

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>
> 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 (and
> that is done), 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.
>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index a567131a0591..84716952052d 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -79,7 +79,7 @@ [FD.MEMFD]
>  0x008000|0x001000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>
> -0x009000|0x001000
> +0x009000|0x002000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>
>  0x010000|0x010000
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index 30c0e4af7252..699bb8b11557 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>    //
>    // Allocate GHCB pages.
>    //
> -  GhcbPageCount = mMaxCpuCount;
> +  GhcbPageCount = mMaxCpuCount * 2;
>    GhcbBase = AllocatePages (GhcbPageCount);
>    ASSERT (GhcbBase);
>
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 8909fc9313f4..d7c0ab3ada00 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -57,7 +57,7 @@
>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>    %endif
>
> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>    %endif
>
>

(1) I think it makes sense to split this patch in two, one half for SEC,
another for PlatformPei.

(2) The PlatformPei hunk makes me realize that
"mS3AcpiReservedMemorySize" in PublishPeiMemory() is already
proportional to "mMaxCpuCount".

The current coefficient is PcdCpuApStackSize (= 32KB). If we're adding
8KB (2 pages) per CPU, for SEV-ES, that's not negligible (1/4th
increase).

Can you please extend both patch#8, and the PlatformPei hunk split out
of patch#10 (= this patch), to increase "mS3AcpiReservedMemorySize" in
PublishPeiMemory(), if MemEncryptSevEsIsEnabled()?

   if (mS3Supported) {
     mS3AcpiReservedMemorySize = ...;
+    if (MemEncryptSevEsIsEnabled ()) {
+      mS3AcpiReservedMemorySize += ...
+    }
     mS3AcpiReservedMemoryBase = ...

Otherwise, AmdSevEsInitialize() could run out of permanent PEI RAM
during S3 resume.


... Side question: actually, do we support S3 with SEV enabled, at the
moment? Last week or so I tried to test it, and it didn't work. I don't
remember if we *intended* to support S3 in SEV guests at all. If we
never cared, then we should document that, plus I shouldn't make the
SEV-ES work needlessly difficult with S3 remarks... Brijesh, what's your
recollection?

If the intent has always been to ignore S3 in SEV guests, then we should
modify the S3Verification() function to catch QEMU configs where both
features are enabled, and force the user to disable at least one of
them. Otherwise, the user might suspend the OS to S3, and then lose data
when resume fails. In such cases, the user should be forced -- during
early boot -- to explicitly disable S3 on the QEMU cmdline, and to
re-launch the guest. And then the OS won't ever attempt S3.

Hm.... I've now found some internal correspondence at Red Hat, from Aug
2017. I wrote,

> With SEV enabled, the S3 boot script would have to manipulate page
> tables (which might require more memory pre-allocation), in order to
> continue using the currently pre-reserved memory areas for guest-host
> communication during S3 resume.
>
> This kind of page table manipulation is very difficult to do with the
> currently specified / standardized boot script opcodes.
> EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE *might* prove usable to call custom
> code during S3 resume, from the boot script, but the callee seems to
> need a custom assembly trampoline, and likely some magic for code
> relocation too (or the code must be position independent). One example
> seems to exist in the edk2 tree, but for OVMF this is uncharted
> territory.

And then the participants in that discussion seemed to set S3+SEV aside,
indefinitely.

... I've also found some S3 references in the following blurb:


http://mid.mail-archive.com/1499351394-1175-1-git-send-email-brijesh.singh@amd.com

We ended up not adding any SEV-related code to
"OvmfPkg/Library/QemuFwCfgS3Lib", so I think S3 must have remained out
of scope.

If we agree now that S3 is out of scope (for both SEV and SEV-ES), then:

- I think we should ignore all S3-related code paths in this series,

- we should drop patches already written for S3 (sorry about that!),

- we should extend S3Verification() like described above.

I apologize if my reviews are a bit incoherent; I can track only so many
things in parallel :(

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-09-19 19:52 ` [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-10-02 12:05   ` Laszlo Ersek
  2019-10-02 16:10     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 12:05 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> 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.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> 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 699bb8b11557..d6733447bdf2 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -37,6 +37,8 @@ AmdSevEsInitialize (
>    PHYSICAL_ADDRESS  GhcbBasePa;
>    UINTN             GhcbPageCount;
>    RETURN_STATUS     PcdStatus, DecryptStatus;
> +  IA32_DESCRIPTOR   Gdtr;
> +  VOID              *Gdt;
>  
>    if (!MemEncryptSevEsIsEnabled ()) {
>      return;
> @@ -72,6 +74,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 = AllocatePages (EFI_SIZE_TO_PAGES (Gdtr.Limit + 1));

EFI_SIZE_TO_PAGES() expects an UINTN argument. "Gdtr.Limit" is UINT16
("unsigned short"), which is promoted (as part of the integer
promotions) to INT32 ("int"). The addition is then performed in INT32.

(1) Please cast either Gdtr.Limit, or the sum, to UINTN explicitly.

> +  ASSERT (Gdt);

(2) Please write (Gdt != NULL).

> +
> +  CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
> +  Gdtr.Base = (UINTN) Gdt;
> +  AsmWriteGdtr (&Gdtr);
>  }
>  
>  /**
> 

With those changes:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
  2019-09-19 19:52 ` [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC Lendacky, Thomas
@ 2019-10-02 12:24   ` Laszlo Ersek
  2019-10-02 12:30     ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 12:24 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> The SEC phase of OVMF will need access to the MemEncryptSevLib library,
> so make the library available during SEC.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
> index 7c44d0952815..755d49cc22dc 100644
> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
> @@ -14,7 +14,7 @@ [Defines]
>    FILE_GUID                      = c1594631-3888-4be4-949f-9c630dbc842b
>    MODULE_TYPE                    = BASE
>    VERSION_STRING                 = 1.0
> -  LIBRARY_CLASS                  = MemEncryptSevLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
> +  LIBRARY_CLASS                  = MemEncryptSevLib|SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
>  
>  #
>  # The following information is for reference only and not required by the build
> 

This is not a good idea, at least in this form.

This library instance uses multiple variables with static storage
duration, such as:
- mSevStatus
- mSevEsStatus
- mSevStatusChecked
- mAddressEncMaskChecked [X64]
- mAddressEncMask [X64]
- mPageTablePool [X64]

SEC runs from pflash, so such variables are read-only (writes to them
won't trap, but will have no effect).

What are the functions from "OvmfPkg/Include/Library/MemEncryptSevLib.h"
that you need in the SEC phase?

Because, maybe we should split the library class in two classes. One lib
class would declare (for example):
- MemEncryptSevEsIsEnabled
- MemEncryptSevIsEnabled

The other lib class would declare:
- MemEncryptSevClearPageEncMask
- MemEncryptSevSetPageEncMask
- MemEncryptSevLocateInitialSmramSaveStateMapPages

The first lib class could have two instances, one for SEC (using no
global variables for caching / speeding up the checks), and another
instance for PEI and later (with the global variables used for caching
the detection results).

The second lib class would have only one instance (the current one), and
it would not be usable in the SEC phase. (The main issue is that, for
manipulating PTEs, MemEncryptSevSetPageEncMask and
MemEncryptSevClearPageEncMask sometimes need to split page tables, and
for that, they need to allocate pages dynamically. We can't do that in SEC.)

The [LibraryClasses] sections of some INF files that currently list
"MemEncryptSevLib" may have to be updated, corresponding to the split.

Again, all of this depends on the exact subset of APIs you need in SEC.
If it's just one API, e.g. MemEncryptSevEsIsEnabled(), needed in just
one place in SEC, then it might not necessarily be tragic to simply
open-code (duplicate) the CPUID logic in SEC.

Thanks,
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
  2019-10-02 12:24   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 12:30     ` Laszlo Ersek
  2019-10-02 16:16       ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 12:30 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 10/02/19 14:24, Laszlo Ersek wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> The SEC phase of OVMF will need access to the MemEncryptSevLib library,
>> so make the library available during SEC.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>> index 7c44d0952815..755d49cc22dc 100644
>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>> @@ -14,7 +14,7 @@ [Defines]
>>    FILE_GUID                      = c1594631-3888-4be4-949f-9c630dbc842b
>>    MODULE_TYPE                    = BASE
>>    VERSION_STRING                 = 1.0
>> -  LIBRARY_CLASS                  = MemEncryptSevLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
>> +  LIBRARY_CLASS                  = MemEncryptSevLib|SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
>>  
>>  #
>>  # The following information is for reference only and not required by the build
>>
> 
> This is not a good idea, at least in this form.
> 
> This library instance uses multiple variables with static storage
> duration, such as:
> - mSevStatus
> - mSevEsStatus
> - mSevStatusChecked
> - mAddressEncMaskChecked [X64]
> - mAddressEncMask [X64]
> - mPageTablePool [X64]
> 
> SEC runs from pflash, so such variables are read-only (writes to them
> won't trap, but will have no effect).
> 
> What are the functions from "OvmfPkg/Include/Library/MemEncryptSevLib.h"
> that you need in the SEC phase?
> 
> Because, maybe we should split the library class in two classes. One lib
> class would declare (for example):
> - MemEncryptSevEsIsEnabled
> - MemEncryptSevIsEnabled
> 
> The other lib class would declare:
> - MemEncryptSevClearPageEncMask
> - MemEncryptSevSetPageEncMask
> - MemEncryptSevLocateInitialSmramSaveStateMapPages
> 
> The first lib class could have two instances, one for SEC (using no
> global variables for caching / speeding up the checks), and another
> instance for PEI and later (with the global variables used for caching
> the detection results).
> 
> The second lib class would have only one instance (the current one), and
> it would not be usable in the SEC phase. (The main issue is that, for
> manipulating PTEs, MemEncryptSevSetPageEncMask and
> MemEncryptSevClearPageEncMask sometimes need to split page tables, and
> for that, they need to allocate pages dynamically. We can't do that in SEC.)
> 
> The [LibraryClasses] sections of some INF files that currently list
> "MemEncryptSevLib" may have to be updated, corresponding to the split.
> 
> Again, all of this depends on the exact subset of APIs you need in SEC.
> If it's just one API, e.g. MemEncryptSevEsIsEnabled(), needed in just
> one place in SEC, then it might not necessarily be tragic to simply
> open-code (duplicate) the CPUID logic in SEC.

Ah right, so if it's just for patch#18 ("OvmfPkg/Sec: Enable cache early
to speed up booting"), then I'd definitely opt for open-coding the two
AsmCpuid(), plus one AsmReadMsr32(), calls, in SecCoreStartupWithStack().

Later on, *if* we decide to call AsmEnableCache() in
SecCoreStartupWithStack() unconditionally -- and that's a big "if" --,
then it's going to be easier to remove those CPUID+MSR checks, than to
undo the MemEncryptSevLib class split as well.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-09-19 19:52 ` [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-10-02 12:31   ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 12: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 09/19/19 21:52, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> 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 when running as an SEV-ES guest.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/Sec/SecMain.inf |  1 +
>  OvmfPkg/Sec/SecMain.c   | 10 ++++++++++
>  2 files changed, 11 insertions(+)
> 
> diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
> index 7f53845f5436..fdf00e5d8be3 100644
> --- a/OvmfPkg/Sec/SecMain.inf
> +++ b/OvmfPkg/Sec/SecMain.inf
> @@ -51,6 +51,7 @@ [LibraryClasses]
>    ExtractGuidedSectionLib
>    LocalApicLib
>    CpuExceptionHandlerLib
> +  MemEncryptSevLib
>  
>  [Ppis]
>    gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index 7f1dfb2e57c1..20716d484ab0 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -25,6 +25,7 @@
>  #include <Library/ExtractGuidedSectionLib.h>
>  #include <Library/LocalApicLib.h>
>  #include <Library/CpuExceptionHandlerLib.h>
> +#include <Library/MemEncryptSevLib.h>
>  
>  #include <Ppi/TemporaryRamSupport.h>
>  
> @@ -755,6 +756,15 @@ SecCoreStartupWithStack (
>  
>    ProcessLibraryConstructorList (NULL, NULL);
>  
> +  //
> +  // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
> +  // caching in order to speed up the boot. Enable caching early for
> +  // an SEV-ES guest.
> +  //
> +  if (MemEncryptSevEsIsEnabled()) {
> +    AsmEnableCache ();
> +  }
> +
>    DEBUG ((EFI_D_INFO,
>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>      (UINT32)(UINTN)BootFv,
> 

Please see under patch#16; IMO, we should open-code the CPUID+RDMSR
sequence here.

Thanks,
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory
  2019-09-20 13:16 ` [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
@ 2019-10-02 14:38   ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 14:38 UTC (permalink / raw)
  To: devel, thomas.lendacky

On 09/20/19 15:16, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> After having transitioned from UEFI to the OS, the OS will need to boot
> the APs. For an SEV-ES guest, the APs will have been parked by UEFI using
> GHCB pages allocated by UEFI. The hypervisor will write to the GHCB
> SW_EXITINFO2 field of the GHCB when the AP is booted. As a result, the
> GHCB pages must be marked reserved so that the OS does not attempt to use
> them and experience memory corruption because of the hypervisor write.
> 
> Change the GHCB allocation from the default boot services memory to
> reserved memory.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/PlatformPei/AmdSev.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
> index d6733447bdf2..53eeb59702ae 100644
> --- a/OvmfPkg/PlatformPei/AmdSev.c
> +++ b/OvmfPkg/PlatformPei/AmdSev.c
> @@ -49,9 +49,11 @@ AmdSevEsInitialize (
>  
>    //
>    // Allocate GHCB pages.
> +  //   Since the pages must survive across the UEFI to OS transition
> +  //   make them reserved.
>    //
>    GhcbPageCount = mMaxCpuCount * 2;
> -  GhcbBase = AllocatePages (GhcbPageCount);
> +  GhcbBase = AllocateReservedPages (GhcbPageCount);
>    ASSERT (GhcbBase);
>  
>    GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> 

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-10-02 10:23   ` Laszlo Ersek
@ 2019-10-02 14:43     ` Lendacky, Thomas
  2019-10-02 15:55       ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 14:43 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 10/2/19 5:23 AM, Laszlo Ersek wrote:
> After the discussion elsewhere in this patch thread, which related to
> commit messages, and patch order in the series, I can make a few coding
> style comments on the patch. (No change to functionality.)
> 
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> Allocate memory for the GHCB pages during SEV initialization for use
>> during Pei and Dxe phases. The GHCB page(s) must be shared pages, so
>> clear the encryption mask from the current page table entries. Upon
>> successful allocation, set the GHCB PCDs (PcdGhcbBase and PcdGhcbSize).
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgIa32.dsc             |  2 ++
>>  OvmfPkg/OvmfPkgIa32X64.dsc          |  2 ++
>>  OvmfPkg/OvmfPkgX64.dsc              |  2 ++
>>  OvmfPkg/PlatformPei/PlatformPei.inf |  2 ++
>>  OvmfPkg/PlatformPei/AmdSev.c        | 36 ++++++++++++++++++++++++++++-
>>  5 files changed, 43 insertions(+), 1 deletion(-)
>>
>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>> index 0ce5c01722ef..4369cf6d55e5 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -560,6 +560,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index e7455e35a55d..a74f5028068e 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -572,6 +572,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index 0b8305cd10a2..fd714d386e75 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -571,6 +571,8 @@ [PcdsDynamicDefault]
>>  
>>    # Set SEV-ES defaults
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
>>  
>>  !if $(SMM_REQUIRE) == TRUE
>>    gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index a9e424a6012a..62abc99f4622 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -105,6 +105,8 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsActive
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
>>  
>>  [FixedPcd]
>>    gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> 
> (1) Once you move PcdSevEsActive near the other
> gEfiMdeModulePkgTokenSpaceGuid PCDs, per
> <http://mid.mail-archive.com/bd38da31-0985-2ffc-b60d-f867a0218ab2@redhat.com>,
> please keep these grouped with it, too.

Will do.

> 
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 7ae2f26a2ba7..30c0e4af7252 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -16,6 +16,9 @@
>>  #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>
> 
> (2) This #include list is currently sorted. Can you please keep it sorted?
> 
>>  
>>  #include "Platform.h"
>>  
>> @@ -30,7 +33,10 @@ AmdSevEsInitialize (
>>    VOID
>>    )
>>  {
>> -  RETURN_STATUS     PcdStatus;
>> +  VOID              *GhcbBase;
>> +  PHYSICAL_ADDRESS  GhcbBasePa;
>> +  UINTN             GhcbPageCount;
>> +  RETURN_STATUS     PcdStatus, DecryptStatus;
>>  
>>    if (!MemEncryptSevEsIsEnabled ()) {
>>      return;
>> @@ -38,6 +44,34 @@ AmdSevEsInitialize (
>>  
>>    PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
>>    ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> +  //
>> +  // Allocate GHCB pages.
>> +  //
>> +  GhcbPageCount = mMaxCpuCount;
>> +  GhcbBase = AllocatePages (GhcbPageCount);
> 
> Yes, AllocatePages() looks safe, per
> <http://mid.mail-archive.com/4029f533-9f2a-ba71-2ba6-348187dc7684@redhat.com>.
> 
>> +  ASSERT (GhcbBase);
> 
> (3) I don't really like using *only* an ASSERT for stopping, when we run
> out of resources in a place like this (i.e. where there's no way to
> recover, or to report the issue nicely). I'd suggest throwing in an
> explicit check and a CpuDeadLoop(), in addition to the ASSERT. Anyway,
> not really important, up to you.

Ok, let me think about that. If ASSERT is enabled, you'll get the ASSERT
message (since the SEC GHCB is in place and OVMF is running in 64-bit
mode). If ASSERT is not enabled, then the ZeroMem will segfault on a NULL
pointer, which will give a bit more info than the CpuDeadLoop() which
would look more like a hang.

> 
> (4) The expression in the ASSERT() should compare GhcbBase against NULL
> explicitly, however. The edk2 coding style permits the implicit "!= 0"
> comparison (in controlling expressions) for BOOLEANs only.

Will do.

> 
>> +
>> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> +  DecryptStatus = MemEncryptSevClearPageEncMask (
>> +    0,
>> +    GhcbBasePa,
>> +    GhcbPageCount,
>> +    TRUE
>> +    );
>> +  ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> +  SetMem (GhcbBase, GhcbPageCount * SIZE_4KB, 0);
> 
> (5) The following would be more idiomatic:
> 
>   ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));

Will do.

> 
> (like you write below already)
> 
>> +
>> +  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));
> 
> (6) This line is too long; please try to stick with <=80 chars per line.

Huh, don't know how I missed that one. I'll fix that.

> 
> (7) UINTN values (such as GhcbPageCount) should be converted to UINT64
> explicitly, and then formatted with %lu.

Ok, will do (and I'll check the rest of my patches for this).

> 
> (8) GhcbBase is a pointer-to-void; please either format it with %p, or
> use GhcbBasePa. (We can rely on the latter being UINT64.)
> 
>   DEBUG ((DEBUG_INFO,
>     "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%lx\n",
>     (UINT64)GhcbPageCount, GhcbBasePa));
> 
>> +
>> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, (UINT64)GhcbBasePa);
>>  }
>>  
>>  /**
>>
> 
> (9) If you like, you can drop the (UINT64) casts from all the
> "GhcbBasePa" references; all of edk2 uses PHYSICAL_ADDRESS and
> EFI_PHYSICAL_ADDRESS interchangeably, and the latter is UINT64 per spec.

Nice, that will clean it up a bit.

Thanks, Tom

> 
> With the above updated -- (3) and (9) are optional --
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing
  2019-09-19 19:53 ` [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing Lendacky, Thomas
@ 2019-10-02 14:54   ` Laszlo Ersek
  2019-10-02 17:33     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 14:54 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh

On 09/19/19 21:53, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>
> A hypervisor is not allowed to update an SEV-ES guests register state,
> so when booting an SEV-ES guest AP, the hypervisor is not allowed to
> set the RIP to the guest requested value. Instead an SEV-ES AP must be
> re-directed from within the guest to the actual requested staring location
> as specified in the INIT-SIPI-SIPI sequence.
>
> Provide reset vector code that contains support to jump to the desired
> RIP location after having been started. This is required for only the
> very first AP reset.

(1) In the commit message, can you mention the build mechanism by which
this file overrides the original in UefiCpuPkg?

Is it due to include path order?

>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 80 ++++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>
> diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
> new file mode 100644
> index 000000000000..1ac8b7ca7e85
> --- /dev/null
> +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
> @@ -0,0 +1,80 @@
> +;------------------------------------------------------------------------------
> +; @file
> +; First code executed by processor after resetting.
> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
> +;
> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
> +; SPDX-License-Identifier: BSD-2-Clause-Patent

(2) Thanks for the "derived from" hint -- but in that case, you should
probably keep the original copyright notice too.

> +;
> +;------------------------------------------------------------------------------
> +
> +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
> +;
> +; standardProcessorSevEsReset:    (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:
> +
>

It's worth looking at this patch as a diff against the original:

> --- UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm        2019-09-25 17:09:42.856850422 +0200
> +++ OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm        2019-10-02 16:40:55.906630335 +0200
> @@ -1,8 +1,9 @@
>  ;------------------------------------------------------------------------------
>  ; @file
>  ; First code executed by processor after resetting.
> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
>  ;
> -; Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
>  ; SPDX-License-Identifier: BSD-2-Clause-Patent
>  ;
>  ;------------------------------------------------------------------------------
> @@ -24,6 +25,20 @@
>      TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
>  %endif
>
> +;
> +; SEV-ES Processor Reset support
> +;
> +; standardProcessorSevEsReset:    (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
> @@ -55,9 +70,9 @@
>  ;
>  ; This is where the processor will begin execution
>  ;
> -    nop
> -    nop
> -    jmp     EarlyBspInitReal16
> +    cmp     dword [CS:0xFFD0], 0
> +    je      EarlyBspInitReal16
> +    jmp     far [CS:0xFFD0]
>
>  ALIGN   16
>

(3) Can't we / shouldn't we implement this change in the original,
actually? The new code doesn't seem to hurt if it's not activated, and
it doesn't complicate the code much.

(4) Can we use "standardProcessorSevEsReset" in place of the constant
0xFFD0 somehow?

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-09-19 19:53 ` [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
@ 2019-10-02 15:15   ` Laszlo Ersek
  2019-10-02 15:26     ` Laszlo Ersek
  2019-10-02 17:58     ` Lendacky, Thomas
  0 siblings, 2 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 15:15 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh, Philippe Mathieu-Daudé

Adding Phil.

I'm looking at this patch only because one thing caught my attention in
the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
re-directing":

On 09/19/19 21:53, Lendacky, Thomas wrote:
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> 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.

I don't understand how this can work: the guest-phys address 0xffffffd0
is backed by read-only pflash in most OVMF deployments.

In addition:

[...]

> @@ -1002,6 +1204,7 @@ WakeUpAP (
>        CpuMpData->InitFlag   != ApInitDone) {
>      ResetVectorRequired = TRUE;
>      AllocateResetVector (CpuMpData);
> +    AllocateSevEsAPMemory (CpuMpData);
>      FillExchangeInfoData (CpuMpData);
>      SaveLocalApicTimerSetting (CpuMpData);
>    }
> @@ -1038,6 +1241,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);
> +      }

Even if the address is backed by a single "unified" pflash, mapped r/w
-- which we can call a "non-standard OVMF deployment" nowadays --, a
normal store doesn't appear sufficient to me. The first write to pflash
will flip it to "programming mode", and the values stored are supposed
to be pflash commands (not just the raw data we intend to put in place).

See for example the QemuFlashWrite() function in
"OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c". (But, again, that
is used with the pflash chip that hosts the variable store, and is
therefore mapped r/w.)


Taking a step back... I don't think APs execute any code from pflash,
when MpInitLib boots them.

In OVMF, PcdCpuApLoopMode is ApInHltLoop (value 1), therefore
"CpuMpData->WakeUpByInitSipiSipi" should be TRUE, and
"ResetVectorRequired" too should be TRUE, at first AP boot.
Consequently, the reset vector seems to be allocated with
AllocateResetVector().

AllocateResetVector() has separate implementations for PEI and DXE, but
in both cases, it returns RAM. So I don't see where the AP accesses (or
executes) pflash.

Thanks,
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-02 15:15   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 15:26     ` Laszlo Ersek
  2019-10-02 18:07       ` Lendacky, Thomas
  2019-10-02 17:58     ` Lendacky, Thomas
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 15:26 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Singh, Brijesh, Philippe Mathieu-Daudé

On 10/02/19 17:15, Laszlo Ersek wrote:
> Adding Phil.
> 
> I'm looking at this patch only because one thing caught my attention in
> the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
> re-directing":
> 
> On 09/19/19 21:53, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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.
> 
> I don't understand how this can work: the guest-phys address 0xffffffd0
> is backed by read-only pflash in most OVMF deployments.
> 
> In addition:
> 
> [...]
> 
>> @@ -1002,6 +1204,7 @@ WakeUpAP (
>>        CpuMpData->InitFlag   != ApInitDone) {
>>      ResetVectorRequired = TRUE;
>>      AllocateResetVector (CpuMpData);
>> +    AllocateSevEsAPMemory (CpuMpData);
>>      FillExchangeInfoData (CpuMpData);
>>      SaveLocalApicTimerSetting (CpuMpData);
>>    }
>> @@ -1038,6 +1241,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);
>> +      }
> 
> Even if the address is backed by a single "unified" pflash, mapped r/w
> -- which we can call a "non-standard OVMF deployment" nowadays --, a
> normal store doesn't appear sufficient to me. The first write to pflash
> will flip it to "programming mode", and the values stored are supposed
> to be pflash commands (not just the raw data we intend to put in place).
> 
> See for example the QemuFlashWrite() function in
> "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c". (But, again, that
> is used with the pflash chip that hosts the variable store, and is
> therefore mapped r/w.)
> 
> 
> Taking a step back... I don't think APs execute any code from pflash,
> when MpInitLib boots them.
> 
> In OVMF, PcdCpuApLoopMode is ApInHltLoop (value 1), therefore
> "CpuMpData->WakeUpByInitSipiSipi" should be TRUE, and
> "ResetVectorRequired" too should be TRUE, at first AP boot.
> Consequently, the reset vector seems to be allocated with
> AllocateResetVector().
> 
> AllocateResetVector() has separate implementations for PEI and DXE, but
> in both cases, it returns RAM. So I don't see where the AP accesses (or
> executes) pflash.

... I believe I understand that this is precisely what cannot work under
SEV-ES -- because we cannot launch an AP at an address that's
dynamically chosen by the firmware (and passed to the hypervisor), like
with INIT-SIPI-SIPI.

And so firmware and hypervisor have to agree upon a *constant* AP reset
vector address, in advance.

We have two options:

- pick the reset vector address *constant* such that it falls into RAM, or

- let the AP reset vector reside in pflash, but then the code in pflash
has to look for a parameter block at a fixed address in RAM.

So in the end, both options require the same -- we need a RAM address
constant that is determined at firmware build time. Either for the reset
vector itself, or for the reset vector's parameter block.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-10-02 14:43     ` Lendacky, Thomas
@ 2019-10-02 15:55       ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-02 15:55 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 10/02/19 16:43, Lendacky, Thomas wrote:
> On 10/2/19 5:23 AM, Laszlo Ersek wrote:
>> On 09/19/19 21:52, Lendacky, Thomas wrote:

>>> @@ -38,6 +44,34 @@ AmdSevEsInitialize (
>>>  
>>>    PcdStatus = PcdSetBoolS (PcdSevEsActive, 1);
>>>    ASSERT_RETURN_ERROR (PcdStatus);
>>> +
>>> +  //
>>> +  // Allocate GHCB pages.
>>> +  //
>>> +  GhcbPageCount = mMaxCpuCount;
>>> +  GhcbBase = AllocatePages (GhcbPageCount);
>>
>> Yes, AllocatePages() looks safe, per
>> <http://mid.mail-archive.com/4029f533-9f2a-ba71-2ba6-348187dc7684@redhat.com>.
>>
>>> +  ASSERT (GhcbBase);
>>
>> (3) I don't really like using *only* an ASSERT for stopping, when we run
>> out of resources in a place like this (i.e. where there's no way to
>> recover, or to report the issue nicely). I'd suggest throwing in an
>> explicit check and a CpuDeadLoop(), in addition to the ASSERT. Anyway,
>> not really important, up to you.
> 
> Ok, let me think about that. If ASSERT is enabled, you'll get the ASSERT
> message (since the SEC GHCB is in place and OVMF is running in 64-bit
> mode). If ASSERT is not enabled, then the ZeroMem will segfault on a NULL
> pointer, which will give a bit more info than the CpuDeadLoop() which
> would look more like a hang.

I don't insist on "strengthening" the ASSERT(). For technical
correctness though: accessing page#0 has -- by default -- no ill effects
in the firmware. Page#0 is normal RAM, and mapped as such (by default).

MdeModulePkg offers null pointer detection; see
"PcdNullPointerDetectionPropertyMask". It's a debug feature (not a
production feature), to my understanding anyway. It's disabled by
default (per DEC file), and OVMF does not enable it.

See also commit 90f3922b018e ("OvmfPkg/QemuVideoDxe: Bypass NULL pointer
detection during VBE SHIM installing", 2017-10-11).

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-10-02 11:51   ` Laszlo Ersek
@ 2019-10-02 16:06     ` Lendacky, Thomas
  2019-10-03  9:06       ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 16:06 UTC (permalink / raw)
  To: Laszlo Ersek, devel@edk2.groups.io, Singh, Brijesh
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni

On 10/2/19 6:51 AM, Laszlo Ersek wrote:
> A few more comments:
> 
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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 (and
>> that is done), 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.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgX64.fdf                | 2 +-
>>  OvmfPkg/PlatformPei/AmdSev.c          | 2 +-
>>  OvmfPkg/ResetVector/ResetVector.nasmb | 2 +-
>>  3 files changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index a567131a0591..84716952052d 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -79,7 +79,7 @@ [FD.MEMFD]
>>  0x008000|0x001000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
>>
>> -0x009000|0x001000
>> +0x009000|0x002000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
>>
>>  0x010000|0x010000
>> diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
>> index 30c0e4af7252..699bb8b11557 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -48,7 +48,7 @@ AmdSevEsInitialize (
>>    //
>>    // Allocate GHCB pages.
>>    //
>> -  GhcbPageCount = mMaxCpuCount;
>> +  GhcbPageCount = mMaxCpuCount * 2;
>>    GhcbBase = AllocatePages (GhcbPageCount);
>>    ASSERT (GhcbBase);
>>
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 8909fc9313f4..d7c0ab3ada00 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -57,7 +57,7 @@
>>      %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
>>    %endif
>>
>> -  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x1000)
>> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)
>>      %error "This implementation inherently depends on PcdOvmfSecGhcbSize"
>>    %endif
>>
>>
> 
> (1) I think it makes sense to split this patch in two, one half for SEC,
> another for PlatformPei.

With the way I'm re-ordering the patches (building the exception handling
up first), the per-CPU allocation will just be part of the overall GHCB
allocation in each phase and be separate patches.

> 
> (2) The PlatformPei hunk makes me realize that
> "mS3AcpiReservedMemorySize" in PublishPeiMemory() is already
> proportional to "mMaxCpuCount".
> 
> The current coefficient is PcdCpuApStackSize (= 32KB). If we're adding
> 8KB (2 pages) per CPU, for SEV-ES, that's not negligible (1/4th
> increase).
> 
> Can you please extend both patch#8, and the PlatformPei hunk split out
> of patch#10 (= this patch), to increase "mS3AcpiReservedMemorySize" in
> PublishPeiMemory(), if MemEncryptSevEsIsEnabled()?
> 
>    if (mS3Supported) {
>      mS3AcpiReservedMemorySize = ...;
> +    if (MemEncryptSevEsIsEnabled ()) {
> +      mS3AcpiReservedMemorySize += ...
> +    }
>      mS3AcpiReservedMemoryBase = ...
> 
> Otherwise, AmdSevEsInitialize() could run out of permanent PEI RAM
> during S3 resume.

Ok, I'll do that if we decide that S3 is supported after discussing it
some more.

> 
> 
> ... Side question: actually, do we support S3 with SEV enabled, at the
> moment? Last week or so I tried to test it, and it didn't work. I don't
> remember if we *intended* to support S3 in SEV guests at all. If we
> never cared, then we should document that, plus I shouldn't make the
> SEV-ES work needlessly difficult with S3 remarks... Brijesh, what's your
> recollection?
> 
> If the intent has always been to ignore S3 in SEV guests, then we should
> modify the S3Verification() function to catch QEMU configs where both
> features are enabled, and force the user to disable at least one of
> them. Otherwise, the user might suspend the OS to S3, and then lose data
> when resume fails. In such cases, the user should be forced -- during
> early boot -- to explicitly disable S3 on the QEMU cmdline, and to
> re-launch the guest. And then the OS won't ever attempt S3.
> 
> Hm.... I've now found some internal correspondence at Red Hat, from Aug
> 2017. I wrote,
> 
>> With SEV enabled, the S3 boot script would have to manipulate page
>> tables (which might require more memory pre-allocation), in order to
>> continue using the currently pre-reserved memory areas for guest-host
>> communication during S3 resume.

I guess I need to understand more about this. Does the page table
manipulation occur in the guest or hypervisor? If in the guest, then that
is ok. But the page tables can't be successfully manipulated by the
hypervisor.

>>
>> This kind of page table manipulation is very difficult to do with the
>> currently specified / standardized boot script opcodes.
>> EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE *might* prove usable to call custom
>> code during S3 resume, from the boot script, but the callee seems to
>> need a custom assembly trampoline, and likely some magic for code
>> relocation too (or the code must be position independent). One example
>> seems to exist in the edk2 tree, but for OVMF this is uncharted
>> territory.
> 
> And then the participants in that discussion seemed to set S3+SEV aside,
> indefinitely.
> 
> ... I've also found some S3 references in the following blurb:
> 
> 
> http://mid.mail-archive.com/1499351394-1175-1-git-send-email-brijesh.singh@amd.com
> 
> We ended up not adding any SEV-related code to
> "OvmfPkg/Library/QemuFwCfgS3Lib", so I think S3 must have remained out
> of scope.

Brijesh commented in the referenced link that he was able to do
suspend/resume successfully. It's possible that some later changes caused
that to fail?

Maybe we need to understand how you did your S3 test vs. how Brijesh did
his.

> 
> If we agree now that S3 is out of scope (for both SEV and SEV-ES), then:
> 
> - I think we should ignore all S3-related code paths in this series,
> 
> - we should drop patches already written for S3 (sorry about that!),
> 
> - we should extend S3Verification() like described above.

It's probably worth doing this as the only S3-related patch in this series
until we understand the complete SEV-ES / S3 requirements. I'm a bit
hesitant to include base SEV in this until we discuss some more.

> 
> I apologize if my reviews are a bit incoherent; I can track only so many
> things in parallel :(

No worries, they're not!

Thanks,
Tom

> 
> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-10-02 12:05   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 16:10     ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 16:10 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 10/2/19 7:05 AM, Laszlo Ersek via Groups.Io wrote:
> On 09/19/19 21:52, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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.
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> 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 699bb8b11557..d6733447bdf2 100644
>> --- a/OvmfPkg/PlatformPei/AmdSev.c
>> +++ b/OvmfPkg/PlatformPei/AmdSev.c
>> @@ -37,6 +37,8 @@ AmdSevEsInitialize (
>>    PHYSICAL_ADDRESS  GhcbBasePa;
>>    UINTN             GhcbPageCount;
>>    RETURN_STATUS     PcdStatus, DecryptStatus;
>> +  IA32_DESCRIPTOR   Gdtr;
>> +  VOID              *Gdt;
>>  
>>    if (!MemEncryptSevEsIsEnabled ()) {
>>      return;
>> @@ -72,6 +74,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 = AllocatePages (EFI_SIZE_TO_PAGES (Gdtr.Limit + 1));
> 
> EFI_SIZE_TO_PAGES() expects an UINTN argument. "Gdtr.Limit" is UINT16
> ("unsigned short"), which is promoted (as part of the integer
> promotions) to INT32 ("int"). The addition is then performed in INT32.
> 
> (1) Please cast either Gdtr.Limit, or the sum, to UINTN explicitly.

Will do.

> 
>> +  ASSERT (Gdt);
> 
> (2) Please write (Gdt != NULL).

Yup.

Thanks,
Tom

> 
>> +
>> +  CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
>> +  Gdtr.Base = (UINTN) Gdt;
>> +  AsmWriteGdtr (&Gdtr);
>>  }
>>  
>>  /**
>>
> 
> With those changes:
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks
> Laszlo
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC
  2019-10-02 12:30     ` Laszlo Ersek
@ 2019-10-02 16:16       ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 16:16 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 10/2/19 7:30 AM, Laszlo Ersek via Groups.Io wrote:
> On 10/02/19 14:24, Laszlo Ersek wrote:
>> On 09/19/19 21:52, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> The SEC phase of OVMF will need access to the MemEncryptSevLib library,
>>> so make the library available during SEC.
>>>
>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>>> index 7c44d0952815..755d49cc22dc 100644
>>> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>>> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
>>> @@ -14,7 +14,7 @@ [Defines]
>>>    FILE_GUID                      = c1594631-3888-4be4-949f-9c630dbc842b
>>>    MODULE_TYPE                    = BASE
>>>    VERSION_STRING                 = 1.0
>>> -  LIBRARY_CLASS                  = MemEncryptSevLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
>>> +  LIBRARY_CLASS                  = MemEncryptSevLib|SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
>>>  
>>>  #
>>>  # The following information is for reference only and not required by the build
>>>
>>
>> This is not a good idea, at least in this form.
>>
>> This library instance uses multiple variables with static storage
>> duration, such as:
>> - mSevStatus
>> - mSevEsStatus
>> - mSevStatusChecked
>> - mAddressEncMaskChecked [X64]
>> - mAddressEncMask [X64]
>> - mPageTablePool [X64]
>>
>> SEC runs from pflash, so such variables are read-only (writes to them
>> won't trap, but will have no effect).
>>
>> What are the functions from "OvmfPkg/Include/Library/MemEncryptSevLib.h"
>> that you need in the SEC phase?
>>
>> Because, maybe we should split the library class in two classes. One lib
>> class would declare (for example):
>> - MemEncryptSevEsIsEnabled
>> - MemEncryptSevIsEnabled
>>
>> The other lib class would declare:
>> - MemEncryptSevClearPageEncMask
>> - MemEncryptSevSetPageEncMask
>> - MemEncryptSevLocateInitialSmramSaveStateMapPages
>>
>> The first lib class could have two instances, one for SEC (using no
>> global variables for caching / speeding up the checks), and another
>> instance for PEI and later (with the global variables used for caching
>> the detection results).
>>
>> The second lib class would have only one instance (the current one), and
>> it would not be usable in the SEC phase. (The main issue is that, for
>> manipulating PTEs, MemEncryptSevSetPageEncMask and
>> MemEncryptSevClearPageEncMask sometimes need to split page tables, and
>> for that, they need to allocate pages dynamically. We can't do that in SEC.)
>>
>> The [LibraryClasses] sections of some INF files that currently list
>> "MemEncryptSevLib" may have to be updated, corresponding to the split.
>>
>> Again, all of this depends on the exact subset of APIs you need in SEC.
>> If it's just one API, e.g. MemEncryptSevEsIsEnabled(), needed in just
>> one place in SEC, then it might not necessarily be tragic to simply
>> open-code (duplicate) the CPUID logic in SEC.
> 
> Ah right, so if it's just for patch#18 ("OvmfPkg/Sec: Enable cache early
> to speed up booting"), then I'd definitely opt for open-coding the two
> AsmCpuid(), plus one AsmReadMsr32(), calls, in SecCoreStartupWithStack().

Yup, it was just for the cache checking.  I'll do the open-coding.

Thanks,
Tom

> 
> Later on, *if* we decide to call AsmEnableCache() in
> SecCoreStartupWithStack() unconditionally -- and that's a big "if" --,
> then it's going to be easier to remove those CPUID+MSR checks, than to
> undo the MemEncryptSevLib class split as well.
> 
> Thanks
> Laszlo
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing
  2019-10-02 14:54   ` [edk2-devel] " Laszlo Ersek
@ 2019-10-02 17:33     ` Lendacky, Thomas
  2019-10-03  9:09       ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 17:33 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 10/2/19 9:54 AM, Laszlo Ersek wrote:
> On 09/19/19 21:53, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> A hypervisor is not allowed to update an SEV-ES guests register state,
>> so when booting an SEV-ES guest AP, the hypervisor is not allowed to
>> set the RIP to the guest requested value. Instead an SEV-ES AP must be
>> re-directed from within the guest to the actual requested staring location
>> as specified in the INIT-SIPI-SIPI sequence.
>>
>> Provide reset vector code that contains support to jump to the desired
>> RIP location after having been started. This is required for only the
>> very first AP reset.
> 
> (1) In the commit message, can you mention the build mechanism by which
> this file overrides the original in UefiCpuPkg?
> 
> Is it due to include path order?

Yes, this is due to the BuildOptions include path order. I'll update the
commit message.

> 
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 80 ++++++++++++++++++++
>>  1 file changed, 80 insertions(+)
>>  create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>>
>> diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>> new file mode 100644
>> index 000000000000..1ac8b7ca7e85
>> --- /dev/null
>> +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>> @@ -0,0 +1,80 @@
>> +;------------------------------------------------------------------------------
>> +; @file
>> +; First code executed by processor after resetting.
>> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
>> +;
>> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
>> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> (2) Thanks for the "derived from" hint -- but in that case, you should
> probably keep the original copyright notice too.

Ok, will do.

> 
>> +;
>> +;------------------------------------------------------------------------------
>> +
>> +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
>> +;
>> +; standardProcessorSevEsReset:    (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:
>> +
>>
> 
> It's worth looking at this patch as a diff against the original:
> 
>> --- UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm        2019-09-25 17:09:42.856850422 +0200
>> +++ OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm        2019-10-02 16:40:55.906630335 +0200
>> @@ -1,8 +1,9 @@
>>  ;------------------------------------------------------------------------------
>>  ; @file
>>  ; First code executed by processor after resetting.
>> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
>>  ;
>> -; Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
>> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
>>  ; SPDX-License-Identifier: BSD-2-Clause-Patent
>>  ;
>>  ;------------------------------------------------------------------------------
>> @@ -24,6 +25,20 @@
>>      TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
>>  %endif
>>
>> +;
>> +; SEV-ES Processor Reset support
>> +;
>> +; standardProcessorSevEsReset:    (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
>> @@ -55,9 +70,9 @@
>>  ;
>>  ; This is where the processor will begin execution
>>  ;
>> -    nop
>> -    nop
>> -    jmp     EarlyBspInitReal16
>> +    cmp     dword [CS:0xFFD0], 0
>> +    je      EarlyBspInitReal16
>> +    jmp     far [CS:0xFFD0]
>>
>>  ALIGN   16
>>
> 
> (3) Can't we / shouldn't we implement this change in the original,
> actually? The new code doesn't seem to hurt if it's not activated, and
> it doesn't complicate the code much.

If there are no objections, that can be done. It did concern me that there
are a couple of nop instructions before the jmp (which replaced a WBINVD)
and that there might be a reason for them being there. Based on that, I
just created the new file specific for OVMF.

> 
> (4) Can we use "standardProcessorSevEsReset" in place of the constant
> 0xFFD0 somehow?

I'll look into that. I know "CS:standardProcessorSevEsReset" won't work
and I tried a bunch of different things, but there may be another way.

Thanks,
Tom

> 
> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-02 15:15   ` [edk2-devel] " Laszlo Ersek
  2019-10-02 15:26     ` Laszlo Ersek
@ 2019-10-02 17:58     ` Lendacky, Thomas
  2019-10-03  9:21       ` Laszlo Ersek
  1 sibling, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 17:58 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, Philippe Mathieu-Daudé

On 10/2/19 10:15 AM, Laszlo Ersek via Groups.Io wrote:
> Adding Phil.
> 
> I'm looking at this patch only because one thing caught my attention in
> the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
> re-directing":
> 
> On 09/19/19 21:53, Lendacky, Thomas wrote:
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>
>> 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.
> 
> I don't understand how this can work: the guest-phys address 0xffffffd0
> is backed by read-only pflash in most OVMF deployments.
> 
> In addition:
> 
> [...]
> 
>> @@ -1002,6 +1204,7 @@ WakeUpAP (
>>        CpuMpData->InitFlag   != ApInitDone) {
>>      ResetVectorRequired = TRUE;
>>      AllocateResetVector (CpuMpData);
>> +    AllocateSevEsAPMemory (CpuMpData);
>>      FillExchangeInfoData (CpuMpData);
>>      SaveLocalApicTimerSetting (CpuMpData);
>>    }
>> @@ -1038,6 +1241,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);
>> +      }
> 
> Even if the address is backed by a single "unified" pflash, mapped r/w
> -- which we can call a "non-standard OVMF deployment" nowadays --, a
> normal store doesn't appear sufficient to me. The first write to pflash
> will flip it to "programming mode", and the values stored are supposed
> to be pflash commands (not just the raw data we intend to put in place).

There is a corresponding patch in Qemu that does not set the
KVM_MEM_READONLY flag for the ROM when starting an SEV-ES guest, thus
allowing the MP library to update the location with desired address.

> 
> See for example the QemuFlashWrite() function in
> "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c". (But, again, that
> is used with the pflash chip that hosts the variable store, and is
> therefore mapped r/w.)
> 
> 
> Taking a step back... I don't think APs execute any code from pflash,
> when MpInitLib boots them.

Correct, a non-SEV-ES guest will not execute this code because the
INIT-SIPI-SIPI sequence will direct the RIP to the desired location.

Thanks,
Tom

> 
> In OVMF, PcdCpuApLoopMode is ApInHltLoop (value 1), therefore
> "CpuMpData->WakeUpByInitSipiSipi" should be TRUE, and
> "ResetVectorRequired" too should be TRUE, at first AP boot.
> Consequently, the reset vector seems to be allocated with
> AllocateResetVector().
> 
> AllocateResetVector() has separate implementations for PEI and DXE, but
> in both cases, it returns RAM. So I don't see where the AP accesses (or
> executes) pflash.
> 
> Thanks,
> Laszlo
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-02 15:26     ` Laszlo Ersek
@ 2019-10-02 18:07       ` Lendacky, Thomas
  2019-10-03 10:12         ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-02 18:07 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, Philippe Mathieu-Daudé

On 10/2/19 10:26 AM, Laszlo Ersek wrote:
> On 10/02/19 17:15, Laszlo Ersek wrote:
>> Adding Phil.
>>
>> I'm looking at this patch only because one thing caught my attention in
>> the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
>> re-directing":
>>
>> On 09/19/19 21:53, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> 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.
>>
>> I don't understand how this can work: the guest-phys address 0xffffffd0
>> is backed by read-only pflash in most OVMF deployments.
>>
>> In addition:
>>
>> [...]
>>
>>> @@ -1002,6 +1204,7 @@ WakeUpAP (
>>>        CpuMpData->InitFlag   != ApInitDone) {
>>>      ResetVectorRequired = TRUE;
>>>      AllocateResetVector (CpuMpData);
>>> +    AllocateSevEsAPMemory (CpuMpData);
>>>      FillExchangeInfoData (CpuMpData);
>>>      SaveLocalApicTimerSetting (CpuMpData);
>>>    }
>>> @@ -1038,6 +1241,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);
>>> +      }
>>
>> Even if the address is backed by a single "unified" pflash, mapped r/w
>> -- which we can call a "non-standard OVMF deployment" nowadays --, a
>> normal store doesn't appear sufficient to me. The first write to pflash
>> will flip it to "programming mode", and the values stored are supposed
>> to be pflash commands (not just the raw data we intend to put in place).
>>
>> See for example the QemuFlashWrite() function in
>> "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c". (But, again, that
>> is used with the pflash chip that hosts the variable store, and is
>> therefore mapped r/w.)
>>
>>
>> Taking a step back... I don't think APs execute any code from pflash,
>> when MpInitLib boots them.
>>
>> In OVMF, PcdCpuApLoopMode is ApInHltLoop (value 1), therefore
>> "CpuMpData->WakeUpByInitSipiSipi" should be TRUE, and
>> "ResetVectorRequired" too should be TRUE, at first AP boot.
>> Consequently, the reset vector seems to be allocated with
>> AllocateResetVector().
>>
>> AllocateResetVector() has separate implementations for PEI and DXE, but
>> in both cases, it returns RAM. So I don't see where the AP accesses (or
>> executes) pflash.
> 
> ... I believe I understand that this is precisely what cannot work under
> SEV-ES -- because we cannot launch an AP at an address that's
> dynamically chosen by the firmware (and passed to the hypervisor), like
> with INIT-SIPI-SIPI.

Correct.

> 
> And so firmware and hypervisor have to agree upon a *constant* AP reset
> vector address, in advance.
> 
> We have two options:
> 
> - pick the reset vector address *constant* such that it falls into RAM, or
> 
> - let the AP reset vector reside in pflash, but then the code in pflash
> has to look for a parameter block at a fixed address in RAM.
> 
> So in the end, both options require the same -- we need a RAM address
> constant that is determined at firmware build time. Either for the reset
> vector itself, or for the reset vector's parameter block.

As long as the hypervisor has a way to determine a build time address,
that would be the preferred method. I couldn't come up with a way (or at
least don't know of a way) to allow the hypervisor to discover that build
time address. Hopefully someone else does and we can eliminate the need
to map the ROM read/write and just program the vCPUs initial registers to
the build time value.

I think the address should be for the AP reset vector itself, otherwise
you would have to guarantee that the reset vector parameter block is zero
for the initial BSP boot.

Thanks,
Tom

> 
> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage
  2019-10-02 16:06     ` Lendacky, Thomas
@ 2019-10-03  9:06       ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-03  9:06 UTC (permalink / raw)
  To: Lendacky, Thomas, devel@edk2.groups.io, Singh, Brijesh
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni

On 10/02/19 18:06, Lendacky, Thomas wrote:
> On 10/2/19 6:51 AM, Laszlo Ersek wrote:

>> ... Side question: actually, do we support S3 with SEV enabled, at the
>> moment? Last week or so I tried to test it, and it didn't work. I don't
>> remember if we *intended* to support S3 in SEV guests at all. If we
>> never cared, then we should document that, plus I shouldn't make the
>> SEV-ES work needlessly difficult with S3 remarks... Brijesh, what's your
>> recollection?
>>
>> If the intent has always been to ignore S3 in SEV guests, then we should
>> modify the S3Verification() function to catch QEMU configs where both
>> features are enabled, and force the user to disable at least one of
>> them. Otherwise, the user might suspend the OS to S3, and then lose data
>> when resume fails. In such cases, the user should be forced -- during
>> early boot -- to explicitly disable S3 on the QEMU cmdline, and to
>> re-launch the guest. And then the OS won't ever attempt S3.
>>
>> Hm.... I've now found some internal correspondence at Red Hat, from Aug
>> 2017. I wrote,
>>
>>> With SEV enabled, the S3 boot script would have to manipulate page
>>> tables (which might require more memory pre-allocation), in order to
>>> continue using the currently pre-reserved memory areas for guest-host
>>> communication during S3 resume.
> 
> I guess I need to understand more about this. Does the page table
> manipulation occur in the guest or hypervisor? If in the guest, then that
> is ok. But the page tables can't be successfully manipulated by the
> hypervisor.

It's all on the guest side. That's not the issue, the issue is (again)
complexity, and possibly also the limited expressiveness of the S3 boot
script "language" (the set of opcodes).

Roughly, this is the story: during normal boot, DXE drivers locate the
S3 Save State protocol, and call it to append a number of opcodes to the
S3 boot script. These opcodes allow platform device drivers to "stash"
various chipset programming actions for S3 resume time.

At a certain point in BDS (when the DXE SMM Ready To Lock protocol is
installed by Platform BDS), the boot script is saved into secure storage
(a "lock box" in SMRAM). Furthermore, BootScriptExecutorDxe saves itself
(the executable) into another lock box.

At S3 resume time, at the end of the PEI phase, S3Resume2Pei restores
BootScriptExecutorDxe from SMRAM, restores the boot script, and invokes
BootScriptExecutorDxe to execute the boot script; thereby re-programming
various chipset registers (as queued by platform DXE drivers during
normal boot). Finally control is transferred to the OS waking vector
(per ACPI FACS).

A number of platform drivers in OVMF queue boot script opcodes such that
those opcodes implement fw_cfg actions (fw_cfg DMA transfers) during S3.
Queueing these opcodes is very messy, therefore OVMF has a helper
library for that, QemuFwCfgS3Lib.

For the fw_cfg DMA transfers, the underlying pages need to be decrypted
& re-encrypted, as always. During normal boot, QemuFwCfgLib handles this:

- In the SEC and PEI phases, QemuFwCfgLib uses the IO port access
method, which is slower, and does not support fw_cfg writes. But for
SEC/PEI, that's enough.

- In DXE, QemuFwCfgLib uses the DMA access method, which is faster,
supports fw_cfg writes. It is SEV-aware, and uses the IOMMU protocol for
decrypting / encrypting the relevant pages.

The S3 boot script opcodes saved by QemuFwCfgS3Lib must use fw_cfg DMA
(because they need fw_cfg writes too, which are only supported by the
DMA method), and so they'd need extra page table actions in SEV guests.
But those page table actions appear difficult to express through S3 boot
script opcodes.

Anyway, this is just some background info; I'm certainly not suggesting
that we spend *any* resources on enabling S3 for SEV. SEV (not SEV-ES)
has been available in OVMF for a good while now, and we've seen no
reports related to S3. For another data point, S3 has been en-bloc
unsupported in RHEL downstream, regardless of SEV (it is disabled in
downstream QEMU by default, and if you force-enable it, that will
"taint" the domain). Mainly due to S3 depending very much on guest
driver cooperation (primarily video drivers), and that has been brittle,
in our experience.

So in the end I think we should update S3Verification() to catch S3+SEV
configs.

> 
>>>
>>> This kind of page table manipulation is very difficult to do with the
>>> currently specified / standardized boot script opcodes.
>>> EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE *might* prove usable to call custom
>>> code during S3 resume, from the boot script, but the callee seems to
>>> need a custom assembly trampoline, and likely some magic for code
>>> relocation too (or the code must be position independent). One example
>>> seems to exist in the edk2 tree, but for OVMF this is uncharted
>>> territory.
>>
>> And then the participants in that discussion seemed to set S3+SEV aside,
>> indefinitely.
>>
>> ... I've also found some S3 references in the following blurb:
>>
>>
>> http://mid.mail-archive.com/1499351394-1175-1-git-send-email-brijesh.singh@amd.com
>>
>> We ended up not adding any SEV-related code to
>> "OvmfPkg/Library/QemuFwCfgS3Lib", so I think S3 must have remained out
>> of scope.
> 
> Brijesh commented in the referenced link that he was able to do
> suspend/resume successfully. It's possible that some later changes caused
> that to fail?

It's possible that the basic S3 resume machinery, described above,
works, as long as you don't try to set up fw_cfg DMA through boot script
opcodes. However, those fw_cfg actions are important; for example,
"broadcast SMI" is configured through them.

> Maybe we need to understand how you did your S3 test vs. how Brijesh did
> his.
> 
>>
>> If we agree now that S3 is out of scope (for both SEV and SEV-ES), then:
>>
>> - I think we should ignore all S3-related code paths in this series,
>>
>> - we should drop patches already written for S3 (sorry about that!),
>>
>> - we should extend S3Verification() like described above.
> 
> It's probably worth doing this as the only S3-related patch in this series
> until we understand the complete SEV-ES / S3 requirements.

I agree.

> I'm a bit
> hesitant to include base SEV in this until we discuss some more.

If I understand correctly, you suggest to check SEV-ES enablement in
S3Verification(), but not SEV enablement. Is that right?

I would disagree about that. Broadcast SMI negotiation through fw_cfg is
important. It has been enabled since QEMU 2.9. I strongly recommend
using OVMF only like that, when built with -D SMM_REQUIRE.

If OVMF is built without -D SMM_REQUIRE, then the most important fw_cfg
DMA transfer is out of the picture (see above), and I'm slightly
inclined to agree with you. However, at least one other use case
remains, for fw_cfg DMA, at S3 resume.

Namely, the ACPI linker/loader script has a command type called
QEMU_LOADER_WRITE_POINTER. (See the documentation in
"AcpiPlatformDxe/QemuLoader.h".) Minimally the "vmgenid" platform device
of QEMU depends on the firmware executing this ACPI linker/loader
command, and the command has to be re-run at S3 resume too.

OvmfPkg/AcpiPlatformDxe runs these commands first at normal boot, like
all the other ACPI linker/loader commands. But, specifically for
QEMU_LOADER_WRITE_POINTER, the driver creates a "condensed"
representation too, which is then replayed at S3 resume time, through
boot script opcodes that use fw_cfg DMA.

>> I apologize if my reviews are a bit incoherent; I can track only so many
>> things in parallel :(
> 
> No worries, they're not!

Thank you :)
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing
  2019-10-02 17:33     ` Lendacky, Thomas
@ 2019-10-03  9:09       ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-03  9:09 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 10/02/19 19:33, Lendacky, Thomas wrote:
> On 10/2/19 9:54 AM, Laszlo Ersek wrote:
>> On 09/19/19 21:53, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> A hypervisor is not allowed to update an SEV-ES guests register state,
>>> so when booting an SEV-ES guest AP, the hypervisor is not allowed to
>>> set the RIP to the guest requested value. Instead an SEV-ES AP must be
>>> re-directed from within the guest to the actual requested staring location
>>> as specified in the INIT-SIPI-SIPI sequence.
>>>
>>> Provide reset vector code that contains support to jump to the desired
>>> RIP location after having been started. This is required for only the
>>> very first AP reset.
>>
>> (1) In the commit message, can you mention the build mechanism by which
>> this file overrides the original in UefiCpuPkg?
>>
>> Is it due to include path order?
> 
> Yes, this is due to the BuildOptions include path order. I'll update the
> commit message.
> 
>>
>>>
>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 80 ++++++++++++++++++++
>>>  1 file changed, 80 insertions(+)
>>>  create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>>>
>>> diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>>> new file mode 100644
>>> index 000000000000..1ac8b7ca7e85
>>> --- /dev/null
>>> +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>>> @@ -0,0 +1,80 @@
>>> +;------------------------------------------------------------------------------
>>> +; @file
>>> +; First code executed by processor after resetting.
>>> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
>>> +;
>>> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
>>> +; SPDX-License-Identifier: BSD-2-Clause-Patent
>>
>> (2) Thanks for the "derived from" hint -- but in that case, you should
>> probably keep the original copyright notice too.
> 
> Ok, will do.
> 
>>
>>> +;
>>> +;------------------------------------------------------------------------------
>>> +
>>> +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
>>> +;
>>> +; standardProcessorSevEsReset:    (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:
>>> +
>>>
>>
>> It's worth looking at this patch as a diff against the original:
>>
>>> --- UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm        2019-09-25 17:09:42.856850422 +0200
>>> +++ OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm        2019-10-02 16:40:55.906630335 +0200
>>> @@ -1,8 +1,9 @@
>>>  ;------------------------------------------------------------------------------
>>>  ; @file
>>>  ; First code executed by processor after resetting.
>>> +; Derived from UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm
>>>  ;
>>> -; Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
>>> +; Copyright (c) 2019, AMD Inc. All rights reserved.<BR>
>>>  ; SPDX-License-Identifier: BSD-2-Clause-Patent
>>>  ;
>>>  ;------------------------------------------------------------------------------
>>> @@ -24,6 +25,20 @@
>>>      TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
>>>  %endif
>>>
>>> +;
>>> +; SEV-ES Processor Reset support
>>> +;
>>> +; standardProcessorSevEsReset:    (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
>>> @@ -55,9 +70,9 @@
>>>  ;
>>>  ; This is where the processor will begin execution
>>>  ;
>>> -    nop
>>> -    nop
>>> -    jmp     EarlyBspInitReal16
>>> +    cmp     dword [CS:0xFFD0], 0
>>> +    je      EarlyBspInitReal16
>>> +    jmp     far [CS:0xFFD0]
>>>
>>>  ALIGN   16
>>>
>>
>> (3) Can't we / shouldn't we implement this change in the original,
>> actually? The new code doesn't seem to hurt if it's not activated, and
>> it doesn't complicate the code much.
> 
> If there are no objections, that can be done. It did concern me that there
> are a couple of nop instructions before the jmp (which replaced a WBINVD)
> and that there might be a reason for them being there. Based on that, I
> just created the new file specific for OVMF.
> 
>>
>> (4) Can we use "standardProcessorSevEsReset" in place of the constant
>> 0xFFD0 somehow?
> 
> I'll look into that. I know "CS:standardProcessorSevEsReset" won't work
> and I tried a bunch of different things, but there may be another way.

It would be nice to use a %define then, I think. Macro names are easier
to grep for than magic constants.

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-02 17:58     ` Lendacky, Thomas
@ 2019-10-03  9:21       ` Laszlo Ersek
  0 siblings, 0 replies; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-03  9:21 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, Philippe Mathieu-Daudé

On 10/02/19 19:58, Lendacky, Thomas wrote:
> On 10/2/19 10:15 AM, Laszlo Ersek via Groups.Io wrote:
>> Adding Phil.
>>
>> I'm looking at this patch only because one thing caught my attention in
>> the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
>> re-directing":
>>
>> On 09/19/19 21:53, Lendacky, Thomas wrote:
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>
>>> 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.
>>
>> I don't understand how this can work: the guest-phys address 0xffffffd0
>> is backed by read-only pflash in most OVMF deployments.
>>
>> In addition:
>>
>> [...]
>>
>>> @@ -1002,6 +1204,7 @@ WakeUpAP (
>>>        CpuMpData->InitFlag   != ApInitDone) {
>>>      ResetVectorRequired = TRUE;
>>>      AllocateResetVector (CpuMpData);
>>> +    AllocateSevEsAPMemory (CpuMpData);
>>>      FillExchangeInfoData (CpuMpData);
>>>      SaveLocalApicTimerSetting (CpuMpData);
>>>    }
>>> @@ -1038,6 +1241,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);
>>> +      }
>>
>> Even if the address is backed by a single "unified" pflash, mapped r/w
>> -- which we can call a "non-standard OVMF deployment" nowadays --, a
>> normal store doesn't appear sufficient to me. The first write to pflash
>> will flip it to "programming mode", and the values stored are supposed
>> to be pflash commands (not just the raw data we intend to put in place).
> 
> There is a corresponding patch in Qemu that does not set the
> KVM_MEM_READONLY flag for the ROM when starting an SEV-ES guest, thus
> allowing the MP library to update the location with desired address.

Isn't that a price too high to pay? It seems to allow the memory mapped
contents of the pflash chip to diverge from the host-side file, even if
the QEMU command line specifies that the pflash chip is to be mapped r/o.

With regard to SMM, I think this could even be considered a security
problem -- if the pflash region is not marked as readonly, then the
guest OS could write to it as well (with direct hardware access, like
the code seen above). The write would not trap to QEMU, and QEMU
couldn't prevent the write.

The OS could use this to inject code into the pflash region (e.g., SEC).
Although the host-side pflash file would not be modified, if the OS
performed a warm reboot (or S3 cycle) afterwards, the code it injected
into the flash region would be executed with firmware privileges.

AMD Publication #56421 states that SMM is currently out of scope for
SEV-ES, so I don't think there's a problem right now; I'm just generally
concerned that here we're enabling something I've always considered a
big no-no for SMM builds.

I still have to read your next response though (to my suggestion to use
a fixed RAM address, I believe).

Thanks!
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-02 18:07       ` Lendacky, Thomas
@ 2019-10-03 10:12         ` Laszlo Ersek
  2019-10-03 10:32           ` Laszlo Ersek
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-03 10: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, Philippe Mathieu-Daudé

On 10/02/19 20:07, Lendacky, Thomas wrote:
> On 10/2/19 10:26 AM, Laszlo Ersek wrote:
>> On 10/02/19 17:15, Laszlo Ersek wrote:
>>> Adding Phil.
>>>
>>> I'm looking at this patch only because one thing caught my attention in
>>> the previous one, "OvmfPkg: Add support for SEV-ES AP reset vector
>>> re-directing":
>>>
>>> On 09/19/19 21:53, Lendacky, Thomas wrote:
>>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>>>
>>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
>>>>
>>>> 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.
>>>
>>> I don't understand how this can work: the guest-phys address 0xffffffd0
>>> is backed by read-only pflash in most OVMF deployments.
>>>
>>> In addition:
>>>
>>> [...]
>>>
>>>> @@ -1002,6 +1204,7 @@ WakeUpAP (
>>>>        CpuMpData->InitFlag   != ApInitDone) {
>>>>      ResetVectorRequired = TRUE;
>>>>      AllocateResetVector (CpuMpData);
>>>> +    AllocateSevEsAPMemory (CpuMpData);
>>>>      FillExchangeInfoData (CpuMpData);
>>>>      SaveLocalApicTimerSetting (CpuMpData);
>>>>    }
>>>> @@ -1038,6 +1241,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);
>>>> +      }
>>>
>>> Even if the address is backed by a single "unified" pflash, mapped r/w
>>> -- which we can call a "non-standard OVMF deployment" nowadays --, a
>>> normal store doesn't appear sufficient to me. The first write to pflash
>>> will flip it to "programming mode", and the values stored are supposed
>>> to be pflash commands (not just the raw data we intend to put in place).
>>>
>>> See for example the QemuFlashWrite() function in
>>> "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c". (But, again, that
>>> is used with the pflash chip that hosts the variable store, and is
>>> therefore mapped r/w.)
>>>
>>>
>>> Taking a step back... I don't think APs execute any code from pflash,
>>> when MpInitLib boots them.
>>>
>>> In OVMF, PcdCpuApLoopMode is ApInHltLoop (value 1), therefore
>>> "CpuMpData->WakeUpByInitSipiSipi" should be TRUE, and
>>> "ResetVectorRequired" too should be TRUE, at first AP boot.
>>> Consequently, the reset vector seems to be allocated with
>>> AllocateResetVector().
>>>
>>> AllocateResetVector() has separate implementations for PEI and DXE, but
>>> in both cases, it returns RAM. So I don't see where the AP accesses (or
>>> executes) pflash.
>>
>> ... I believe I understand that this is precisely what cannot work under
>> SEV-ES -- because we cannot launch an AP at an address that's
>> dynamically chosen by the firmware (and passed to the hypervisor), like
>> with INIT-SIPI-SIPI.
> 
> Correct.
> 
>>
>> And so firmware and hypervisor have to agree upon a *constant* AP reset
>> vector address, in advance.
>>
>> We have two options:
>>
>> - pick the reset vector address *constant* such that it falls into RAM, or
>>
>> - let the AP reset vector reside in pflash, but then the code in pflash
>> has to look for a parameter block at a fixed address in RAM.
>>
>> So in the end, both options require the same -- we need a RAM address
>> constant that is determined at firmware build time. Either for the reset
>> vector itself, or for the reset vector's parameter block.
> 
> As long as the hypervisor has a way to determine a build time address,
> that would be the preferred method. I couldn't come up with a way (or at
> least don't know of a way) to allow the hypervisor to discover that build
> time address. Hopefully someone else does and we can eliminate the need
> to map the ROM read/write and just program the vCPUs initial registers to
> the build time value.
> 
> I think the address should be for the AP reset vector itself, otherwise
> you would have to guarantee that the reset vector parameter block is zero
> for the initial BSP boot.

Rough idea:

(1) Introduce a new fixed PCD (UINT32) pointing into RAM -- the AP reset
vector address. You could carve it out from another unused part of
FD.MEMFD, and set the PCD in the FDF files.

(2) In PlatformPei, reserve the area.

(3) In "ResetVectorVtf0.asm", we should introduce a packed structure as
follows, so that it end at label "applicationProcessorEntryPoint":

  UINT32   ApEntryPoint;
  EFI_GUID SevEsFooterGuid;
  UINT16   Size;

I think the assembly source code could populate this structure with DD /
DB / DW pseudo-instructions.

- The "ApEntryPoint" field would be filled from FixedPcdGet32.

- The SevEsFooterGuid field would be open-coded with DB. We'd pick a new
GUID with uuidgen for this.

- The "Size" field would cover the entire structure. I think we should
be able to auto-calculate it for a DW pseudo-instruction, placing a
label at the top of the structure, and then using ($ - ThatLabel) or
similar.

(4) The following information would be fixed (by convention) and known
to QEMU:
- the address of the SevEsFooterGuid field (offset backwards from the
end of flash / 4GB)
- the value of SevEsFooterGuid.

(5) Whenever QEMU finds the GUID, it can check the Size field. Given the
Size field, QEMU can check fields *prepended* to the footer structure.
Incompatible changes to the structure (i.e. any change other than
prepending new fields) require a new GUID to be generated for
SevEsFooterGuid.

(6) Thus QEMU could read ApEntryPoint out of the pflash image.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-03 10:12         ` Laszlo Ersek
@ 2019-10-03 10:32           ` Laszlo Ersek
  2019-10-03 15:12             ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-03 10:32 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, Philippe Mathieu-Daudé

On 10/03/19 12:12, Laszlo Ersek wrote:

>   UINT32   ApEntryPoint;
>   EFI_GUID SevEsFooterGuid;
>   UINT16   Size;

It's probably better to reverse the order of "Size" and
"SevEsFooterGuid", like this:

  UINT32   ApEntryPoint;
  UINT16   Size;
  EFI_GUID SevEsFooterGuid;

because then even the "Size" field can be changed (or resized), as a
function of the footer GUID.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-03 10:32           ` Laszlo Ersek
@ 2019-10-03 15:12             ` Lendacky, Thomas
  2019-10-10 23:17               ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-03 15:12 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, Philippe Mathieu-Daudé



On 10/3/19 5:32 AM, Laszlo Ersek wrote:
> On 10/03/19 12:12, Laszlo Ersek wrote:
> 
>>   UINT32   ApEntryPoint;
>>   EFI_GUID SevEsFooterGuid;
>>   UINT16   Size;
> 
> It's probably better to reverse the order of "Size" and
> "SevEsFooterGuid", like this:
> 
>   UINT32   ApEntryPoint;
>   UINT16   Size;
>   EFI_GUID SevEsFooterGuid;
> 
> because then even the "Size" field can be changed (or resized), as a
> function of the footer GUID.

Cool, I'll look into doing this and see how it works out.

Thanks!
Tom

> 
> Thanks
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-03 15:12             ` Lendacky, Thomas
@ 2019-10-10 23:17               ` Lendacky, Thomas
  2019-10-10 23:56                 ` Andrew Fish
  2019-10-11  8:56                 ` Laszlo Ersek
  0 siblings, 2 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-10-10 23:17 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, Philippe Mathieu-Daudé

On 10/3/19 10:12 AM, Tom Lendacky wrote:
> 
> 
> On 10/3/19 5:32 AM, Laszlo Ersek wrote:
>> On 10/03/19 12:12, Laszlo Ersek wrote:
>>
>>>   UINT32   ApEntryPoint;
>>>   EFI_GUID SevEsFooterGuid;
>>>   UINT16   Size;
>>
>> It's probably better to reverse the order of "Size" and
>> "SevEsFooterGuid", like this:
>>
>>   UINT32   ApEntryPoint;
>>   UINT16   Size;
>>   EFI_GUID SevEsFooterGuid;
>>
>> because then even the "Size" field can be changed (or resized), as a
>> function of the footer GUID.
> 
> Cool, I'll look into doing this and see how it works out.

Just an update on this idea. This has worked out well, but has a couple of
caveats. Removing the Qemu change to make the flash mapped read-only in
the nested page tables, caused the following:

1. QemuFlashDetected() will attempt to detect how the flash memory device
   behaves. Because it is marked as read-only by the hypervisor, writing
   to the area results in a #NPF for the write-fault. With SEV-ES,
   emulation of the instruction can't be performed (can't read guest
   memory and not provided the faulting instruction bytes), so the vCPU is
   just restarted. This results in an infinite #NPF occurring.

   The solution here was to check for SEV-ES being enabled and just return
   false from QemuFlashDetected(). Any downfalls to doing that?

2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
   XCODE5 tool chain") causes a similar situation to #1. It attempts to do
   some address fixups and write to the flash device.

   Reverting that commit fixes the issue. I don't think that will be an
   acceptable solution, though, so need to think about what to do here.

After those two changes, the above method works well.

Thanks,
Tom

> 
> Thanks!
> Tom
> 
>>
>> Thanks
>> Laszlo
>>

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-10 23:17               ` Lendacky, Thomas
@ 2019-10-10 23:56                 ` Andrew Fish
  2019-10-11  8:56                 ` Laszlo Ersek
  1 sibling, 0 replies; 106+ messages in thread
From: Andrew Fish @ 2019-10-10 23:56 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Laszlo Ersek, Jordan Justen, Ard Biesheuvel, Mike Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh,
	Philippe Mathieu-Daudé



> On Oct 10, 2019, at 4:17 PM, Lendacky, Thomas <thomas.lendacky@amd.com> wrote:
> 
> On 10/3/19 10:12 AM, Tom Lendacky wrote:
>> 
>> 
>> On 10/3/19 5:32 AM, Laszlo Ersek wrote:
>>> On 10/03/19 12:12, Laszlo Ersek wrote:
>>> 
>>>>  UINT32   ApEntryPoint;
>>>>  EFI_GUID SevEsFooterGuid;
>>>>  UINT16   Size;
>>> 
>>> It's probably better to reverse the order of "Size" and
>>> "SevEsFooterGuid", like this:
>>> 
>>>  UINT32   ApEntryPoint;
>>>  UINT16   Size;
>>>  EFI_GUID SevEsFooterGuid;
>>> 
>>> because then even the "Size" field can be changed (or resized), as a
>>> function of the footer GUID.
>> 
>> Cool, I'll look into doing this and see how it works out.
> 
> Just an update on this idea. This has worked out well, but has a couple of
> caveats. Removing the Qemu change to make the flash mapped read-only in
> the nested page tables, caused the following:
> 
> 1. QemuFlashDetected() will attempt to detect how the flash memory device
>   behaves. Because it is marked as read-only by the hypervisor, writing
>   to the area results in a #NPF for the write-fault. With SEV-ES,
>   emulation of the instruction can't be performed (can't read guest
>   memory and not provided the faulting instruction bytes), so the vCPU is
>   just restarted. This results in an infinite #NPF occurring.
> 
>   The solution here was to check for SEV-ES being enabled and just return
>   false from QemuFlashDetected(). Any downfalls to doing that?
> 
> 2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
>   XCODE5 tool chain") causes a similar situation to #1. It attempts to do
>   some address fixups and write to the flash device.
> 
>   Reverting that commit fixes the issue. I don't think that will be an
>   acceptable solution, though, so need to think about what to do here.
> 

Did you fill a bugzilla for 2)?

Thanks,

Andrew Fish

> After those two changes, the above method works well.
> 
> Thanks,
> Tom
> 
>> 
>> Thanks!
>> Tom
>> 
>>> 
>>> Thanks
>>> Laszlo
>>> 
> 
> 
> 


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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-10 23:17               ` Lendacky, Thomas
  2019-10-10 23:56                 ` Andrew Fish
@ 2019-10-11  8:56                 ` Laszlo Ersek
  2019-10-12  6:42                   ` Andrew Fish
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-11  8:56 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, Philippe Mathieu-Daudé

On 10/11/19 01:17, Lendacky, Thomas wrote:
> On 10/3/19 10:12 AM, Tom Lendacky wrote:
>>
>>
>> On 10/3/19 5:32 AM, Laszlo Ersek wrote:
>>> On 10/03/19 12:12, Laszlo Ersek wrote:
>>>
>>>>   UINT32   ApEntryPoint;
>>>>   EFI_GUID SevEsFooterGuid;
>>>>   UINT16   Size;
>>>
>>> It's probably better to reverse the order of "Size" and
>>> "SevEsFooterGuid", like this:
>>>
>>>   UINT32   ApEntryPoint;
>>>   UINT16   Size;
>>>   EFI_GUID SevEsFooterGuid;
>>>
>>> because then even the "Size" field can be changed (or resized), as a
>>> function of the footer GUID.
>>
>> Cool, I'll look into doing this and see how it works out.
> 
> Just an update on this idea. This has worked out well, but has a couple of
> caveats. Removing the Qemu change to make the flash mapped read-only in
> the nested page tables, caused the following:
> 
> 1. QemuFlashDetected() will attempt to detect how the flash memory device
>    behaves. Because it is marked as read-only by the hypervisor, writing
>    to the area results in a #NPF for the write-fault. With SEV-ES,
>    emulation of the instruction can't be performed (can't read guest
>    memory and not provided the faulting instruction bytes), so the vCPU is
>    just restarted. This results in an infinite #NPF occurring.
> 
>    The solution here was to check for SEV-ES being enabled and just return
>    false from QemuFlashDetected(). Any downfalls to doing that?

Short-circuiting QemuFlashDetected() on SEV-ES seems appropriate.

However, I don't understand why you return FALSE in that case. You
should return TRUE. If QemuFlashDetected() returns FALSE, then the UEFI
variable store will not be backed by the real pflash chip, it will be
emulated with an \NvVars file on the EFI system partition. That
emulation should really not be used nowadays.

So IMO the right approach here is:
- declare that SEV-ES only targets the "two pflash chips" setup
- return TRUE from QemuFlashDetected() when SEV-ES is on.

> 
> 2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
>    XCODE5 tool chain") causes a similar situation to #1. It attempts to do
>    some address fixups and write to the flash device.

That's... stunning.

Commit 2db0ccc2d7fe changes the file

  UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm

such that it does in-place binary patching.

This source file is referenced from:

  UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf

as well. Note "SecPei".

That makes the commit buggy, to my eyes, regardless of SEV-ES. Because:

The binary patching appears to occur in the SEC phase as well, i.e. at a
time when the exception handler is located in flash. That's incorrect on
physical hardware too.

Upon re-reading <https://bugzilla.tianocore.org/show_bug.cgi?id=849>,
this commit worked around an XCODE toolchain bug.

Unfortunately, the workaround is not suitable for the SEC phase. (Also
not suitable for the PEI phase, for such PEIMs that still execute from
flash.)

Please open a new bug for UefiCpuPkg in the TianoCore Bugzilla,
reference BZ#849 in the See Also field, and please also make the new bug
block BZ#2198.

(I'll comment on this issue in a different thread too; I'll CC you on it.)

>    Reverting that commit fixes the issue. I don't think that will be an
>    acceptable solution, though, so need to think about what to do here.
> 
> After those two changes, the above method works well.

I'm happy to hear!

Thanks,
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-11  8:56                 ` Laszlo Ersek
@ 2019-10-12  6:42                   ` Andrew Fish
  2019-10-12  7:46                     ` Liming Gao
  2019-10-14 13:11                     ` Laszlo Ersek
  0 siblings, 2 replies; 106+ messages in thread
From: Andrew Fish @ 2019-10-12  6:42 UTC (permalink / raw)
  To: devel, Laszlo Ersek
  Cc: Lendacky, Thomas, Jordan Justen, Ard Biesheuvel, Mike Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh,
	Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 4546 bytes --]

Laszlo,

For 2) this  is very unfortunate. I think the root cause is for those of us who work on x86 hardware day to day we get programed that SEC/PEI is IA32 and DXE is X64, and this can lead to some unfortunate coding outcomes. 

I'm guessing this code probably got ported from the DXE CPU driver or some other place that had no XIP assumptions. One option vs. patching is putting the relocations in the .data section. The only issue with that could be the need to align sections on page boundaries and that may take up too much space in XIP code. Perhaps we could only require the .data section relocations for XCODE, and map them to .text for the other toolchain? 

Thanks,

Andrew Fish

> On Oct 11, 2019, at 1:56 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 10/11/19 01:17, Lendacky, Thomas wrote:
>> On 10/3/19 10:12 AM, Tom Lendacky wrote:
>>> 
>>> 
>>> On 10/3/19 5:32 AM, Laszlo Ersek wrote:
>>>> On 10/03/19 12:12, Laszlo Ersek wrote:
>>>> 
>>>>>  UINT32   ApEntryPoint;
>>>>>  EFI_GUID SevEsFooterGuid;
>>>>>  UINT16   Size;
>>>> 
>>>> It's probably better to reverse the order of "Size" and
>>>> "SevEsFooterGuid", like this:
>>>> 
>>>>  UINT32   ApEntryPoint;
>>>>  UINT16   Size;
>>>>  EFI_GUID SevEsFooterGuid;
>>>> 
>>>> because then even the "Size" field can be changed (or resized), as a
>>>> function of the footer GUID.
>>> 
>>> Cool, I'll look into doing this and see how it works out.
>> 
>> Just an update on this idea. This has worked out well, but has a couple of
>> caveats. Removing the Qemu change to make the flash mapped read-only in
>> the nested page tables, caused the following:
>> 
>> 1. QemuFlashDetected() will attempt to detect how the flash memory device
>>   behaves. Because it is marked as read-only by the hypervisor, writing
>>   to the area results in a #NPF for the write-fault. With SEV-ES,
>>   emulation of the instruction can't be performed (can't read guest
>>   memory and not provided the faulting instruction bytes), so the vCPU is
>>   just restarted. This results in an infinite #NPF occurring.
>> 
>>   The solution here was to check for SEV-ES being enabled and just return
>>   false from QemuFlashDetected(). Any downfalls to doing that?
> 
> Short-circuiting QemuFlashDetected() on SEV-ES seems appropriate.
> 
> However, I don't understand why you return FALSE in that case. You
> should return TRUE. If QemuFlashDetected() returns FALSE, then the UEFI
> variable store will not be backed by the real pflash chip, it will be
> emulated with an \NvVars file on the EFI system partition. That
> emulation should really not be used nowadays.
> 
> So IMO the right approach here is:
> - declare that SEV-ES only targets the "two pflash chips" setup
> - return TRUE from QemuFlashDetected() when SEV-ES is on.
> 
>> 
>> 2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
>>   XCODE5 tool chain") causes a similar situation to #1. It attempts to do
>>   some address fixups and write to the flash device.
> 
> That's... stunning.
> 
> Commit 2db0ccc2d7fe changes the file
> 
>  UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> 
> such that it does in-place binary patching.
> 
> This source file is referenced from:
> 
>  UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
> 
> as well. Note "SecPei".
> 
> That makes the commit buggy, to my eyes, regardless of SEV-ES. Because:
> 
> The binary patching appears to occur in the SEC phase as well, i.e. at a
> time when the exception handler is located in flash. That's incorrect on
> physical hardware too.
> 
> Upon re-reading <https://bugzilla.tianocore.org/show_bug.cgi?id=849 <https://bugzilla.tianocore.org/show_bug.cgi?id=849>>,
> this commit worked around an XCODE toolchain bug.
> 
> Unfortunately, the workaround is not suitable for the SEC phase. (Also
> not suitable for the PEI phase, for such PEIMs that still execute from
> flash.)
> 
> Please open a new bug for UefiCpuPkg in the TianoCore Bugzilla,
> reference BZ#849 in the See Also field, and please also make the new bug
> block BZ#2198.
> 
> (I'll comment on this issue in a different thread too; I'll CC you on it.)
> 
>>   Reverting that commit fixes the issue. I don't think that will be an
>>   acceptable solution, though, so need to think about what to do here.
>> 
>> After those two changes, the above method works well.
> 
> I'm happy to hear!
> 
> Thanks,
> Laszlo
> 
> 


[-- Attachment #2: Type: text/html, Size: 38670 bytes --]

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-12  6:42                   ` Andrew Fish
@ 2019-10-12  7:46                     ` Liming Gao
  2019-10-12 18:50                       ` Andrew Fish
  2019-10-14 13:11                     ` Laszlo Ersek
  1 sibling, 1 reply; 106+ messages in thread
From: Liming Gao @ 2019-10-12  7:46 UTC (permalink / raw)
  To: devel@edk2.groups.io, afish@apple.com, Laszlo Ersek, Gao, Liming
  Cc: Lendacky, Thomas, Justen, Jordan L, Ard Biesheuvel,
	Kinney, Michael D, Dong, Eric, Ni, Ray, Singh, Brijesh,
	Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 5175 bytes --]

Andrew:
  Can you give more detail on how to update nasm source code to put the 64bit absolute address from .text section to .data section? I will verify it. Now, the patching way doesn't support X64 SEC/PEI. This is a gab in XCODE tool chain.

Thanks
Liming
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Andrew Fish via Groups.Io
Sent: Saturday, October 12, 2019 2:43 PM
To: devel@edk2.groups.io; Laszlo Ersek <lersek@redhat.com>
Cc: Lendacky, Thomas <Thomas.Lendacky@amd.com>; Justen, Jordan L <jordan.l.justen@intel.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>; Philippe Mathieu-Daudé <philmd@redhat.com>
Subject: Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES

Laszlo,

For 2) this  is very unfortunate. I think the root cause is for those of us who work on x86 hardware day to day we get programed that SEC/PEI is IA32 and DXE is X64, and this can lead to some unfortunate coding outcomes.

I'm guessing this code probably got ported from the DXE CPU driver or some other place that had no XIP assumptions. One option vs. patching is putting the relocations in the .data section. The only issue with that could be the need to align sections on page boundaries and that may take up too much space in XIP code. Perhaps we could only require the .data section relocations for XCODE, and map them to .text for the other toolchain?

Thanks,

Andrew Fish


On Oct 11, 2019, at 1:56 AM, Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>> wrote:

On 10/11/19 01:17, Lendacky, Thomas wrote:

On 10/3/19 10:12 AM, Tom Lendacky wrote:



On 10/3/19 5:32 AM, Laszlo Ersek wrote:

On 10/03/19 12:12, Laszlo Ersek wrote:


 UINT32   ApEntryPoint;
 EFI_GUID SevEsFooterGuid;
 UINT16   Size;

It's probably better to reverse the order of "Size" and
"SevEsFooterGuid", like this:

 UINT32   ApEntryPoint;
 UINT16   Size;
 EFI_GUID SevEsFooterGuid;

because then even the "Size" field can be changed (or resized), as a
function of the footer GUID.

Cool, I'll look into doing this and see how it works out.

Just an update on this idea. This has worked out well, but has a couple of
caveats. Removing the Qemu change to make the flash mapped read-only in
the nested page tables, caused the following:

1. QemuFlashDetected() will attempt to detect how the flash memory device
  behaves. Because it is marked as read-only by the hypervisor, writing
  to the area results in a #NPF for the write-fault. With SEV-ES,
  emulation of the instruction can't be performed (can't read guest
  memory and not provided the faulting instruction bytes), so the vCPU is
  just restarted. This results in an infinite #NPF occurring.

  The solution here was to check for SEV-ES being enabled and just return
  false from QemuFlashDetected(). Any downfalls to doing that?

Short-circuiting QemuFlashDetected() on SEV-ES seems appropriate.

However, I don't understand why you return FALSE in that case. You
should return TRUE. If QemuFlashDetected() returns FALSE, then the UEFI
variable store will not be backed by the real pflash chip, it will be
emulated with an \NvVars file on the EFI system partition. That
emulation should really not be used nowadays.

So IMO the right approach here is:
- declare that SEV-ES only targets the "two pflash chips" setup
- return TRUE from QemuFlashDetected() when SEV-ES is on.



2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
  XCODE5 tool chain") causes a similar situation to #1. It attempts to do
  some address fixups and write to the flash device.

That's... stunning.

Commit 2db0ccc2d7fe changes the file

 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm

such that it does in-place binary patching.

This source file is referenced from:

 UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf

as well. Note "SecPei".

That makes the commit buggy, to my eyes, regardless of SEV-ES. Because:

The binary patching appears to occur in the SEC phase as well, i.e. at a
time when the exception handler is located in flash. That's incorrect on
physical hardware too.

Upon re-reading <https://bugzilla.tianocore.org/show_bug.cgi?id=849>,
this commit worked around an XCODE toolchain bug.

Unfortunately, the workaround is not suitable for the SEC phase. (Also
not suitable for the PEI phase, for such PEIMs that still execute from
flash.)

Please open a new bug for UefiCpuPkg in the TianoCore Bugzilla,
reference BZ#849 in the See Also field, and please also make the new bug
block BZ#2198.

(I'll comment on this issue in a different thread too; I'll CC you on it.)


  Reverting that commit fixes the issue. I don't think that will be an
  acceptable solution, though, so need to think about what to do here.

After those two changes, the above method works well.

I'm happy to hear!

Thanks,
Laszlo





[-- Attachment #2: Type: text/html, Size: 12705 bytes --]

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-12  7:46                     ` Liming Gao
@ 2019-10-12 18:50                       ` Andrew Fish
  0 siblings, 0 replies; 106+ messages in thread
From: Andrew Fish @ 2019-10-12 18:50 UTC (permalink / raw)
  To: devel, liming.gao
  Cc: Laszlo Ersek, Lendacky, Thomas, Jordan Justen, Ard Biesheuvel,
	Mike Kinney, Dong, Eric, Ni, Ray, Singh, Brijesh,
	Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 7612 bytes --]

Liming,

Here is a simple example of a global with absolute function address in it. 

1) The text section uses %rip relative addressing. So the 1st goto technique is to convert absolute addressing to PC relative addressing if possible. 
2) The data section can contain absolute addresses. The data section is read/write. As you can see .quad can have a pointer to an absolute address (that would require a relocation).
3) The text section can access data section via PC relative addressing. 
4) While the code looks like it is located together the data section is going to follow the text section and get aligned to section alignment. So in my simple example the data section is 4K from the start of the text section. 
5) If all else fails the assembler will let you put code in the data section, and that code can have relocations, but see 4). 

~/work/Compiler>cat relocation.c
int main();

void *gRelocation = (void *)main;

int main ()
{
  return (int)(unsigned long long)gRelocation;
}
~/work/Compiler>clang -S -Os relocation.c
~/work/Compiler>cat relocation.S
	.section	__TEXT,__text,regular,pure_instructions
	.globl	_main                   ## -- Begin function main
_main:                                  ## @main
	pushq	%rbp
	movq	%rsp, %rbp
	movl	_gRelocation(%rip), %eax
	popq	%rbp
	retq
                                        ## -- End function

	.section	__DATA,__data
	.globl	_gRelocation            ## @gRelocation
	.p2align	3
_gRelocation:
	.quad	_main


.subsections_via_symbols

If you have questions about a specific chunk of code to convert let me know. 

Thanks,

Andrew Fish

> On Oct 12, 2019, at 12:46 AM, Liming Gao <liming.gao@intel.com> wrote:
> 
> Andrew:
>   Can you give more detail on how to update nasm source code to put the 64bit absolute address from .text section to .data section? I will verify it. Now, the patching way doesn’t support X64 SEC/PEI. This is a gab in XCODE tool chain. 
>
> Thanks
> Liming
> From: devel@edk2.groups.io <mailto:devel@edk2.groups.io> [mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>] On Behalf Of Andrew Fish via Groups.Io
> Sent: Saturday, October 12, 2019 2:43 PM
> To: devel@edk2.groups.io <mailto:devel@edk2.groups.io>; Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>>
> Cc: Lendacky, Thomas <Thomas.Lendacky@amd.com <mailto:Thomas.Lendacky@amd.com>>; Justen, Jordan L <jordan.l.justen@intel.com <mailto:jordan.l.justen@intel.com>>; Ard Biesheuvel <ard.biesheuvel@linaro.org <mailto:ard.biesheuvel@linaro.org>>; Kinney, Michael D <michael.d.kinney@intel.com <mailto:michael.d.kinney@intel.com>>; Gao, Liming <liming.gao@intel.com <mailto:liming.gao@intel.com>>; Dong, Eric <eric.dong@intel.com <mailto:eric.dong@intel.com>>; Ni, Ray <ray.ni@intel.com <mailto:ray.ni@intel.com>>; Singh, Brijesh <brijesh.singh@amd.com <mailto:brijesh.singh@amd.com>>; Philippe Mathieu-Daudé <philmd@redhat.com <mailto:philmd@redhat.com>>
> Subject: Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
>
> Laszlo,
>
> For 2) this  is very unfortunate. I think the root cause is for those of us who work on x86 hardware day to day we get programed that SEC/PEI is IA32 and DXE is X64, and this can lead to some unfortunate coding outcomes. 
>
> I'm guessing this code probably got ported from the DXE CPU driver or some other place that had no XIP assumptions. One option vs. patching is putting the relocations in the .data section. The only issue with that could be the need to align sections on page boundaries and that may take up too much space in XIP code. Perhaps we could only require the .data section relocations for XCODE, and map them to .text for the other toolchain? 
>
> Thanks,
>
> Andrew Fish
> 
> 
> On Oct 11, 2019, at 1:56 AM, Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> wrote:
>
> On 10/11/19 01:17, Lendacky, Thomas wrote:
> 
> On 10/3/19 10:12 AM, Tom Lendacky wrote:
> 
> 
> 
> On 10/3/19 5:32 AM, Laszlo Ersek wrote:
> 
> On 10/03/19 12:12, Laszlo Ersek wrote:
> 
> 
>  UINT32   ApEntryPoint;
>  EFI_GUID SevEsFooterGuid;
>  UINT16   Size;
> 
> It's probably better to reverse the order of "Size" and
> "SevEsFooterGuid", like this:
> 
>  UINT32   ApEntryPoint;
>  UINT16   Size;
>  EFI_GUID SevEsFooterGuid;
> 
> because then even the "Size" field can be changed (or resized), as a
> function of the footer GUID.
> 
> Cool, I'll look into doing this and see how it works out.
> 
> Just an update on this idea. This has worked out well, but has a couple of
> caveats. Removing the Qemu change to make the flash mapped read-only in
> the nested page tables, caused the following:
> 
> 1. QemuFlashDetected() will attempt to detect how the flash memory device
>   behaves. Because it is marked as read-only by the hypervisor, writing
>   to the area results in a #NPF for the write-fault. With SEV-ES,
>   emulation of the instruction can't be performed (can't read guest
>   memory and not provided the faulting instruction bytes), so the vCPU is
>   just restarted. This results in an infinite #NPF occurring.
> 
>   The solution here was to check for SEV-ES being enabled and just return
>   false from QemuFlashDetected(). Any downfalls to doing that?
> 
> Short-circuiting QemuFlashDetected() on SEV-ES seems appropriate.
> 
> However, I don't understand why you return FALSE in that case. You
> should return TRUE. If QemuFlashDetected() returns FALSE, then the UEFI
> variable store will not be backed by the real pflash chip, it will be
> emulated with an \NvVars file on the EFI system partition. That
> emulation should really not be used nowadays.
> 
> So IMO the right approach here is:
> - declare that SEV-ES only targets the "two pflash chips" setup
> - return TRUE from QemuFlashDetected() when SEV-ES is on.
> 
> 
> 
> 2. Commit 2db0ccc2d7fe ("UefiCpuPkg: Update CpuExceptionHandlerLib pass
>   XCODE5 tool chain") causes a similar situation to #1. It attempts to do
>   some address fixups and write to the flash device.
> 
> That's... stunning.
> 
> Commit 2db0ccc2d7fe changes the file
> 
>  UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> 
> such that it does in-place binary patching.
> 
> This source file is referenced from:
> 
>  UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
> 
> as well. Note "SecPei".
> 
> That makes the commit buggy, to my eyes, regardless of SEV-ES. Because:
> 
> The binary patching appears to occur in the SEC phase as well, i.e. at a
> time when the exception handler is located in flash. That's incorrect on
> physical hardware too.
> 
> Upon re-reading <https://bugzilla.tianocore.org/show_bug.cgi?id=849 <https://bugzilla.tianocore.org/show_bug.cgi?id=849>>,
> this commit worked around an XCODE toolchain bug.
> 
> Unfortunately, the workaround is not suitable for the SEC phase. (Also
> not suitable for the PEI phase, for such PEIMs that still execute from
> flash.)
> 
> Please open a new bug for UefiCpuPkg in the TianoCore Bugzilla,
> reference BZ#849 in the See Also field, and please also make the new bug
> block BZ#2198.
> 
> (I'll comment on this issue in a different thread too; I'll CC you on it.)
> 
> 
>   Reverting that commit fixes the issue. I don't think that will be an
>   acceptable solution, though, so need to think about what to do here.
> 
> After those two changes, the above method works well.
> 
> I'm happy to hear!
> 
> Thanks,
> Laszlo
> 
> 
>
> 


[-- Attachment #2: Type: text/html, Size: 27810 bytes --]

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-12  6:42                   ` Andrew Fish
  2019-10-12  7:46                     ` Liming Gao
@ 2019-10-14 13:11                     ` Laszlo Ersek
  2019-10-14 19:11                       ` Andrew Fish
  1 sibling, 1 reply; 106+ messages in thread
From: Laszlo Ersek @ 2019-10-14 13:11 UTC (permalink / raw)
  To: Andrew Fish, devel
  Cc: Lendacky, Thomas, Jordan Justen, Ard Biesheuvel, Mike Kinney,
	Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh,
	Philippe Mathieu-Daudé

On 10/12/19 08:42, Andrew Fish wrote:
> Laszlo,
>
> For 2) this  is very unfortunate. I think the root cause is for those
> of us who work on x86 hardware day to day we get programed that
> SEC/PEI is IA32 and DXE is X64, and this can lead to some unfortunate
> coding outcomes.

First I was confused by this; I didn't understand why the "bitness" of
SEC/PEI mattered here.

But, of course, you are right: if SEC/PEI are 32-bit, then the
problematic relocations are never generated by the compiler in the first
place.

> I'm guessing this code probably got ported from the DXE CPU driver or
> some other place that had no XIP assumptions. One option vs. patching
> is putting the relocations in the .data section. The only issue with
> that could be the need to align sections on page boundaries and that
> may take up too much space in XIP code. Perhaps we could only require
> the .data section relocations for XCODE, and map them to .text for
> the other toolchain?

In SEC, all sections of the binary are located in flash, aren't they?
Why would it help if the relocations were placed in .data? I'm reminded
of global variables in SEC, and those are not writable in SEC either.
(At least on QEMU.) I'm uncertain if this is somehow connected to
Cache-as-RAM, but if it is: QEMU does not support Cache-as-RAM.

Thanks
Laszlo

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

* Re: [edk2-devel] [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-10-14 13:11                     ` Laszlo Ersek
@ 2019-10-14 19:11                       ` Andrew Fish
  0 siblings, 0 replies; 106+ messages in thread
From: Andrew Fish @ 2019-10-14 19:11 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: devel, Lendacky, Thomas, Jordan Justen, Ard Biesheuvel,
	Mike Kinney, Liming Gao, Eric Dong, Ray Ni, Singh, Brijesh,
	Philippe Mathieu-Daudé



> On Oct 14, 2019, at 6:11 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 10/12/19 08:42, Andrew Fish wrote:
>> Laszlo,
>> 
>> For 2) this  is very unfortunate. I think the root cause is for those
>> of us who work on x86 hardware day to day we get programed that
>> SEC/PEI is IA32 and DXE is X64, and this can lead to some unfortunate
>> coding outcomes.
> 
> First I was confused by this; I didn't understand why the "bitness" of
> SEC/PEI mattered here.
> 
> But, of course, you are right: if SEC/PEI are 32-bit, then the
> problematic relocations are never generated by the compiler in the first
> place.
> 

Laszlo,

The other "human" problem is people assume DXE always runs from memory so they think that patching is OK. I've even see people use IA32 to mean PEI on X64 platforms. So the implementation (32-bit PEI) leaks into the architecture. 

>> I'm guessing this code probably got ported from the DXE CPU driver or
>> some other place that had no XIP assumptions. One option vs. patching
>> is putting the relocations in the .data section. The only issue with
>> that could be the need to align sections on page boundaries and that
>> may take up too much space in XIP code. Perhaps we could only require
>> the .data section relocations for XCODE, and map them to .text for
>> the other toolchain?
> 
> In SEC, all sections of the binary are located in flash, aren't they?

Yes. 

> Why would it help if the relocations were placed in .data?

Sorry if I was unclear. The Xcode linker (ld64) enforces a macOS x86_64 ABI that makes it so even the image loader can't write the text section.  Thus you can't link an image that has relocations in the text section, and there is no flag to ld64 to turn this behavior off.  So the workaround is to generate code like the compiler and don't have any relocations in the text section.  Moving the relocation from the text to the data section is needed to make the Xcode linker (ld64) link the code. if there are relocations in the text section then the link will fail on Xcode builds. 

When you are writing assembly code there is no restriction about placing code in the data section. Generally we try to fix issues by converting the code to use PC relative addressing, but a quick and dirty fix is to change the code over to the data section.  The cleaner solution is to have a global in the data section that contains the relocatable address, and that is like the simple example of the C code global I sent out. 

> I'm reminded
> of global variables in SEC, and those are not writable in SEC either.
> (At least on QEMU.) I'm uncertain if this is somehow connected to
> Cache-as-RAM, but if it is: QEMU does not support Cache-as-RAM.
> 

For SEC the relocations would have been applied at build time. The SEC will have been linked at around zero, and when it was placed in the FV it would have been relocated to its XIP location. For code running from memory the EFI PE/COFF loader would apply the relocations as part of loading the image.  But non of the above works if your build fails due to a linker error :(. 

Thanks,

Andrew Fish


> Thanks
> Laszlo


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

* Re: [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
  2019-09-20 13:16 ` [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
@ 2019-12-12  8:24   ` Ni, Ray
  2019-12-13 16:35     ` Lendacky, Thomas
  0 siblings, 1 reply; 106+ messages in thread
From: Ni, Ray @ 2019-12-12  8:24 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,
why this cannot be done as today's code in ExitBS callback?
Because it should be done after interrupt is disabled?

> -----Original Message-----
> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
> Sent: Friday, September 20, 2019 3:53 AM
> 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 v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
> 
> From: Tom Lendacky <thomas.lendacky@amd.com>
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Before UEFI transfers control to the OS, it must park the AP. This is
> done using the AsmRelocateApLoop function to transition into 32-bit
> non-paging mode. For an SEV-ES guest, a few additional things must be
> done:
>   - AsmRelocateApLoop must be updated to support SEV-ES. This means
>     performing a VMGEXIT AP Reset Hold instead of an MWAIT or HLT loop.
>   - Since the AP must transition to real mode, a small routine is copied
>     to the WakeupBuffer area. Since the WakeupBuffer will be used by
>     the AP during OS booting, it must be placed in reserved memory.
>     Additionally, the AP stack must be located where it can be accessed
>     in real mode.
>   - Once the AP is in real mode it will transfer control to the
>     destination specified by the OS in the SEV-ES AP Jump Table. The
>     SEV-ES AP Jump Table address is communicated to the OS using the BSP
>     GHCB MSR.
> 
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.h          |   8 +-
>  UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  54 ++++++-
>  UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 134 ++++++++++++++++--
>  3 files changed, 176 insertions(+), 20 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index 5966510d4a1b..2d38a0e85a40 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -277,7 +277,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 {
> @@ -331,8 +332,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
>    );
> 
>  /**
> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
> index 16603ef3f20e..cf53b5026aa4 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;
> @@ -86,6 +85,13 @@ GetWakeupBuffer (
>  {
>    EFI_STATUS              Status;
>    EFI_PHYSICAL_ADDRESS    StartAddress;
> +  EFI_MEMORY_TYPE         MemoryType;
> +
> +  if (PcdGetBool (PcdSevEsActive)) {
> +    MemoryType = EfiReservedMemoryType;
> +  } else {
> +    MemoryType = EfiBootServicesData;
> +  }
> 
>    //
>    // Try to allocate buffer below 1M for waking vector.
> @@ -98,7 +104,7 @@ GetWakeupBuffer (
>    StartAddress = 0x88000;
>    Status = gBS->AllocatePages (
>                    AllocateMaxAddress,
> -                  EfiBootServicesData,
> +                  MemoryType,
>                    EFI_SIZE_TO_PAGES (WakeupBufferSize),
>                    &StartAddress
>                    );
> @@ -331,17 +337,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
> @@ -895,9 +910,34 @@ MpFinalize (
>    IN CPU_MP_DATA   *CpuMpData
>    )
>  {
> -  //
> -  // DXE phase will do this transition, but just return EFI_SUCCESS for now.
> -  //
> +  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/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> index bbc7432740ff..3cb0cd5bb306 100644
> --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
> @@ -465,6 +465,10 @@ BITS 16
>      ;     - IP for Real Mode (two bytes)
>      ;     - CS for Real Mode (two bytes)
>      ;
> +    ; This label is also used with AsmRelocateApLoop. During MP finalization,
> +    ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
> +    ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
> +    ;
>  PM16Mode:
>      mov        eax, cr0                    ; Read CR0
>      btr        eax, 0                      ; Set PE=0
> @@ -487,32 +491,95 @@ 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
> +    ;   - Must be done while in 64-bit long mode so that writes to
> +    ;     the GHCB memory will be unencrypted.
> +    ;   - No NAE events can be generated once this is set otherwise
> +    ;     the AP_RESET_HOLD 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_RESET_HOLD
> +    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
> @@ -525,6 +592,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
> @@ -538,10 +607,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	[flat|nested] 106+ messages in thread

* Re: [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
  2019-12-12  8:24   ` Ni, Ray
@ 2019-12-13 16:35     ` Lendacky, Thomas
  0 siblings, 0 replies; 106+ messages in thread
From: Lendacky, Thomas @ 2019-12-13 16:35 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

On 12/12/19 2:24 AM, Ni, Ray wrote:
> Tom,
> why this cannot be done as today's code in ExitBS callback?
> Because it should be done after interrupt is disabled?

The problem comes from the calls during and after the ExitBS callbacks are
performed. Part of the finalization support is to set the AP jump table in
the GHCB MSR and to copy/move AP reset code for use when the OS starts the
APs.  The GHCB MSR will now not point to an actual GHCB, so we can't take
any more #VCs at that point.  When I look at the #VC count when running
through CoreExitBootServices() in MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
(with debug statements enabled), I see the following #VC counts:

  CoreNotifySignalList() = 12
  MemoryProtectionExitBootServicesCallback() = 1908

If I disable serial debug (don't build with -DDEBUG_ON_SERIAL_PORT=TRUE),
I see the following #VC counts:

  CoreNotifySignalList() = 2
  MemoryProtectionExitBootServicesCallback() = 234

So even if I could ensure that an SEV-ES callback was the last callback
in CoreNotifySignalList(), MemoryProtectionExitBootServicesCallback() will
generate #VCs so we need to perform the finalization (or at least the GHCB
MSR update) after that.

I'm looking at whether I can eliminate the need for the finalization
support. I might be able to perform the copy/move of the AP reset code
in MpInitChangeApLoopCallback() - I just need to be careful that all APs
are out of the area of code that will be updated. And if I implement a
new GHCB protocol for registering the jump page, I can leave the GHCB MSR
in tact. Just a concept at the moment, but it may be possible.

Thanks,
Tom

> 
>> -----Original Message-----
>> From: Lendacky, Thomas <Thomas.Lendacky@amd.com>
>> Sent: Friday, September 20, 2019 3:53 AM
>> 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 v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
>>
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>
>> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2198&amp;data=02%7C01%7CThomas.Lendacky%40amd.com%7Ce9dfe136268e4b3b8bd308d77edca950%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117358507708564&amp;sdata=o7EsL8JXEpjg8sixUFshm3yIoCHi8T7dyCLEPNT1bqQ%3D&amp;reserved=0
>>
>> Before UEFI transfers control to the OS, it must park the AP. This is
>> done using the AsmRelocateApLoop function to transition into 32-bit
>> non-paging mode. For an SEV-ES guest, a few additional things must be
>> done:
>>   - AsmRelocateApLoop must be updated to support SEV-ES. This means
>>     performing a VMGEXIT AP Reset Hold instead of an MWAIT or HLT loop.
>>   - Since the AP must transition to real mode, a small routine is copied
>>     to the WakeupBuffer area. Since the WakeupBuffer will be used by
>>     the AP during OS booting, it must be placed in reserved memory.
>>     Additionally, the AP stack must be located where it can be accessed
>>     in real mode.
>>   - Once the AP is in real mode it will transfer control to the
>>     destination specified by the OS in the SEV-ES AP Jump Table. The
>>     SEV-ES AP Jump Table address is communicated to the OS using the BSP
>>     GHCB MSR.
>>
>> Cc: Eric Dong <eric.dong@intel.com>
>> Cc: Ray Ni <ray.ni@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  UefiCpuPkg/Library/MpInitLib/MpLib.h          |   8 +-
>>  UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  54 ++++++-
>>  UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 134 ++++++++++++++++--
>>  3 files changed, 176 insertions(+), 20 deletions(-)
>>
>> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> index 5966510d4a1b..2d38a0e85a40 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> @@ -277,7 +277,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 {
>> @@ -331,8 +332,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
>>    );
>>
>>  /**
>> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
>> index 16603ef3f20e..cf53b5026aa4 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;
>> @@ -86,6 +85,13 @@ GetWakeupBuffer (
>>  {
>>    EFI_STATUS              Status;
>>    EFI_PHYSICAL_ADDRESS    StartAddress;
>> +  EFI_MEMORY_TYPE         MemoryType;
>> +
>> +  if (PcdGetBool (PcdSevEsActive)) {
>> +    MemoryType = EfiReservedMemoryType;
>> +  } else {
>> +    MemoryType = EfiBootServicesData;
>> +  }
>>
>>    //
>>    // Try to allocate buffer below 1M for waking vector.
>> @@ -98,7 +104,7 @@ GetWakeupBuffer (
>>    StartAddress = 0x88000;
>>    Status = gBS->AllocatePages (
>>                    AllocateMaxAddress,
>> -                  EfiBootServicesData,
>> +                  MemoryType,
>>                    EFI_SIZE_TO_PAGES (WakeupBufferSize),
>>                    &StartAddress
>>                    );
>> @@ -331,17 +337,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
>> @@ -895,9 +910,34 @@ MpFinalize (
>>    IN CPU_MP_DATA   *CpuMpData
>>    )
>>  {
>> -  //
>> -  // DXE phase will do this transition, but just return EFI_SUCCESS for now.
>> -  //
>> +  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/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> index bbc7432740ff..3cb0cd5bb306 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
>> @@ -465,6 +465,10 @@ BITS 16
>>      ;     - IP for Real Mode (two bytes)
>>      ;     - CS for Real Mode (two bytes)
>>      ;
>> +    ; This label is also used with AsmRelocateApLoop. During MP finalization,
>> +    ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
>> +    ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
>> +    ;
>>  PM16Mode:
>>      mov        eax, cr0                    ; Read CR0
>>      btr        eax, 0                      ; Set PE=0
>> @@ -487,32 +491,95 @@ 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
>> +    ;   - Must be done while in 64-bit long mode so that writes to
>> +    ;     the GHCB memory will be unencrypted.
>> +    ;   - No NAE events can be generated once this is set otherwise
>> +    ;     the AP_RESET_HOLD 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_RESET_HOLD
>> +    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
>> @@ -525,6 +592,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
>> @@ -538,10 +607,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	[flat|nested] 106+ messages in thread

end of thread, other threads:[~2019-12-13 16:35 UTC | newest]

Thread overview: 106+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-09-19 19:52 [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 01/44] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 02/44] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2019-09-24 11:53   ` [edk2-devel] " Laszlo Ersek
2019-09-19 19:52 ` [RFC PATCH v2 03/44] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
2019-09-24 11:59   ` [edk2-devel] " Laszlo Ersek
2019-09-24 14:43     ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 04/44] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2019-09-24 13:42   ` [edk2-devel] " Laszlo Ersek
2019-09-24 13:50     ` Laszlo Ersek
2019-09-24 18:57     ` Lendacky, Thomas
2019-09-25 14:45       ` Laszlo Ersek
2019-09-30 19:29       ` Laszlo Ersek
2019-09-30 19:55         ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 05/44] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 06/44] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2019-09-25  8:09   ` [edk2-devel] " Laszlo Ersek
2019-09-25 17:36     ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 07/44] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
2019-09-25  8:27   ` [edk2-devel] " Laszlo Ersek
2019-09-25 17:52     ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 08/44] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2019-09-26  8:00   ` [edk2-devel] " Laszlo Ersek
2019-09-26 14:00     ` Lendacky, Thomas
2019-09-30 18:52       ` Laszlo Ersek
2019-09-30 19:49         ` Lendacky, Thomas
2019-09-30 19:12       ` Laszlo Ersek
2019-09-30 19:51         ` Lendacky, Thomas
2019-10-02 10:23   ` Laszlo Ersek
2019-10-02 14:43     ` Lendacky, Thomas
2019-10-02 15:55       ` Laszlo Ersek
2019-09-19 19:52 ` [RFC PATCH v2 09/44] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 10/44] OvmfPkg: A per-CPU variable area for #VC usage Lendacky, Thomas
2019-09-26  8:17   ` [edk2-devel] " Laszlo Ersek
2019-09-26 14:46     ` Lendacky, Thomas
2019-09-30 19:15       ` Laszlo Ersek
2019-09-30 19:52         ` Lendacky, Thomas
2019-10-02 11:51   ` Laszlo Ersek
2019-10-02 16:06     ` Lendacky, Thomas
2019-10-03  9:06       ` Laszlo Ersek
2019-09-19 19:52 ` [RFC PATCH v2 11/44] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2019-10-02 12:05   ` [edk2-devel] " Laszlo Ersek
2019-10-02 16:10     ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 12/44] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 13/44] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 14/44] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 15/44] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 16/44] OvmfPkg/MemEncryptSevLib: Make MemEncryptSevLib available during SEC Lendacky, Thomas
2019-10-02 12:24   ` [edk2-devel] " Laszlo Ersek
2019-10-02 12:30     ` Laszlo Ersek
2019-10-02 16:16       ` Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 17/44] UefiCpuPkg/CpuExceptionHandler: Add #VC exception handling for Sec phase Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 18/44] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2019-10-02 12:31   ` [edk2-devel] " Laszlo Ersek
2019-09-19 19:52 ` [RFC PATCH v2 19/44] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 20/44] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 21/44] MdePkg: Add support for the XGETBV instruction Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 22/44] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 23/44] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 24/44] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 25/44] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 26/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 27/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 28/44] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 29/44] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 30/44] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
2019-09-19 19:52 ` [RFC PATCH v2 31/44] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 32/44] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 33/44] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 34/44] UefiCpuPkg/MpInitLib: Update CPU MP data with a flag to indicate if SEV-ES is active Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 35/44] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 36/44] UefiCpuPkg: Add " Lendacky, Thomas
2019-09-19 19:53 ` [RFC PATCH v2 37/44] OvmfPkg: Add support for SEV-ES AP reset vector re-directing Lendacky, Thomas
2019-10-02 14:54   ` [edk2-devel] " Laszlo Ersek
2019-10-02 17:33     ` Lendacky, Thomas
2019-10-03  9:09       ` Laszlo Ersek
2019-09-19 19:53 ` [RFC PATCH v2 38/44] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
2019-10-02 15:15   ` [edk2-devel] " Laszlo Ersek
2019-10-02 15:26     ` Laszlo Ersek
2019-10-02 18:07       ` Lendacky, Thomas
2019-10-03 10:12         ` Laszlo Ersek
2019-10-03 10:32           ` Laszlo Ersek
2019-10-03 15:12             ` Lendacky, Thomas
2019-10-10 23:17               ` Lendacky, Thomas
2019-10-10 23:56                 ` Andrew Fish
2019-10-11  8:56                 ` Laszlo Ersek
2019-10-12  6:42                   ` Andrew Fish
2019-10-12  7:46                     ` Liming Gao
2019-10-12 18:50                       ` Andrew Fish
2019-10-14 13:11                     ` Laszlo Ersek
2019-10-14 19:11                       ` Andrew Fish
2019-10-02 17:58     ` Lendacky, Thomas
2019-10-03  9:21       ` Laszlo Ersek
2019-09-19 19:53 ` [RFC PATCH v2 40/44] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
2019-09-20 13:16 ` [RFC PATCH v2 39/44] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
2019-10-02 14:38   ` [edk2-devel] " Laszlo Ersek
2019-09-20 13:16 ` [RFC PATCH v2 42/44] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
2019-12-12  8:24   ` Ni, Ray
2019-12-13 16:35     ` Lendacky, Thomas
2019-09-20 13:16 ` [RFC PATCH v2 41/44] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
2019-09-20 13:16 ` [RFC PATCH v2 43/44] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
2019-09-20 13:16 ` [RFC PATCH v2 44/44] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
2019-09-20 19:24 ` [RFC PATCH v2 00/44] SEV-ES guest support Lendacky, Thomas
2019-09-24  1:55   ` [edk2-devel] " Dong, Eric
2019-09-24 14:31     ` Lendacky, Thomas
2019-09-25 22:31       ` Ni, Ray

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