public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [RFC PATCH v3 00/43] SEV-ES guest support
@ 2019-11-20 20:06 Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
                   ` (44 more replies)
  0 siblings, 45 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Benjamin You,
	Dandan Bi, Guo Dong, Hao A Wu, Jian J Wang, Maurice Ma

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:
cc6854506c2b ("Readme.md: remove positional references from submodule description")

Proper execution of SEV-ES relies on Bugzilla 2340 being fixed.

A version of the tree (with an extra patch to workaround Bugzilla 2340) can
be found at:
https://github.com/AMDESE/ovmf/tree/sev-es-v9

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 v2:
- Added a way to locate the SEV-ES fixed AP RIP address for starting
  AP's to avoid updating the actual flash image (build time location
  that is identified with a GUID value).
- Create a VmgExit library to replace static inline functions.
- Move some PCDs to the appropriate packages
- Add support for writing to QEMU flash under SEV-ES
- Add additional MMIO opcode support
- Cleaned up the GHCB MSR CPUID protocol support

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 (43):
  MdePkg: Create PCDs to be used in support of SEV-ES
  MdePkg: Add the MSR definition for the GHCB register
  MdePkg: Add a structure definition for the GHCB
  MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  MdePkg/BaseLib: Add support for the XGETBV instruction
  MdePkg/BaseLib: Add support for the VMGEXIT instruction
  UefiCpuPkg: Implement library support for VMGEXIT
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE
    events
  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
  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
  OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  OvmfPkg/Sec: Add #VC exception handling for Sec phase
  OvmfPkg/Sec: Enable cache early to speed up booting
  OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with
    SEV-ES is enabled
  MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
  UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is
    enabled
  UefiCpuPkg: Allow AP booting under SEV-ES
  OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  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                 |   23 +
 OvmfPkg/OvmfPkg.dec                           |    5 +
 UefiCpuPkg/UefiCpuPkg.dec                     |    8 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   11 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   11 +
 OvmfPkg/OvmfPkgX64.dsc                        |   11 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
 UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
 UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
 OvmfPkg/OvmfPkgX64.fdf                        |    9 +
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
 MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
 .../FvbServicesRuntimeDxe.inf                 |    2 +
 OvmfPkg/ResetVector/ResetVector.inf           |    9 +
 OvmfPkg/Sec/SecMain.inf                       |    1 +
 .../DxeCpuExceptionHandlerLib.inf             |    5 +
 .../PeiCpuExceptionHandlerLib.inf             |    5 +
 .../SecPeiCpuExceptionHandlerLib.inf          |    8 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    4 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    4 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
 .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
 MdePkg/Include/Library/BaseLib.h              |   31 +
 MdePkg/Include/Protocol/Cpu.h                 |   18 +
 MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
 MdePkg/Include/Register/Amd/Ghcb.h            |  117 ++
 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       |   96 ++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   26 +
 .../CpuExceptionCommon.h                      |    2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |   79 +-
 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                  |   82 ++
 OvmfPkg/PlatformPei/MemDetect.c               |   23 +
 .../QemuFlash.c                               |   38 +-
 OvmfPkg/Sec/SecMain.c                         |   74 +-
 UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
 UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
 .../CpuExceptionCommon.c                      |    2 +-
 .../Ia32/AMDSevVcCommon.c                     |   20 +
 .../PeiDxeAMDSevVcHandler.c                   |   29 +
 .../PeiDxeSmmCpuException.c                   |   16 +
 .../SecAMDSevVcHandler.c                      |   50 +
 .../SecPeiCpuException.c                      |   16 +
 .../X64/AMDSevVcCommon.c                      | 1230 +++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  280 +++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |  132 ++
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   37 +
 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  |   94 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  337 ++++-
 OvmfPkg/ResetVector/ResetVector.nasmb         |   19 +
 .../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 |  370 ++++-
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
 .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
 74 files changed, 3969 insertions(+), 101 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] 82+ messages in thread

* [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  6:53   ` Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 02/43] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
                   ` (43 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Jian J Wang,
	Hao A Wu

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

Two new fixed PCSs are needed to support SEV-ES under OVMF:
  - PcdSecGhcbBase  UINT64 value that is the base address of the GHCB
                    used during the SEC phase.
  - PcdSecGhcbSize  UINT64 value that is the size, in bytes, of the GHCB
                    area used during the SEC phase.

Three new dynamic PCDs are needed to support SEV-ES under OVMF:
  - PcdSevEsIsEnabled: BOOLEAN value used to indicate if SEV-ES is enabled
  - 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 | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 41b9e70a1ac8..c3bdfcc80971 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -1037,6 +1037,14 @@ [PcdsFixedAtBuild]
   # @Prompt Enable UEFI Stack Guard.
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055
 
+  ## The base address of the SEC GHCB page.
+  # @Prompt SEC GHCB Base Address
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|0|UINT32|0x30001056
+
+  ## The total size of the SEC GHCB page.
+  # @Prompt SEC GHCB Size
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize|0|UINT32|0x30001057
+
 [PcdsFixedAtBuild, PcdsPatchableInModule]
   ## Dynamic type PCD can be registered callback function for Pcd setting action.
   #  PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
@@ -2053,6 +2061,21 @@ [PcdsDynamic, PcdsDynamicEx]
   # @Prompt If there is any test key used by the platform.
   gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed|FALSE|BOOLEAN|0x00030003
 
+  ## This dynamic PCD indicates whether SEV-ES is enabled
+  #   TRUE  - SEV-ES is enabled
+  #   FALSE - SEV-ES is not enabled
+  # @Prompt SEV-ES Status
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x00030007
+
+  ## This dynamic PCD holds the base address of the GHCB pool allocation.
+  # @Prompt GHCB Pool Base Address
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00030008
+
+  ## This dynamic PCD holds the total size of the GHCB pool allocation.
+  #  The amount of memory allocated for GHCBs is dependent on the number of APs.
+  # @Prompt GHCB Pool Size
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030009
+
 [PcdsDynamicEx]
   ## This dynamic PCD enables the default variable setting.
   #  Its value is the default store ID value. The default value is zero as Standard default.
-- 
2.17.1


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

* [RFC PATCH v3 02/43] MdePkg: Add the MSR definition for the GHCB register
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 03/43] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
                   ` (42 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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] 82+ messages in thread

* [RFC PATCH v3 03/43] MdePkg: Add a structure definition for the GHCB
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 02/43] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
                   ` (41 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 | 117 +++++++++++++++++++++++++++++
 1 file changed, 117 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..e7ccca91f93d
--- /dev/null
+++ b/MdePkg/Include/Register/Amd/Ghcb.h
@@ -0,0 +1,117 @@
+/** @file
+  Guest-Hypervisor Communication Block (GHCB) Definition.
+
+  Provides data types allowing an SEV-ES guest to interact with the hypervisor
+  using the GHCB protocol.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Specification Reference:
+  SEV-ES Guest-Hypervisor Communication Block Standardization
+
+**/
+
+#ifndef __GHCB_H__
+#define __GHCB_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] 82+ messages in thread

* [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (2 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 03/43] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  6:53   ` [edk2-devel] " Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 05/43] MdePkg/BaseLib: Add support for the XGETBV instruction Lendacky, Thomas
                   ` (40 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Jian J Wang,
	Hao A Wu, Dandan Bi

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 6e8ca824d469..284b34818ca7 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
@@ -282,7 +282,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 f465eb1d8ac4..156a477d8467 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;
 
   //
   // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
@@ -81,12 +83,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] 82+ messages in thread

* [RFC PATCH v3 05/43] MdePkg/BaseLib: Add support for the XGETBV instruction
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (3 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 06/43] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
                   ` (39 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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        | 17 +++++++++++++
 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, 142 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 3586beb0ab5c..d7a1dd017e95 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/XGetBv.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/XGetBv.nasm | MSFT
 
 
   X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 2a75bc023f56..8b710dcc0aad 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7880,6 +7880,23 @@ AsmLfence (
   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,
   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..591f0bb0e097 100644
--- a/MdePkg/Library/BaseLib/Ia32/GccInline.c
+++ b/MdePkg/Library/BaseLib/Ia32/GccInline.c
@@ -1763,3 +1763,31 @@ AsmFlushCacheLine (
 }
 
 
+/**
+  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 154ce1f57e92..3eed1205adb2 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1798,3 +1798,33 @@ AsmFlushCacheLine (
 }
 
 
+/**
+  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..23ad38df0710
--- /dev/null
+++ b/MdePkg/Library/BaseLib/Ia32/XGetBv.nasm
@@ -0,0 +1,31 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Devices, 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..cd73e972d31b
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/XGetBv.nasm
@@ -0,0 +1,34 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Devices, 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, 32
+    or      rax, rdx
+    ret
+
-- 
2.17.1


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

* [RFC PATCH v3 06/43] MdePkg/BaseLib: Add support for the VMGEXIT instruction
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (4 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 05/43] MdePkg/BaseLib: Add support for the XGETBV instruction Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
                   ` (38 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 | 37 ++++++++++++++++++++++++
 MdePkg/Library/BaseLib/X64/VmgExit.nasm  | 32 ++++++++++++++++++++
 6 files changed, 119 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 d7a1dd017e95..62a09197b8a8 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/XGetBv.nasm | MSFT
+  Ia32/VmgExit.nasm | MSFT
 
 
   Ia32/GccInline.c | GCC
@@ -288,6 +289,7 @@ [Sources.X64]
   X64/ReadCr0.nasm| MSFT
   X64/ReadEflags.nasm| MSFT
   X64/XGetBv.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 8b710dcc0aad..378f5c1b18fb 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7897,6 +7897,20 @@ AsmXGetBv (
   );
 
 
+/**
+  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 591f0bb0e097..ee8c62c79c93 100644
--- a/MdePkg/Library/BaseLib/Ia32/GccInline.c
+++ b/MdePkg/Library/BaseLib/Ia32/GccInline.c
@@ -1791,3 +1791,20 @@ AsmXGetBv (
 }
 
 
+/**
+  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 3eed1205adb2..277974eff9ee 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1828,3 +1828,20 @@ AsmXGetBv (
 }
 
 
+/**
+  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..85e6260b4e2c
--- /dev/null
+++ b/MdePkg/Library/BaseLib/Ia32/VmgExit.nasm
@@ -0,0 +1,37 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Devices, 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):
+;
+; NASM doesn't support the vmmcall instruction in 32-bit mode, so work around
+; this by temporarily switching to 64-bit mode.
+;
+BITS    64
+    rep     vmmcall
+BITS    32
+    ret
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
new file mode 100644
index 000000000000..400d0302c4a3
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
@@ -0,0 +1,32 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Devices, 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] 82+ messages in thread

* [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (5 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 06/43] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 11:15   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 08/43] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
                   ` (37 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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.

Additionally, two VMGEXIT / MMIO related functions are created to support
flash emulation. Flash emulation currently is done by marking the flash
area as read-only and taking a nested page fault to perform the emulation
of the instruction. However, emulation cannot be performed because there
is no instruction decode assist support when SEV-ES is enabled. Provide
routines to initiate an MMIO request to perform actual writes to flash.

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      |  96 ++++++++++++++
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c   | 132 +++++++++++++++++++
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni |  15 +++
 6 files changed, 284 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 12f4413ea5b0..90feb9166dc8 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 d28cb5cccb52..5ab7e423e8ab 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
@@ -136,6 +140,7 @@ [Components.IA32, Components.X64]
   UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
   UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
   UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
+  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
   UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf
   UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf
   UefiCpuPkg/SecCore/SecCore.inf
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
new file mode 100644
index 000000000000..6acfa779e75a
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -0,0 +1,33 @@
+## @file
+#  VMGEXIT Support Library.
+#
+#  Copyright (c) 2019, Advanced Micro Devices, 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..b5639fbfa1a5
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
@@ -0,0 +1,96 @@
+/** @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, Advanced Micro Devices, 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
+  );
+
+#define VMGMMIO_READ   False
+#define VMGMMIO_WRITE  True
+
+/**
+  Perform MMIO write of a buffer to a non-MMIO marked range.
+
+  Performs an MMIO write without taking a #VC. This is useful
+  for Flash devices, which are marked read-only.
+
+  @param[in]  UINT8      A pointer to the destination buffer
+  @param[in]  UINTN      The immediate value to write
+  @param[in]  UINTN      Number of bytes to write
+
+**/
+VOID
+EFIAPI
+VmgMmioWrite (
+  UINT8               *Dest,
+  UINT8               *Src,
+  UINTN                Bytes
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
new file mode 100644
index 000000000000..23965b7ff022
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
@@ -0,0 +1,132 @@
+/** @file
+  VMGEXIT Support Library.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Register/Amd/Ghcb.h>
+#include <Register/Amd/Msr.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
+  )
+{
+}
+
+UINTN
+EFIAPI
+VmgMmio (
+  UINT8               *MmioAddress,
+  UINT8               *Buffer,
+  UINTN               Bytes,
+  BOOLEAN             Write
+  )
+{
+  UINT64                    MmioOp;
+  UINT64                    ExitInfo1, ExitInfo2;
+  UINTN                     Status;
+  GHCB                      *Ghcb;
+  MSR_SEV_ES_GHCB_REGISTER  Msr;
+
+  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+  Ghcb = Msr.Ghcb;
+
+  if (Write) {
+    MmioOp = SvmExitMmioWrite;
+  } else {
+    MmioOp = SvmExitMmioRead;
+  }
+
+  ExitInfo1 = (UINT64) (UINTN) MmioAddress;
+  ExitInfo2 = Bytes;
+
+  if (Write) {
+    CopyMem (Ghcb->SharedBuffer, Buffer, Bytes);
+  }
+
+  Ghcb->SaveArea.SwScratch = (UINT64) (UINTN) Ghcb->SharedBuffer;
+  Status = VmgExit (Ghcb, MmioOp, ExitInfo1, ExitInfo2);
+  if (Status != 0) {
+    return Status;
+  }
+
+  if (!Write) {
+    CopyMem (Buffer, Ghcb->SharedBuffer, Bytes);
+  }
+
+  return 0;
+}
+
+VOID
+EFIAPI
+VmgMmioWrite (
+  UINT8               *Dest,
+  UINT8               *Src,
+  UINTN                Bytes
+  )
+{
+  VmgMmio (Dest, Src, Bytes, TRUE);
+}
+
diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
new file mode 100644
index 000000000000..e8656aae4726
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// VMGEXIT support library instance.
+//
+// VMGEXIT support library instance.
+//
+// Copyright (c) 2019, Advanced Micro Devices, 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] 82+ messages in thread

* [RFC PATCH v3 08/43] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (6 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 09/43] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
                   ` (36 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Maurice Ma,
	Guo Dong, Benjamin You

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          |  8 +++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   | 26 ++++++++++
 .../CpuExceptionCommon.h                      |  2 +
 .../CpuExceptionCommon.c                      |  2 +-
 .../Ia32/AMDSevVcCommon.c                     | 20 ++++++++
 .../PeiDxeAMDSevVcHandler.c                   | 29 +++++++++++
 .../PeiDxeSmmCpuException.c                   | 16 ++++++
 .../SecAMDSevVcHandler.c                      | 50 +++++++++++++++++++
 .../SecPeiCpuException.c                      | 16 ++++++
 .../X64/AMDSevVcCommon.c                      | 35 +++++++++++++
 17 files changed, 232 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 d350b756304e..0e17de188cd6 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -236,6 +236,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
@@ -274,6 +275,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
@@ -299,6 +301,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]
@@ -349,6 +352,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
@@ -392,6 +396,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
 !if $(SOURCE_DEBUG_ENABLE) == TRUE
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 1ef82cafe4aa..c8708c90f695 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -241,6 +241,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
@@ -279,6 +280,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
@@ -304,6 +306,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]
@@ -354,6 +357,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
@@ -397,6 +401,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
 !if $(SOURCE_DEBUG_ENABLE) == TRUE
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 232815c08e11..85f817b86130 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -241,6 +241,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
@@ -279,6 +280,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
@@ -304,6 +306,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]
@@ -354,6 +357,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
@@ -397,6 +401,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
 !if $(SOURCE_DEBUG_ENABLE) == TRUE
   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..28b9a78c6be5 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,7 @@ [LibraryClasses]
   PrintLib
   LocalApicLib
   PeCoffGetEntryPointLib
+  VmgExitLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
new file mode 100644
index 000000000000..c0a2ecd17d4c
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/AMDSevVcCommon.h
@@ -0,0 +1,26 @@
+/** @file
+  Common header file for SEV-ES #VC Exception Handler Support.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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..595d9c2ba04e
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/AMDSevVcCommon.c
@@ -0,0 +1,20 @@
+/** @file
+  IA32 SEV-ES #VC Exception Handler functons.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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..68baaa7c6a89
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeAMDSevVcHandler.c
@@ -0,0 +1,29 @@
+/** @file
+  PEI and DXE SEV-ES #VC Exception Handler functons.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 == FALSE);
+
+  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..a68b178d2236
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecAMDSevVcHandler.c
@@ -0,0 +1,50 @@
+/** @file
+  SEC SEV-ES #VC Exception Handler functons.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.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);
+  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 = FixedPcdGet32 (PcdSecGhcbBase);
+    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..4b56767f9374
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -0,0 +1,35 @@
+/** @file
+  X64 SEV-ES #VC Exception Handler functons.
+
+  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/VmgExitLib.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] 82+ messages in thread

* [RFC PATCH v3 09/43] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (7 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 08/43] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 10/43] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
                   ` (35 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 4b56767f9374..c42fe632f255 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -11,6 +11,425 @@
 #include <Library/VmgExitLib.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,
@@ -18,6 +437,8 @@ DoVcCommon (
   )
 {
   EFI_SYSTEM_CONTEXT_X64   *Regs = Context.SystemContextX64;
+  SEV_ES_INSTRUCTION_DATA  InstructionData;
+  NAE_EXIT                 NaeExit;
   UINTN                    ExitCode;
   UINTN                    Status;
 
@@ -25,8 +446,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] 82+ messages in thread

* [RFC PATCH v3 10/43] UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (8 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 09/43] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 11/43] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
                   ` (34 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 c42fe632f255..98b62c21bbce 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -312,6 +312,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:
@@ -349,6 +365,8 @@ IoioExitInfo (
   }
 
   switch (*(InstructionData->OpCodes)) {
+  case 0x6C:
+  case 0x6E:
   case 0xE4:
   case 0xE6:
   case 0xEC:
@@ -395,8 +413,9 @@ IoioExit (
   SEV_ES_INSTRUCTION_DATA  *InstructionData
   )
 {
-  UINT64  ExitInfo1;
-  UINTN   Status;
+  UINT64   ExitInfo1, ExitInfo2;
+  UINTN    Status;
+  BOOLEAN  String;
 
   ExitInfo1 = IoioExitInfo (Regs, InstructionData);
   if (!ExitInfo1) {
@@ -414,17 +433,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] 82+ messages in thread

* [RFC PATCH v3 11/43] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (9 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 10/43] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 12/43] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
                   ` (33 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 98b62c21bbce..56f0040fff9f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -11,6 +11,8 @@
 #include <Library/VmgExitLib.h>
 #include "AMDSevVcCommon.h"
 
+#define CR4_OSXSAVE (1 << 18)
+
 typedef enum {
   LongMode64Bit        = 0,
   LongModeCompat32Bit,
@@ -488,6 +490,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,
@@ -504,6 +545,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] 82+ messages in thread

* [RFC PATCH v3 12/43] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (10 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 11/43] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 13/43] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
                   ` (32 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 56f0040fff9f..578fee7deaad 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -285,6 +285,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)
@@ -553,6 +601,10 @@ DoVcCommon (
     NaeExit = IoioExit;
     break;
 
+  case SvmExitMsr:
+    NaeExit = MsrExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH v3 13/43] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (11 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 12/43] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 14/43] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
                   ` (31 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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                      | 308 +++++++++++++++++-
 1 file changed, 306 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
index 578fee7deaad..d82121c3fa1c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -86,8 +86,8 @@ typedef struct {
     UINT8  Scale;
   } Sib;
 
-  UINTN  RegData;
-  UINTN  RmData;
+  INTN  RegData;
+  INTN  RmData;
 } SEV_ES_INSTRUCTION_OPCODE_EXT;
 
 typedef struct {
@@ -159,6 +159,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 != NULL);
+
+  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 (
@@ -269,6 +461,114 @@ 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;
+
+  case 0xC6:
+    Bytes = 1;
+  case 0xC7:
+    DecodeModRm (Regs, InstructionData);
+    Bytes = (Bytes) ? Bytes
+                    : (InstructionData->DataSize == Size16Bits) ? 2
+                    : (InstructionData->DataSize == Size32Bits) ? 4
+                    : 0;
+
+    InstructionData->ImmediateSize = Bytes;
+    InstructionData->End += Bytes;
+
+    ExitInfo1 = InstructionData->Ext.RmData;
+    ExitInfo2 = Bytes;
+    CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, 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 (
@@ -605,6 +905,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitNpf:
+    NaeExit = MmioExit;
+    break;
+
   default:
     NaeExit = UnsupportedExit;
   }
-- 
2.17.1


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

* [RFC PATCH v3 14/43] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (12 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 13/43] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 15/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
                   ` (30 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 d82121c3fa1c..697d50338da0 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -585,6 +585,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 (
@@ -905,6 +923,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitWbinvd:
+    NaeExit = WbinvdExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 15/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (13 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 14/43] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 16/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
                   ` (29 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 697d50338da0..1b08a855cda0 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -895,6 +895,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,
@@ -911,6 +937,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] 82+ messages in thread

* [RFC PATCH v3 16/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (14 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 15/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 17/43] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
                   ` (28 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 1b08a855cda0..5fb3766ef138 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -895,6 +895,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 (
@@ -941,6 +970,10 @@ DoVcCommon (
     NaeExit = RdtscExit;
     break;
 
+  case SvmExitRdpmc:
+    NaeExit = RdpmcExit;
+    break;
+
   case SvmExitCpuid:
     NaeExit = CpuidExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 17/43] UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (15 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 16/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 18/43] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
                   ` (27 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 5fb3766ef138..a9dd98250c58 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -856,6 +856,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 (
@@ -978,6 +996,10 @@ DoVcCommon (
     NaeExit = CpuidExit;
     break;
 
+  case SvmExitInvd:
+    NaeExit = InvdExit;
+    break;
+
   case SvmExitIoioProt:
     NaeExit = IoioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 18/43] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (16 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 17/43] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 19/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
                   ` (26 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 a9dd98250c58..8b0192bf0a0e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -603,6 +603,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 (
@@ -1008,6 +1039,10 @@ DoVcCommon (
     NaeExit = MsrExit;
     break;
 
+  case SvmExitVmmCall:
+    NaeExit = VmmCallExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 19/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (17 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 18/43] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 20/43] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
                   ` (25 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 8b0192bf0a0e..425b1c533532 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -603,6 +603,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 (
@@ -1043,6 +1073,10 @@ DoVcCommon (
     NaeExit = VmmCallExit;
     break;
 
+  case SvmExitRdtscp:
+    NaeExit = RdtscpExit;
+    break;
+
   case SvmExitWbinvd:
     NaeExit = WbinvdExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 20/43] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (18 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 19/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 21/43] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
                   ` (24 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 425b1c533532..eeaf524467a7 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -585,6 +585,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 (
@@ -1081,6 +1108,10 @@ DoVcCommon (
     NaeExit = WbinvdExit;
     break;
 
+  case SvmExitMonitor:
+    NaeExit = MonitorExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 21/43] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (19 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 20/43] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
                   ` (23 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 eeaf524467a7..1d7c34e7e442 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -585,6 +585,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 (
@@ -1112,6 +1137,10 @@ DoVcCommon (
     NaeExit = MonitorExit;
     break;
 
+  case SvmExitMwait:
+    NaeExit = MwaitExit;
+    break;
+
   case SvmExitNpf:
     NaeExit = MmioExit;
     break;
-- 
2.17.1


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

* [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (20 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 21/43] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  6:53   ` Ni, Ray
  2019-12-12  6:53   ` Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 23/43] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
                   ` (22 subsequent siblings)
  44 siblings, 2 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 1d7c34e7e442..22393f72d795 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
@@ -13,6 +13,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,
@@ -1081,6 +1087,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,
@@ -1097,6 +1157,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 19198f273137..a0549f7ae6bd 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
@@ -225,6 +225,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
@@ -237,7 +240,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] 82+ messages in thread

* [RFC PATCH v3 23/43] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (21 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 24/43] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
                   ` (21 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
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] 82+ messages in thread

* [RFC PATCH v3 24/43] OvmfPkg: Add support to perform SEV-ES initialization
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (22 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 23/43] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
                   ` (20 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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

When SEV-ES is enabled, then SEV is also enabled. Add support to the SEV
initialization function to also check for SEV-ES being enabled, and if
enabled, set the SEV-ES enabled PCD (PcdSevEsIsEnabled).

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
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 0e17de188cd6..d9dd2db52ea6 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -568,6 +568,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index c8708c90f695..291cb6d1f603 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -580,6 +580,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|0
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes|8
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x01
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 85f817b86130..5990dab4f65e 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -579,6 +579,9 @@ [PcdsDynamicDefault]
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set SEV-ES defaults
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|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..031154389426 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -95,6 +95,7 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 2ae8126ccf8a..c12aea46d94e 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -19,6 +19,27 @@
 
 #include "Platform.h"
 
+/**
+
+  Initialize SEV-ES support if running as an SEV-ES guest.
+
+  **/
+STATIC
+VOID
+AmdSevEsInitialize (
+  VOID
+  )
+{
+  RETURN_STATUS     PcdStatus;
+
+  if (!MemEncryptSevEsIsEnabled ()) {
+    return;
+  }
+
+  PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
+  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] 82+ messages in thread

* [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (23 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 24/43] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 11:02   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
                   ` (19 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 | 261 +++++++++++++++++++++-
 OvmfPkg/ResetVector/ResetVector.nasmb     |   2 +
 3 files changed, 262 insertions(+), 3 deletions(-)

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..c902fa68d556 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -31,13 +31,52 @@ BITS    32
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
 
+;
+; SEV-ES #VC exception handler support
+;
+; #VC handler local variable locations
+;
+%define VC_CPUID_RESULT_EAX         0
+%define VC_CPUID_RESULT_EBX         4
+%define VC_CPUID_RESULT_ECX         8
+%define VC_CPUID_RESULT_EDX        12
+%define VC_GHCB_MSR_EDX            16
+%define VC_GHCB_MSR_EAX            20
+%define VC_CPUID_REQUEST_REGISTER  24
+%define VC_CPUID_FUNCTION          28
+
+; #VC handler total local variable size
+;
+%define VC_VARIABLE_SIZE           32
+
+; #VC handler GHCB CPUID request/response protocol values
+;
+%define GHCB_CPUID_REQUEST          4
+%define GHCB_CPUID_RESPONSE         5
+%define GHCB_CPUID_REGISTER_SHIFT  30
+%define CPUID_INSN_LEN              2
+
+
 ; Check if Secure Encrypted Virtualization (SEV) 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 (see SevEsIdtVmmComm for
+    ;   stack usage)
+    ;   Establish exception handlers
+    ;
+    mov       esp, SEV_ES_VC_TOP_OF_STACK
+    mov       eax, ADDR_OF(Idtr)
+    lidt      [cs:eax]
+
     ; Check if we have a valid (0x8000_001F) CPUID leaf
+    ;   CPUID raises a #VC exception if running as an SEV-ES guest
     mov       eax, 0x80000000
     cpuid
 
@@ -48,8 +87,8 @@ CheckSevFeature:
     jl        NoSev
 
     ; Check for memory encryption feature:
-    ;  CPUID  Fn8000_001F[EAX] - Bit 1
-    ;
+    ; CPUID  Fn8000_001F[EAX] - Bit 1
+    ;   CPUID raises a #VC exception if running as an SEV-ES guest
     mov       eax,  0x8000001f
     cpuid
     bt        eax, 1
@@ -73,6 +112,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 +194,210 @@ pageTableEntriesLoop:
     mov     cr3, eax
 
     OneTimeCallRet SetCr3ForPageTables64
+
+SevEsIdtNotCpuid:
+    ;
+    ; Use VMGEXIT to request termination.
+    ;   1 - #VC was not for CPUID
+    ;
+    mov     eax, 1
+    jmp     SevEsIdtTerminate
+
+SevEsIdtNoCpuidResponse:
+    ;
+    ; Use VMGEXIT to request termination.
+    ;   2 - GHCB_CPUID_RESPONSE not received
+    ;
+    mov     eax, 2
+
+SevEsIdtTerminate:
+    ;
+    ; Use VMGEXIT to request termination. At this point the reason code is
+    ; located in EAX, so shift it left 16 bits to the proper location.
+    ;
+    ; EAX[11:0]  => 0x100 - request termination
+    ; EAX[15:12] => 0x1   - OVMF
+    ; EAX[23:16] => 0xXX  - REASON CODE
+    ;
+    shl     eax, 16
+    or      eax, 0x1100
+    xor     edx, edx
+    mov     ecx, 0xc0010130
+    wrmsr
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+    ;
+    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
+    ;
+SevEsIdtHlt:
+    hlt
+    jmp     SevEsIdtHlt
+    iret
+
+    ;
+    ; Total stack usage for the #VC handler is 44 bytes:
+    ;   - 12 bytes for the exception IRET (after popping error code)
+    ;   - 32 bytes for the local variables.
+    ;
+SevEsIdtVmmComm:
+    ;
+    ; If we're here, then we are an SEV-ES guest and this
+    ; was triggered by a CPUID instruction
+    ;
+    pop     ecx                     ; Error code
+    cmp     ecx, 0x72               ; Be sure it was CPUID
+    jne     SevEsIdtNotCpuid
+
+    ; Set up local variable room on the stack
+    ;   CPUID function         : + 28
+    ;   CPUID request register : + 24
+    ;   GHCB MSR (EAX)         : + 20
+    ;   GHCB MSR (EDX)         : + 16
+    ;   CPUID result (EDX)     : + 12
+    ;   CPUID result (ECX)     : + 8
+    ;   CPUID result (EBX)     : + 4
+    ;   CPUID result (EAX)     : + 0
+    sub     esp, VC_VARIABLE_SIZE
+
+    ; Save the CPUID function being requested
+    mov     [esp + VC_CPUID_FUNCTION], eax
+
+    ; The GHCB CPUID protocol uses the following mapping to request
+    ; a specific register:
+    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
+    ;
+    ; Set EAX as the first register to request. This will also be used as a
+    ; loop variable to request all register values (EAX to EDX).
+    xor     eax, eax
+    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
+
+    ; Save current GHCB MSR value
+    mov     ecx, 0xc0010130
+    rdmsr
+    mov     [esp + VC_GHCB_MSR_EAX], eax
+    mov     [esp + VC_GHCB_MSR_EDX], edx
+
+NextReg:
+    ;
+    ; Setup GHCB MSR
+    ;   GHCB_MSR[63:32] = CPUID function
+    ;   GHCB_MSR[31:30] = CPUID register
+    ;   GHCB_MSR[11:0]  = CPUID request protocol
+    ;
+    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
+    cmp     eax, 4
+    jge     VmmDone
+
+    shl     eax, GHCB_CPUID_REGISTER_SHIFT
+    or      eax, GHCB_CPUID_REQUEST
+    mov     edx, [esp + VC_CPUID_FUNCTION]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+    ;
+    ; Read GHCB MSR
+    ;   GHCB_MSR[63:32] = CPUID register value
+    ;   GHCB_MSR[31:30] = CPUID register
+    ;   GHCB_MSR[11:0]  = CPUID response protocol
+    ;
+    mov     ecx, 0xc0010130
+    rdmsr
+    mov     ecx, eax
+    and     ecx, 0xfff
+    cmp     ecx, GHCB_CPUID_RESPONSE
+    jne     SevEsIdtNoCpuidResponse
+
+    ; Save returned value
+    shr     eax, GHCB_CPUID_REGISTER_SHIFT
+    mov     [esp + eax * 4], edx
+
+    ; Next register
+    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
+
+    jmp     NextReg
+
+VmmDone:
+    ;
+    ; At this point we have all CPUID register values. Restore the GHCB MSR,
+    ; set the return register values and return.
+    ;
+    mov     eax, [esp + VC_GHCB_MSR_EAX]
+    mov     edx, [esp + VC_GHCB_MSR_EDX]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    mov     eax, [esp + VC_CPUID_RESULT_EAX]
+    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
+    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
+    mov     edx, [esp + VC_CPUID_RESULT_EDX]
+
+    add     esp, VC_VARIABLE_SIZE
+
+    ; Update the EIP value to skip over the now handled CPUID instruction
+    ; (the CPUID instruction has a length of 2)
+    add     word [esp], CPUID_INSN_LEN
+    iret
+
+ALIGN   2
+
+Idtr:
+    dw      IDT_END - IDT_BASE - 1  ; Limit
+    dd      ADDR_OF(IDT_BASE)       ; Base
+
+IdtrClear:
+    dw      0                       ; Limit
+    dd      0                       ; Base
+
+ALIGN   16
+
+;
+; The Interrupt Descriptor Table (IDT)
+;   This will be used to determine if SEV-ES is enabled.  Upon execution
+;   of the CPUID instruction, a VMM Communication Exception will occur.
+;   This will tell us if SEV-ES is enabled.  We can use the current value
+;   of the GHCB MSR to determine the SEV attributes.
+;
+IDT_BASE:
+;
+; Vectors 0 - 28 (No handlers)
+;
+%rep 29
+    dw      0                                    ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      0                                    ; Offset high bits 31..16
+%endrep
+;
+; Vector 29 (VMM Communication Exception)
+;
+    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
+;
+; Vectors 30 - 31 (No handlers)
+;
+%rep 2
+    dw      0                                    ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      0                                    ; Offset high bits 31..16
+%endrep
+IDT_END:
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 75cfe16654b1..579c75f5ba0c 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -55,6 +55,8 @@
 
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 %include "Ia32/Flat32ToFlat64.asm"
+
+  %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/PageTables64.asm"
 %endif
 
-- 
2.17.1


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

* [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (24 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 11:29   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 27/43] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
                   ` (18 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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 #VC exception handler routines assume that a per-CPU
variable area is immediately after the GHCB, this per-CPU variable area
must also 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 and per-CPU variable pages. After breaking down
the 2MB page, update the GHCB page table entry to remove the encryption
mask.

The GHCB page will be used by the SEC #VC exception handler. The #VC
exception handler will fill in the necessary fields of the GHCB and exit
to the hypervisor using the VMGEXIT instruction. The hypervisor then
accesses the GHCB in order to perform the requested function.

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                       |  5 ++
 OvmfPkg/OvmfPkgX64.fdf                    |  6 ++
 OvmfPkg/ResetVector/ResetVector.inf       |  5 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm | 76 +++++++++++++++++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb     | 16 +++++
 5 files changed, 108 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index d5fee805ef4a..19723786d729 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -228,6 +228,11 @@ [PcdsFixedAtBuild]
   ## Number of page frames to use for storing grant table entries.
   gUefiOvmfPkgTokenSpaceGuid.PcdXenGrantFrames|4|UINT32|0x33
 
+  ## 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|0x34
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|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 e49adc425fce..973b19fdbf19 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|0x002000
+gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 960b47cd0797..266c5fc5c8b3 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -26,6 +26,7 @@ [Sources]
 [Packages]
   OvmfPkg/OvmfPkg.dec
   MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [BuildOptions]
@@ -33,7 +34,11 @@ [BuildOptions]
    *_*_X64_NASMB_FLAGS = -I$(WORKSPACE)/UefiCpuPkg/ResetVector/Vtf0/
 
 [Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index c902fa68d556..b064ca65b88d 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 + \
@@ -123,6 +128,37 @@ SevExit:
 
     OneTimeCallRet CheckSevFeature
 
+; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
+; is enabled.
+;
+; Modified:  EAX, EBX, ECX
+;
+; 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
 ;
@@ -187,6 +223,46 @@ 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 GHCB_BASE and needs to be un-encrypted.
+    ; This requires the 2MB page for this range be broken down into 512 4KB
+    ; pages.  All will be marked encrypted, except for the GHCB.
+    ;
+    mov     ecx, (GHCB_BASE >> 21)
+    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
+
+    ;
+    ; Page Table Entries (512 * 4KB entries => 2MB)
+    ;
+    mov     ecx, 512
+pageTableEntries4kLoop:
+    mov     eax, ecx
+    dec     eax
+    shl     eax, 12
+    add     eax, GHCB_BASE & 0xFFE0_0000
+    add     eax, PAGE_4K_PDE_ATTR
+    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
+    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
+    loop    pageTableEntries4kLoop
+
+    ;
+    ; Clear the encryption bit from the GHCB entry
+    ;
+    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
+    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
+
+    mov     ecx, GHCB_SIZE / 4
+    xor     eax, eax
+clearGhcbMemoryLoop:
+    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
+    loop    clearGhcbMemoryLoop
+
+SetCr3:
     ;
     ; Set CR3 now that the paging structures are available
     ;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 579c75f5ba0c..708bbda6208f 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -53,9 +53,25 @@
     %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
   %endif
 
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
+    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
+  %endif
+
+  %if (FixedPcdGet32 (PcdSecGhcbSize) != 0x2000)
+    %error "This implementation inherently depends on PcdSecGhcbSize"
+  %endif
+
+  %if ((FixedPcdGet32 (PcdSecGhcbBase) >> 21) != \
+       ((FixedPcdGet32 (PcdSecGhcbBase) + FixedPcdGet32 (PcdSecGhcbSize) - 1) >> 21))
+    %error "This implementation inherently depends on PcdSecGhcbBase not straddling a 2MB boundary"
+  %endif
+
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 %include "Ia32/Flat32ToFlat64.asm"
 
+  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
+  %define GHCB_BASE (FixedPcdGet32 (PcdSecGhcbBase))
+  %define GHCB_SIZE (FixedPcdGet32 (PcdSecGhcbSize))
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 %include "Ia32/PageTables64.asm"
 %endif
-- 
2.17.1


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

* [RFC PATCH v3 27/43] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (25 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
                   ` (17 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Anthony Perard,
	Julien Grall

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 ranges with an AcpiNVS
  memory allocation HOB, in PEI.

  If S3 is disabled, then these ranges are 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 PcdOvmfSecGhcbPageTableBase. PEI switches to GHCB pages in
  permanent PEI memory and DXE will use these PEI GHCB pages, so we don't
  have to preserve PcdOvmfSecGhcbBase.

(c) how it is protected from the OS

  If S3 is enabled, then (b) 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 (a), which is fine because (b) reserved it.

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

  It is rewritten same as in (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>
Reviewed-by: Laszlo Ersek <lersek@redhat.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 031154389426..920b619446f0 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -72,6 +72,8 @@ [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
@@ -96,6 +98,8 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d451989f31c9..677e65e86d7b 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -26,6 +26,7 @@ Module Name:
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
 #include <Library/IoLib.h>
+#include <Library/MemEncryptSevLib.h>
 #include <Library/PcdLib.h>
 #include <Library/PciLib.h>
 #include <Library/PeimEntryPoint.h>
@@ -805,6 +806,28 @@ InitializeRamRegions (
       (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
       EfiACPIMemoryNVS
       );
+
+    if (MemEncryptSevEsIsEnabled ()) {
+      //
+      // If SEV-ES is enabled, 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 (PcdSecGhcbBase),
+        (UINT64)(UINTN) PcdGet32 (PcdSecGhcbSize),
+        EfiACPIMemoryNVS
+        );
+    }
 #endif
   }
 
-- 
2.17.1


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

* [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (26 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 27/43] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  6:54   ` Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 29/43] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
                   ` (16 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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

Allocate memory for the GHCB pages and the per-CPU variable 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).

The per-CPU variable page needs to be unique per 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.

The GHCB pages (one per vCPU) will be used by the PEI and DXE #VC
exception handlers. The #VC exception handler will fill in the necessary
fields of the GHCB and exit to the hypervisor using the VMGEXIT
instruction. The hypervisor then accesses the GHCB associated with the
vCPU in order to perform the requested function.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
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        | 38 ++++++++++++++++++++++++++++-
 5 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index d9dd2db52ea6..56670eefde6b 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -570,6 +570,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|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 291cb6d1f603..9897e6889573 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -582,6 +582,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|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 5990dab4f65e..59c4f9207fc3 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -581,6 +581,8 @@ [PcdsDynamicDefault]
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|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 920b619446f0..25bb59d161de 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -100,6 +100,8 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index c12aea46d94e..900b0d977d61 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -9,12 +9,15 @@
 //
 // The package level header files this module uses
 //
+#include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
 #include <Library/MemEncryptSevLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/PcdLib.h>
 #include <PiPei.h>
 #include <Register/Amd/Cpuid.h>
+#include <Register/Amd/Msr.h>
 #include <Register/Cpuid.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,36 @@ AmdSevEsInitialize (
 
   PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
   ASSERT_RETURN_ERROR (PcdStatus);
+
+  //
+  // Allocate GHCB and per-CPU variable pages.
+  //
+  GhcbPageCount = mMaxCpuCount * 2;
+  GhcbBase = AllocatePages (GhcbPageCount);
+  ASSERT (GhcbBase != NULL);
+
+  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
+
+  DecryptStatus = MemEncryptSevClearPageEncMask (
+    0,
+    GhcbBasePa,
+    GhcbPageCount,
+    TRUE
+    );
+  ASSERT_RETURN_ERROR (DecryptStatus);
+
+  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
+
+  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  DEBUG ((DEBUG_INFO,
+    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
+    (UINT64)GhcbPageCount, GhcbBase));
+
+  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
 }
 
 /**
-- 
2.17.1


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

* [RFC PATCH v3 29/43] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (27 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
                   ` (15 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/PlatformPei/AmdSev.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index 900b0d977d61..b3fd2d86541a 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;
@@ -74,6 +76,22 @@ AmdSevEsInitialize (
     (UINT64)GhcbPageCount, GhcbBase));
 
   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
+
+  //
+  // 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 was created before the C-bit
+  // was cleared (encrypted). This will result in a failure to be able to
+  // handle the exception.
+  //
+  AsmReadGdtr (&Gdtr);
+
+  Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN) Gdtr.Limit + 1));
+  ASSERT (Gdt != NULL);
+
+  CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
+  Gdtr.Base = (UINTN) Gdt;
+  AsmWriteGdtr (&Gdtr);
 }
 
 /**
-- 
2.17.1


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

* [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (28 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 29/43] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 12:06   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
                   ` (14 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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.

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 bae9764577f0..db319030ee58 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] 82+ messages in thread

* [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (29 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 12:08   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled Lendacky, Thomas
                   ` (13 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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.c | 45 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index db319030ee58..53c850134897 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -25,6 +25,9 @@
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
+#include <Register/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+#include <Register/Amd/Fam17Msr.h>
 
 #include <Ppi/TemporaryRamSupport.h>
 
@@ -713,6 +716,39 @@ FindAndReportEntryPoints (
   return;
 }
 
+STATIC
+BOOLEAN
+SevEsIsEnabled (
+  VOID
+  )
+{
+  UINT32                            RegEax;
+  CPUID_MEMORY_ENCRYPTION_INFO_EAX  Eax;
+  MSR_SEV_STATUS_REGISTER           Msr;
+
+  //
+  // Check if the memory encryption leaf exist
+  //
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
+  if (RegEax >= CPUID_MEMORY_ENCRYPTION_INFO) {
+    //
+    // CPUID Fn8000_001F[EAX] Bit 1 (Sev supported)
+    //
+    AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, &Eax.Uint32, NULL, NULL, NULL);
+    if (Eax.Bits.SevBit && Eax.Bits.SevEsBit) {
+      //
+      // Check MSR_0xC0010131 Bit 1 (Sev-Es Enabled)
+      //
+      Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
+      if (Msr.Bits.SevEsBit) {
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
 VOID
 EFIAPI
 SecCoreStartupWithStack (
@@ -755,6 +791,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 (SevEsIsEnabled()) {
+    AsmEnableCache ();
+  }
+
   DEBUG ((EFI_D_INFO,
     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
     (UINT32)(UINTN)BootFv,
-- 
2.17.1


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

* [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (30 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 12:31   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:06 ` [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
                   ` (12 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

The flash detection routine will attempt to determine how the flash
device behaves (e.g. ROM, RAM, Flash). But when SEV-ES is enabled and
the flash device behaves as a ROM device (meaning it is marked read-only
by the hypervisor), this check may result in an infinite nested page fault
because of the attempted write. Since the instruction cannot be emulated
when SEV-ES is enabled, the RIP is never advanced, resulting in repeated
nested page faults.

When SEV-ES is enabled, exit the flash detection early and assume that
the FD behaves as Flash. This will result in QemuFlashWrite() being called
to store EFI variables, which will also result in an infinite nested page
fault when the write is performed. In this case, update QemuFlashWrite()
to use the VmgMmioWrite function from the VmgExitLib library to have the
hypervisor perform the write without having to emulate the instruction.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/OvmfPkgIa32.dsc                       |  1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  1 +
 OvmfPkg/OvmfPkgX64.dsc                        |  1 +
 .../FvbServicesRuntimeDxe.inf                 |  2 +
 .../QemuFlash.c                               | 38 +++++++++++++++++--
 5 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 56670eefde6b..ff2814c6246e 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -320,6 +320,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.UEFI_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 9897e6889573..212952cfaacd 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.UEFI_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 59c4f9207fc3..8331fc0b663e 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
 
 [LibraryClasses.common.UEFI_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
index ca6326e833ed..0b7741ac07f8 100644
--- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
+++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
@@ -38,6 +38,7 @@ [Sources]
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
@@ -52,6 +53,7 @@ [LibraryClasses]
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiRuntimeLib
+  VmgExitLib
 
 [Guids]
   gEfiEventVirtualAddressChangeGuid   # ALWAYS_CONSUMED
diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
index c81c58972bf2..4f3bf690fcad 100644
--- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
+++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
@@ -9,7 +9,9 @@
 
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/MemEncryptSevLib.h>
 #include <Library/PcdLib.h>
+#include <Library/VmgExitLib.h>
 
 #include "QemuFlash.h"
 
@@ -80,6 +82,20 @@ QemuFlashDetected (
 
   DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
 
+  if (MemEncryptSevEsIsEnabled()) {
+    //
+    // When SEV-ES is enabled, the check below can result in an infinite
+    // loop with respect to a nested page fault. When the FD behaves as
+    // a ROM, the nested page table entry is read-only. The check below
+    // will cause a nested page fault that cannot be emulated, causing
+    // the instruction to retried over and over. For SEV-ES, assume that
+    // the FD does not behave as FLASH.
+    //
+    DEBUG ((DEBUG_INFO,
+      "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"));
+    return TRUE;
+  }
+
   OriginalUint8 = *Ptr;
   *Ptr = CLEAR_STATUS_CMD;
   ProbeUint8 = *Ptr;
@@ -147,6 +163,21 @@ QemuFlashRead (
 }
 
 
+STATIC
+VOID
+QemuFlashPtrWrite (
+  IN        volatile UINT8                      *Ptr,
+  IN        UINT8                               Value
+  )
+{
+  if (MemEncryptSevEsIsEnabled()) {
+    VmgMmioWrite ((UINT8 *) Ptr, &Value, 1);
+  } else {
+    *Ptr = Value;
+  }
+}
+
+
 /**
   Write to QEMU Flash
 
@@ -181,8 +212,9 @@ QemuFlashWrite (
   //
   Ptr = QemuFlashPtr (Lba, Offset);
   for (Loop = 0; Loop < *NumBytes; Loop++) {
-    *Ptr = WRITE_BYTE_CMD;
-    *Ptr = Buffer[Loop];
+    QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
+    QemuFlashPtrWrite (Ptr, Buffer[Loop]);
+
     Ptr++;
   }
 
@@ -190,7 +222,7 @@ QemuFlashWrite (
   // Restore flash to read mode
   //
   if (*NumBytes > 0) {
-    *(Ptr - 1) = READ_ARRAY_CMD;
+    QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
   }
 
   return EFI_SUCCESS;
-- 
2.17.1


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

* [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (31 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  6:57   ` Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 34/43] UefiCpuPkg: Add " Lendacky, Thomas
                   ` (11 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh, Jian J Wang,
	Hao A Wu, Dandan Bi

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 284b34818ca7..c9cf2e36214f 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] 82+ messages in thread

* [RFC PATCH v3 34/43] UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (32 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
                   ` (10 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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] 82+ messages in thread

* [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (33 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 34/43] UefiCpuPkg: Add " Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-12-12  7:01   ` Ni, Ray
  2019-11-20 20:06 ` [RFC PATCH v3 36/43] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
                   ` (9 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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
enabled. This new field is set during MP library initialization with the
PCD value PcdSevEsIsEnabled. This flag can then be used to determine if
SEV-ES is enabled.

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 cd912ab0c5ee..f84dbb09ae49 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -69,4 +69,5 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 1538185ef99a..9c1215ec75d0 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -60,6 +60,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 8fa07b12c5e1..c10fe894cf9b 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -259,6 +259,8 @@ struct _CPU_MP_DATA {
   // driver.
   //
   BOOLEAN                        WakeUpByInitSipiSipi;
+
+  BOOLEAN                        SevEsIsEnabled;
 };
 
 extern EFI_GUID mCpuInitMpLibHobGuid;
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 49be5d5385d9..aa25bf9b3671 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1708,6 +1708,7 @@ MpInitLibInitialize (
     CpuMpData->MicrocodePatchAddress    = OldCpuMpData->MicrocodePatchAddress;
   }
   InitializeSpinLock(&CpuMpData->MpLock);
+  CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
 
   //
   // Make sure no memory usage outside of the allocated buffer.
-- 
2.17.1


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

* [RFC PATCH v3 36/43] UefiCpuPkg: Allow AP booting under SEV-ES
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (34 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-20 20:06 ` [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector Lendacky, Thomas
                   ` (8 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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, the firmware will provide a build time reserved area
 that can be used as the initial IP value. The hypervisor can extract this
 location value by checking for the SEV-ES reset block GUID that must be
 located 48-bytes from the end of the firmware. The format of the SEV-ES
 reset block area is:

   0x00 - 0x01 - SEV-ES Reset IP
   0x02 - 0x03 - SEV-ES Reset CS
   0x04 - 0x05 - Size of the SEV-ES reset block
   0x06 - 0x15 - SEV-ES Reset Block GUID
                   (00f771de-1a7e-4fcb-890e-68c77e2fb44e)

   The total size is 22 bytes. Any expansion to this block must be done
   by adding new values before existing values.

 The hypervisor will use the IP and CS values obtained from the SEV-ES
 reset block to set as the AP's initial values.

 Before booting the AP for the first time, the BSP must initialize the
 SEV-ES reset area. This consists of programming a FAR JMP instruction
 to the contents of a memory location that is also located in the SEV-ES
 reset area. The BSP must program the IP and CS values for the FAR JMP
 based on values drived 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 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/UefiCpuPkg.dec                     |   5 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |  60 ++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  70 ++++-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          | 256 +++++++++++++++++-
 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 ++++++++++++++++
 12 files changed, 664 insertions(+), 14 deletions(-)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 90feb9166dc8..d09cba9b2abc 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -151,6 +151,11 @@ [PcdsFixedAtBuild]
   # @Prompt Specify size of good stack of exception which need switching stack.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize|2048|UINT32|0x30002001
 
+  ## Area of memory where the SEV-ES AP reset block lives.
+  # @Prompt Configure the SEV-ES reset block base
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase|0x0|UINT32|0x30002002
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize|0x0|UINT32|0x30002003
+
 [PcdsFixedAtBuild, PcdsPatchableInModule]
   ## This value is the CPU Local APIC base address, which aligns the address on a 4-KByte boundary.
   # @Prompt Configure base address of CPU Local APIC
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index f84dbb09ae49..7b449fb8cfe3 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
@@ -68,6 +69,8 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 9c1215ec75d0..af29f33a156e 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,7 +61,9 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
 
 [Guids]
   gEdkiiS3SmmInitDoneGuid
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index c10fe894cf9b..445ec2e950a9 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               SevEsIsEnabled;
+  UINTN                 GhcbBase;
 } MP_CPU_EXCHANGE_INFO;
 
 #pragma pack()
@@ -235,6 +242,7 @@ struct _CPU_MP_DATA {
   UINT8                          ApLoopMode;
   UINT8                          ApTargetCState;
   UINT16                         PmCodeSegment;
+  UINT16                         Pm16CodeSegment;
   CPU_AP_DATA                    *CpuData;
   volatile MP_CPU_EXCHANGE_INFO  *MpCpuExchangeInfo;
 
@@ -261,8 +269,47 @@ struct _CPU_MP_DATA {
   BOOLEAN                        WakeUpByInitSipiSipi;
 
   BOOLEAN                        SevEsIsEnabled;
+  UINTN                          SevEsAPBuffer;
+  UINTN                          SevEsAPResetStackStart;
+  CPU_MP_DATA                    *NewCpuMpData;
+
+  UINT64                         GhcbBase;
 };
 
+#define AP_RESET_STACK_SIZE 64
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8   InsnBuffer[8];
+  UINT16  Rip;
+  UINT16  Segment;
+} SEV_ES_AP_JMP_FAR;
+
+#pragma pack()
+
+/**
+  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;
 
 /**
@@ -368,6 +415,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 aa25bf9b3671..817fbe85dd7d 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 (PcdSevEsIsEnabled)) {
+      //
+      // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
+      // protocol for starting APs
+      //
+      ApLoopMode = ApInHltLoop;
+    }
   }
 
   if (ApLoopMode != ApInMwaitLoop) {
@@ -563,6 +574,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.
 
@@ -722,7 +835,28 @@ ApWakeupFunction (
       //
       while (TRUE) {
         DisableInterrupts ();
-        CpuSleep ();
+        if (CpuMpData->SevEsIsEnabled) {
+          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 ();
       }
     }
@@ -835,6 +969,9 @@ FillExchangeInfoData (
   ExchangeInfo->Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
   DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
 
+  ExchangeInfo->SevEsIsEnabled  = CpuMpData->SevEsIsEnabled;
+  ExchangeInfo->GhcbBase        = CpuMpData->GhcbBase;
+
   //
   // Get the BSP's data of GDT and IDT
   //
@@ -861,8 +998,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 +
@@ -915,7 +1053,8 @@ BackupAndPrepareWakeupBuffer(
   CopyMem (
     (VOID *) CpuMpData->WakeupBuffer,
     (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
-    CpuMpData->AddressMap.RendezvousFunnelSize
+    CpuMpData->AddressMap.RendezvousFunnelSize +
+      CpuMpData->AddressMap.SwitchToRealSize
     );
 }
 
@@ -936,6 +1075,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.
 
@@ -949,16 +1122,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);
 }
@@ -973,7 +1152,31 @@ FreeResetVector (
   IN CPU_MP_DATA              *CpuMpData
   )
 {
-  RestoreWakeupBuffer (CpuMpData);
+  //
+  // If SEV-ES is enabled, 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->SevEsIsEnabled) {
+    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->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
+  }
 }
 
 /**
@@ -1010,6 +1213,7 @@ WakeUpAP (
       CpuMpData->InitFlag   != ApInitDone) {
     ResetVectorRequired = TRUE;
     AllocateResetVector (CpuMpData);
+    AllocateSevEsAPMemory (CpuMpData);
     FillExchangeInfoData (CpuMpData);
     SaveLocalApicTimerSetting (CpuMpData);
   }
@@ -1046,6 +1250,35 @@ WakeUpAP (
       }
     }
     if (ResetVectorRequired) {
+      //
+      // For SEV-ES, the initial AP boot address will be defined by
+      // PcdSevEsResetRipBase. The Segment/Rip must be the jump address
+      // from the original INIT-SIPI-SIPI.
+      //
+      if (CpuMpData->SevEsIsEnabled) {
+        SEV_ES_AP_JMP_FAR *JmpFar;
+        UINT32            Offset, InsnByte;
+        UINT8             LoNib, HiNib;
+
+        JmpFar = (SEV_ES_AP_JMP_FAR *) FixedPcdGet32 (PcdSevEsResetRipBase);
+        ASSERT (JmpFar != NULL);
+
+        Offset = FixedPcdGet32 (PcdSevEsResetRipBase);
+        Offset += sizeof(JmpFar->InsnBuffer);
+        LoNib = (UINT8) Offset;
+        HiNib = (UINT8) (Offset >> 8);
+
+        // JMP FAR [CS:XXYY] => 2E FF 2E YY XX
+        InsnByte = 0;
+        JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // CS override prefix
+        JmpFar->InsnBuffer[InsnByte++] = 0xFF;  // JMP (FAR)
+        JmpFar->InsnBuffer[InsnByte++] = 0x2E;  // ModRM (JMP memory location)
+        JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...
+        JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...
+
+        JmpFar->Rip = 0;
+        JmpFar->Segment = (UINT16) (ExchangeInfo->BufferStart >> 4);
+      }
       //
       // Wakeup all APs
       //
@@ -1614,7 +1847,7 @@ MpInitLibInitialize (
   ASSERT (MaxLogicalProcessorNumber != 0);
 
   AsmGetAddressMap (&AddressMap);
-  ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+  ApResetVectorSize = GetApResetVectorSize (&AddressMap);
   ApStackSize = PcdGet32(PcdCpuApStackSize);
   ApLoopMode  = GetApLoopMode (&MonitorFilterSize);
 
@@ -1709,6 +1942,8 @@ MpInitLibInitialize (
   }
   InitializeSpinLock(&CpuMpData->MpLock);
   CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+  CpuMpData->SevEsAPBuffer  = (UINTN) -1;
+  CpuMpData->GhcbBase       = PcdGet64 (PcdGhcbBase);
 
   //
   // Make sure no memory usage outside of the allocated buffer.
@@ -1775,6 +2010,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..c92daaaffd6b 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
+SevEsIsEnabledLocation              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..6956b408d004 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 + SevEsIsEnabledLocation]
+    cmp        byte [edi], 1        ; SevEsIsEnabled
+    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 + SevEsIsEnabledLocation]
+    cmp        byte [edi], 1        ; SevEsIsEnabled
+    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] 82+ messages in thread

* [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (35 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 36/43] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
@ 2019-11-20 20:06 ` Lendacky, Thomas
  2019-11-21 19:27   ` [edk2-devel] " Laszlo Ersek
  2019-11-20 20:07 ` [RFC PATCH v3 38/43] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
                   ` (7 subsequent siblings)
  44 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:06 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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

Reserve a fixed area of memory for the SEV-ES AP reset vector and set
the fixed PCD, PcdSevEsResetRipBase, to this value.

A hypervisor is not allowed to update an SEV-ES guest's 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.

This new reset vector code is used in place of the original code because
of the include path order set in OvmfPkg/ResetVector/ResetVector.inf
under "[BuildOptions]".

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                       |  3 +
 OvmfPkg/ResetVector/ResetVector.inf          |  2 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 94 ++++++++++++++++++++
 OvmfPkg/ResetVector/ResetVector.nasmb        |  1 +
 4 files changed, 100 insertions(+)
 create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm

diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 973b19fdbf19..b7618b376430 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -82,6 +82,9 @@ [FD.MEMFD]
 0x009000|0x002000
 gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
 
+0x00B000|0x001000
+gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize
+
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
 
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index 266c5fc5c8b3..284f03c4fb1e 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -36,6 +36,8 @@ [BuildOptions]
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
   gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
new file mode 100644
index 000000000000..2a3c9bafb451
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -0,0 +1,94 @@
+;------------------------------------------------------------------------------
+; @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>
+; 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
+;
+; sevEsResetBlock:
+;   For the initial boot of an AP under SEV-ES, the "reset" RIP must be
+;   programmed to the RAM area defined by SEV_ES_RESET_IP. A known offset
+;   and GUID will be used to locate this block in the firmware and extract
+;   the build time RIP value. The GUID must always be 48 bytes from the
+;   end of the firmware.
+;
+;   0xffffffca (-0x36) - IP value
+;   0xffffffcc (-0x34) - CS selector value
+;   0xffffffce (-0x32) - Size of SEV-ES reset block
+;   0xffffffd0 (-0x30) - SEV-ES reset block GUID
+;                        (00f771de-1a7e-4fcb-890e-68c77e2fb44e)
+;
+
+TIMES (32 - (sevEsResetBlockEnd - sevEsResetBlockStart)) DB 0
+
+sevEsResetBlockStart:
+    DD      SEV_ES_RESET_IP
+    DW      sevEsResetBlockEnd - sevEsResetBlockStart
+    DB      0xDE, 0x71, 0xF7, 0x00, 0x7E, 0x1A, 0xCB, 0x4F
+    DB      0x89, 0x0E, 0x68, 0xC7, 0x7E, 0x2F, 0xB4, 0x4E
+sevEsResetBlockEnd:
+
+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
+;
+    nop
+    nop
+    jmp     EarlyBspInitReal16
+
+ALIGN   16
+
+fourGigabytes:
+
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 708bbda6208f..2bf14681099e 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -81,5 +81,6 @@
 
 %include "Main.asm"
 
+  %define SEV_ES_RESET_IP  FixedPcdGet32 (PcdSevEsResetRipBase)
 %include "Ia16/ResetVectorVtf0.asm"
 
-- 
2.17.1


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

* [RFC PATCH v3 38/43] OvmfPkg: Move the GHCB allocations into reserved memory
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (36 preceding siblings ...)
  2019-11-20 20:06 ` [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector Lendacky, Thomas
@ 2019-11-20 20:07 ` Lendacky, Thomas
  2019-11-20 20:07 ` [RFC PATCH v3 39/43] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
                   ` (6 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:07 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
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 b3fd2d86541a..84b337325d5c 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -49,9 +49,11 @@ AmdSevEsInitialize (
 
   //
   // Allocate GHCB and per-CPU variable 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 != NULL);
 
   GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
-- 
2.17.1


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

* [RFC PATCH v3 39/43] MdePkg: Add a finalization function to the CPU protocol
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (37 preceding siblings ...)
  2019-11-20 20:07 ` [RFC PATCH v3 38/43] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
@ 2019-11-20 20:07 ` Lendacky, Thomas
  2019-11-20 21:32 ` [RFC PATCH v3 40/43] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
                   ` (5 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 20:07 UTC (permalink / raw)
  To: devel
  Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel, Michael D Kinney,
	Liming Gao, Eric Dong, Ray Ni, Brijesh Singh

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] 82+ messages in thread

* [RFC PATCH v3 40/43] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (38 preceding siblings ...)
  2019-11-20 20:07 ` [RFC PATCH v3 39/43] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
@ 2019-11-20 21:32 ` Lendacky, Thomas
  2019-11-20 21:32 ` [RFC PATCH v3 41/43] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
                   ` (4 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 21:32 UTC (permalink / raw)
  To: devel

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 445ec2e950a9..22cf798c017d 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -655,5 +655,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 817fbe85dd7d..63df349b0c92 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1800,6 +1800,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] 82+ messages in thread

* [RFC PATCH v3 41/43] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (39 preceding siblings ...)
  2019-11-20 21:32 ` [RFC PATCH v3 40/43] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
@ 2019-11-20 21:32 ` Lendacky, Thomas
  2019-11-20 21:32 ` [RFC PATCH v3 42/43] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
                   ` (3 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 21:32 UTC (permalink / raw)
  To: devel

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 | 131 ++++++++++++++++--
 3 files changed, 173 insertions(+), 20 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 22cf798c017d..8efec7599546 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -276,7 +276,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
 
 #pragma pack(1)
 
@@ -332,8 +333,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..89165560fe22 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 (PcdSevEsIsEnabled)) {
+    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->SevEsIsEnabled) {
+    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->SevEsIsEnabled) {
+    //
+    // 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 6956b408d004..3b8ec477b8b3 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,50 @@ 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 enabled, use VMGEXIT (GHCB information already
+    ; set by caller)
+    ;
+BITS 64
+    rep        vmmcall
+BITS 32
+
+    ;
+    ; 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] 82+ messages in thread

* [RFC PATCH v3 42/43] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (40 preceding siblings ...)
  2019-11-20 21:32 ` [RFC PATCH v3 41/43] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
@ 2019-11-20 21:32 ` Lendacky, Thomas
  2019-11-20 21:32 ` [RFC PATCH v3 43/43] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
                   ` (2 subsequent siblings)
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 21:32 UTC (permalink / raw)
  To: devel

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] 82+ messages in thread

* [RFC PATCH v3 43/43] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (41 preceding siblings ...)
  2019-11-20 21:32 ` [RFC PATCH v3 42/43] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
@ 2019-11-20 21:32 ` Lendacky, Thomas
  2019-11-21  1:53 ` [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support Nate DeSimone
  2019-11-21  9:45 ` Laszlo Ersek
  44 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-20 21:32 UTC (permalink / raw)
  To: devel

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 they 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] 82+ messages in thread

* Re: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (42 preceding siblings ...)
  2019-11-20 21:32 ` [RFC PATCH v3 43/43] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
@ 2019-11-21  1:53 ` Nate DeSimone
  2019-11-21 15:50   ` Lendacky, Thomas
  2019-11-21  9:45 ` Laszlo Ersek
  44 siblings, 1 reply; 82+ messages in thread
From: Nate DeSimone @ 2019-11-21  1:53 UTC (permalink / raw)
  To: devel@edk2.groups.io, thomas.lendacky@amd.com
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Ni, Ray, Brijesh Singh, You, Benjamin,
	Bi, Dandan, Dong, Guo, Wu, Hao A, Wang, Jian J, Ma, Maurice

Hi Tom,

EFI_CPU_ARCH_PROTOCOL is a PI spec defined protocol. Please see Volume 2, Section 12.3 of the UEFI Platform Initialization Specification. Generally we strictly adhere to the spec when a PPI or protocol is spec defined. If not already done, I would recommend submitting a spec change request with the UEFI Forum. I don't think we can merge the patch series as-is without your change being ratified by the UEFI Forum.

Another option would be to define a separate protocol with the EDKII_ prefix instead of the EFI_ prefix as the EFI_ prefix is exclusively reserved for PPIs and protocols that are defined by either the UEFI spec or the PI spec. In which case, the protocol would need to be moved to either MdeModulePkg or UefiCpuPkg, as only spec defined PPIs and protocols are allowed in MdePkg.

Regards,
Nate

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lendacky, Thomas
Sent: Wednesday, November 20, 2019 12:06 PM
To: devel@edk2.groups.io
Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Brijesh Singh <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: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support

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:
cc6854506c2b ("Readme.md: remove positional references from submodule description")

Proper execution of SEV-ES relies on Bugzilla 2340 being fixed.

A version of the tree (with an extra patch to workaround Bugzilla 2340) can be found at:
https://github.com/AMDESE/ovmf/tree/sev-es-v9

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 v2:
- Added a way to locate the SEV-ES fixed AP RIP address for starting
  AP's to avoid updating the actual flash image (build time location
  that is identified with a GUID value).
- Create a VmgExit library to replace static inline functions.
- Move some PCDs to the appropriate packages
- Add support for writing to QEMU flash under SEV-ES
- Add additional MMIO opcode support
- Cleaned up the GHCB MSR CPUID protocol support

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 (43):
  MdePkg: Create PCDs to be used in support of SEV-ES
  MdePkg: Add the MSR definition for the GHCB register
  MdePkg: Add a structure definition for the GHCB
  MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  MdePkg/BaseLib: Add support for the XGETBV instruction
  MdePkg/BaseLib: Add support for the VMGEXIT instruction
  UefiCpuPkg: Implement library support for VMGEXIT
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
  UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
  UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
  UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE
    events
  UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE
    events
  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
  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
  OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
  OvmfPkg/Sec: Add #VC exception handling for Sec phase
  OvmfPkg/Sec: Enable cache early to speed up booting
  OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with
    SEV-ES is enabled
  MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
  UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is
    enabled
  UefiCpuPkg: Allow AP booting under SEV-ES
  OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  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                 |   23 +
 OvmfPkg/OvmfPkg.dec                           |    5 +
 UefiCpuPkg/UefiCpuPkg.dec                     |    8 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   11 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   11 +
 OvmfPkg/OvmfPkgX64.dsc                        |   11 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
 UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
 UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
 OvmfPkg/OvmfPkgX64.fdf                        |    9 +
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
 MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
 .../FvbServicesRuntimeDxe.inf                 |    2 +
 OvmfPkg/ResetVector/ResetVector.inf           |    9 +
 OvmfPkg/Sec/SecMain.inf                       |    1 +
 .../DxeCpuExceptionHandlerLib.inf             |    5 +
 .../PeiCpuExceptionHandlerLib.inf             |    5 +
 .../SecPeiCpuExceptionHandlerLib.inf          |    8 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    4 +
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    4 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
 .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
 MdePkg/Include/Library/BaseLib.h              |   31 +
 MdePkg/Include/Protocol/Cpu.h                 |   18 +
 MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
 MdePkg/Include/Register/Amd/Ghcb.h            |  117 ++
 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       |   96 ++
 .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   26 +
 .../CpuExceptionCommon.h                      |    2 +
 UefiCpuPkg/Library/MpInitLib/MpLib.h          |   79 +-
 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                  |   82 ++
 OvmfPkg/PlatformPei/MemDetect.c               |   23 +
 .../QemuFlash.c                               |   38 +-
 OvmfPkg/Sec/SecMain.c                         |   74 +-
 UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
 UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
 .../CpuExceptionCommon.c                      |    2 +-
 .../Ia32/AMDSevVcCommon.c                     |   20 +
 .../PeiDxeAMDSevVcHandler.c                   |   29 +
 .../PeiDxeSmmCpuException.c                   |   16 +
 .../SecAMDSevVcHandler.c                      |   50 +
 .../SecPeiCpuException.c                      |   16 +
 .../X64/AMDSevVcCommon.c                      | 1230 +++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  280 +++-
 UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |  132 ++
 UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
 MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   37 +
 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  |   94 ++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  337 ++++-
 OvmfPkg/ResetVector/ResetVector.nasmb         |   19 +
 .../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 |  370 ++++-
 UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
 .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
 74 files changed, 3969 insertions(+), 101 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] 82+ messages in thread

* Re: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support
  2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
                   ` (43 preceding siblings ...)
  2019-11-21  1:53 ` [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support Nate DeSimone
@ 2019-11-21  9:45 ` Laszlo Ersek
  2019-11-21  9:48   ` Laszlo Ersek
  44 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21  9:45 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh, Benjamin You, Dandan Bi,
	Guo Dong, Hao A Wu, Jian J Wang, Maurice Ma

On 11/20/19 21:06, Lendacky, Thomas wrote:

> Changes since v2:
> - Added a way to locate the SEV-ES fixed AP RIP address for starting
>   AP's to avoid updating the actual flash image (build time location
>   that is identified with a GUID value).

Good news! But...

> - Create a VmgExit library to replace static inline functions.
> - Move some PCDs to the appropriate packages
> - Add support for writing to QEMU flash under SEV-ES

this confuses me.

Anyway I'll check the patches.

Thanks
Laszlo

> - Add additional MMIO opcode support
> - Cleaned up the GHCB MSR CPUID protocol support


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

* Re: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support
  2019-11-21  9:45 ` Laszlo Ersek
@ 2019-11-21  9:48   ` Laszlo Ersek
  0 siblings, 0 replies; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21  9:48 UTC (permalink / raw)
  To: devel, thomas.lendacky

On 11/21/19 10:45, Laszlo Ersek wrote:
> On 11/20/19 21:06, Lendacky, Thomas wrote:
> 
>> Changes since v2:
>> - Added a way to locate the SEV-ES fixed AP RIP address for starting
>>   AP's to avoid updating the actual flash image (build time location
>>   that is identified with a GUID value).
> 
> Good news! But...
> 
>> - Create a VmgExit library to replace static inline functions.
>> - Move some PCDs to the appropriate packages
>> - Add support for writing to QEMU flash under SEV-ES
> 
> this confuses me.
> 
> Anyway I'll check the patches.

Ah, I think this might refer to VmgMmioWrite() in

  [edk2-devel] [RFC PATCH v3 07/43]
  UefiCpuPkg: Implement library support for VMGEXIT

and

  [edk2-devel] [RFC PATCH v3 32/43]
  OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with
  SEV-ES is enabled

So I think I do understand the reference in the blurb now.

Thanks!
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check
  2019-11-20 20:06 ` [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
@ 2019-11-21 11:02   ` Laszlo Ersek
  0 siblings, 0 replies; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 11:02 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> 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 | 261 +++++++++++++++++++++-
>  OvmfPkg/ResetVector/ResetVector.nasmb     |   2 +
>  3 files changed, 262 insertions(+), 3 deletions(-)
> 
> 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..c902fa68d556 100644
> --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> @@ -31,13 +31,52 @@ BITS    32
>                         PAGE_READ_WRITE + \
>                         PAGE_PRESENT)
>  
> +;
> +; SEV-ES #VC exception handler support
> +;
> +; #VC handler local variable locations
> +;
> +%define VC_CPUID_RESULT_EAX         0
> +%define VC_CPUID_RESULT_EBX         4
> +%define VC_CPUID_RESULT_ECX         8
> +%define VC_CPUID_RESULT_EDX        12
> +%define VC_GHCB_MSR_EDX            16
> +%define VC_GHCB_MSR_EAX            20
> +%define VC_CPUID_REQUEST_REGISTER  24
> +%define VC_CPUID_FUNCTION          28
> +
> +; #VC handler total local variable size
> +;
> +%define VC_VARIABLE_SIZE           32
> +
> +; #VC handler GHCB CPUID request/response protocol values
> +;
> +%define GHCB_CPUID_REQUEST          4
> +%define GHCB_CPUID_RESPONSE         5
> +%define GHCB_CPUID_REGISTER_SHIFT  30
> +%define CPUID_INSN_LEN              2
> +
> +
>  ; Check if Secure Encrypted Virtualization (SEV) 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 (see SevEsIdtVmmComm for
> +    ;   stack usage)
> +    ;   Establish exception handlers
> +    ;
> +    mov       esp, SEV_ES_VC_TOP_OF_STACK
> +    mov       eax, ADDR_OF(Idtr)
> +    lidt      [cs:eax]
> +
>      ; Check if we have a valid (0x8000_001F) CPUID leaf
> +    ;   CPUID raises a #VC exception if running as an SEV-ES guest
>      mov       eax, 0x80000000
>      cpuid
>  
> @@ -48,8 +87,8 @@ CheckSevFeature:
>      jl        NoSev
>  
>      ; Check for memory encryption feature:
> -    ;  CPUID  Fn8000_001F[EAX] - Bit 1
> -    ;
> +    ; CPUID  Fn8000_001F[EAX] - Bit 1
> +    ;   CPUID raises a #VC exception if running as an SEV-ES guest
>      mov       eax,  0x8000001f
>      cpuid
>      bt        eax, 1
> @@ -73,6 +112,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 +194,210 @@ pageTableEntriesLoop:
>      mov     cr3, eax
>  
>      OneTimeCallRet SetCr3ForPageTables64
> +
> +SevEsIdtNotCpuid:
> +    ;
> +    ; Use VMGEXIT to request termination.
> +    ;   1 - #VC was not for CPUID
> +    ;
> +    mov     eax, 1
> +    jmp     SevEsIdtTerminate
> +
> +SevEsIdtNoCpuidResponse:
> +    ;
> +    ; Use VMGEXIT to request termination.
> +    ;   2 - GHCB_CPUID_RESPONSE not received
> +    ;
> +    mov     eax, 2
> +
> +SevEsIdtTerminate:
> +    ;
> +    ; Use VMGEXIT to request termination. At this point the reason code is
> +    ; located in EAX, so shift it left 16 bits to the proper location.
> +    ;
> +    ; EAX[11:0]  => 0x100 - request termination
> +    ; EAX[15:12] => 0x1   - OVMF
> +    ; EAX[23:16] => 0xXX  - REASON CODE
> +    ;
> +    shl     eax, 16
> +    or      eax, 0x1100
> +    xor     edx, edx
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +    ;
> +    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
> +    ; mode, so work around this by temporarily switching to 64-bit mode.
> +    ;
> +BITS    64
> +    rep     vmmcall
> +BITS    32
> +
> +    ;
> +    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
> +    ;
> +SevEsIdtHlt:
> +    hlt
> +    jmp     SevEsIdtHlt
> +    iret
> +
> +    ;
> +    ; Total stack usage for the #VC handler is 44 bytes:
> +    ;   - 12 bytes for the exception IRET (after popping error code)
> +    ;   - 32 bytes for the local variables.
> +    ;
> +SevEsIdtVmmComm:
> +    ;
> +    ; If we're here, then we are an SEV-ES guest and this
> +    ; was triggered by a CPUID instruction
> +    ;
> +    pop     ecx                     ; Error code
> +    cmp     ecx, 0x72               ; Be sure it was CPUID
> +    jne     SevEsIdtNotCpuid
> +
> +    ; Set up local variable room on the stack
> +    ;   CPUID function         : + 28
> +    ;   CPUID request register : + 24
> +    ;   GHCB MSR (EAX)         : + 20
> +    ;   GHCB MSR (EDX)         : + 16
> +    ;   CPUID result (EDX)     : + 12
> +    ;   CPUID result (ECX)     : + 8
> +    ;   CPUID result (EBX)     : + 4
> +    ;   CPUID result (EAX)     : + 0
> +    sub     esp, VC_VARIABLE_SIZE
> +
> +    ; Save the CPUID function being requested
> +    mov     [esp + VC_CPUID_FUNCTION], eax
> +
> +    ; The GHCB CPUID protocol uses the following mapping to request
> +    ; a specific register:
> +    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
> +    ;
> +    ; Set EAX as the first register to request. This will also be used as a
> +    ; loop variable to request all register values (EAX to EDX).
> +    xor     eax, eax
> +    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
> +
> +    ; Save current GHCB MSR value
> +    mov     ecx, 0xc0010130
> +    rdmsr
> +    mov     [esp + VC_GHCB_MSR_EAX], eax
> +    mov     [esp + VC_GHCB_MSR_EDX], edx
> +
> +NextReg:
> +    ;
> +    ; Setup GHCB MSR
> +    ;   GHCB_MSR[63:32] = CPUID function
> +    ;   GHCB_MSR[31:30] = CPUID register
> +    ;   GHCB_MSR[11:0]  = CPUID request protocol
> +    ;
> +    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
> +    cmp     eax, 4
> +    jge     VmmDone
> +
> +    shl     eax, GHCB_CPUID_REGISTER_SHIFT
> +    or      eax, GHCB_CPUID_REQUEST
> +    mov     edx, [esp + VC_CPUID_FUNCTION]
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +
> +    ;
> +    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
> +    ; mode, so work around this by temporarily switching to 64-bit mode.
> +    ;
> +BITS    64
> +    rep     vmmcall
> +BITS    32
> +
> +    ;
> +    ; Read GHCB MSR
> +    ;   GHCB_MSR[63:32] = CPUID register value
> +    ;   GHCB_MSR[31:30] = CPUID register
> +    ;   GHCB_MSR[11:0]  = CPUID response protocol
> +    ;
> +    mov     ecx, 0xc0010130
> +    rdmsr
> +    mov     ecx, eax
> +    and     ecx, 0xfff
> +    cmp     ecx, GHCB_CPUID_RESPONSE
> +    jne     SevEsIdtNoCpuidResponse
> +
> +    ; Save returned value
> +    shr     eax, GHCB_CPUID_REGISTER_SHIFT
> +    mov     [esp + eax * 4], edx
> +
> +    ; Next register
> +    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
> +
> +    jmp     NextReg
> +
> +VmmDone:
> +    ;
> +    ; At this point we have all CPUID register values. Restore the GHCB MSR,
> +    ; set the return register values and return.
> +    ;
> +    mov     eax, [esp + VC_GHCB_MSR_EAX]
> +    mov     edx, [esp + VC_GHCB_MSR_EDX]
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +
> +    mov     eax, [esp + VC_CPUID_RESULT_EAX]
> +    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
> +    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
> +    mov     edx, [esp + VC_CPUID_RESULT_EDX]
> +
> +    add     esp, VC_VARIABLE_SIZE
> +
> +    ; Update the EIP value to skip over the now handled CPUID instruction
> +    ; (the CPUID instruction has a length of 2)
> +    add     word [esp], CPUID_INSN_LEN
> +    iret
> +
> +ALIGN   2
> +
> +Idtr:
> +    dw      IDT_END - IDT_BASE - 1  ; Limit
> +    dd      ADDR_OF(IDT_BASE)       ; Base
> +
> +IdtrClear:
> +    dw      0                       ; Limit
> +    dd      0                       ; Base
> +
> +ALIGN   16
> +
> +;
> +; The Interrupt Descriptor Table (IDT)
> +;   This will be used to determine if SEV-ES is enabled.  Upon execution
> +;   of the CPUID instruction, a VMM Communication Exception will occur.
> +;   This will tell us if SEV-ES is enabled.  We can use the current value
> +;   of the GHCB MSR to determine the SEV attributes.
> +;
> +IDT_BASE:
> +;
> +; Vectors 0 - 28 (No handlers)
> +;
> +%rep 29
> +    dw      0                                    ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      0                                    ; Offset high bits 31..16
> +%endrep
> +;
> +; Vector 29 (VMM Communication Exception)
> +;
> +    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
> +;
> +; Vectors 30 - 31 (No handlers)
> +;
> +%rep 2
> +    dw      0                                    ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      0                                    ; Offset high bits 31..16
> +%endrep
> +IDT_END:
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 75cfe16654b1..579c75f5ba0c 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -55,6 +55,8 @@
>  
>    %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
>  %include "Ia32/Flat32ToFlat64.asm"
> +
> +  %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
>  %include "Ia32/PageTables64.asm"
>  %endif
>  
> 

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


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

* Re: [edk2-devel] [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT
  2019-11-20 20:06 ` [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
@ 2019-11-21 11:15   ` Laszlo Ersek
  2019-11-21 16:48     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 11:15 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> 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.
> 
> Additionally, two VMGEXIT / MMIO related functions are created to support
> flash emulation. Flash emulation currently is done by marking the flash
> area as read-only and taking a nested page fault to perform the emulation
> of the instruction. However, emulation cannot be performed because there
> is no instruction decode assist support when SEV-ES is enabled. Provide
> routines to initiate an MMIO request to perform actual writes to flash.
> 
> 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      |  96 ++++++++++++++
>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c   | 132 +++++++++++++++++++
>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni |  15 +++
>  6 files changed, 284 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 12f4413ea5b0..90feb9166dc8 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 d28cb5cccb52..5ab7e423e8ab 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
> @@ -136,6 +140,7 @@ [Components.IA32, Components.X64]
>    UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
>    UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>    UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
> +  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>    UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf
>    UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf
>    UefiCpuPkg/SecCore/SecCore.inf
> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
> new file mode 100644
> index 000000000000..6acfa779e75a
> --- /dev/null
> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
> @@ -0,0 +1,33 @@
> +## @file
> +#  VMGEXIT Support Library.
> +#
> +#  Copyright (c) 2019, Advanced Micro Devices, 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..b5639fbfa1a5
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
> @@ -0,0 +1,96 @@
> +/** @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, Advanced Micro Devices, 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
> +  );
> +
> +#define VMGMMIO_READ   False
> +#define VMGMMIO_WRITE  True
> +
> +/**
> +  Perform MMIO write of a buffer to a non-MMIO marked range.
> +
> +  Performs an MMIO write without taking a #VC. This is useful
> +  for Flash devices, which are marked read-only.
> +
> +  @param[in]  UINT8      A pointer to the destination buffer
> +  @param[in]  UINTN      The immediate value to write
> +  @param[in]  UINTN      Number of bytes to write
> +
> +**/
> +VOID
> +EFIAPI
> +VmgMmioWrite (
> +  UINT8               *Dest,
> +  UINT8               *Src,
> +  UINTN                Bytes
> +  );
> +
> +#endif
> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
> new file mode 100644
> index 000000000000..23965b7ff022
> --- /dev/null
> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
> @@ -0,0 +1,132 @@
> +/** @file
> +  VMGEXIT Support Library.
> +
> +  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Uefi.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Register/Amd/Ghcb.h>
> +#include <Register/Amd/Msr.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 ();

This patch looks good to me (and, in general, I'd like to defer to Ray
and Eric on the UefiCpuPkg patches); just one comment:

AsmVmgExit() orchestrates guest-host communication in guest RAM, and in
that sense, it is somewhat similar to virtio. In virtio (per spec), we
use MemoryFence() calls carefully.

Now, if you check the MemoryFence() implementation in
"MdePkg/Library/BaseLib/X64/GccInline.c", it is only

  __asm__ __volatile__ ("":::"memory");

which is already part of AsmVmgExit(), from the previous patch:

  [edk2-devel] [RFC PATCH v3 06/43]
  MdePkg/BaseLib: Add support for the VMGEXIT instruction

  __asm__ __volatile__ ("rep; vmmcall":::"memory");

So, I think it's not necessary *in practice* to add a MemoryFence()
ahead of the AsmVmgExit(). But, I think it is needed afterwards.

The comment in "MdePkg/Library/BaseLib/X64/GccInline.c" says, "it is
more about the compiler that it is actually processor synchronization".
With that in mind, I'd like to suggest one of two alternatives:

- modify the AsmVmgExit() documentation (function level comment in the
lib class header) so that it spell out that all barriers (before &
after) are contained within,

- or please modify the call site so that it is both preceded and
succeeded by MemoryFence().

With either option implemented:

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

Thanks
Laszlo



> +
> +  return VmgExitErrorCheck (Ghcb);
> +}
> +
> +VOID
> +EFIAPI
> +VmgInit (
> +  GHCB                *Ghcb
> +  )
> +{
> +  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
> +}
> +
> +VOID
> +EFIAPI
> +VmgDone (
> +  GHCB                *Ghcb
> +  )
> +{
> +}
> +
> +UINTN
> +EFIAPI
> +VmgMmio (
> +  UINT8               *MmioAddress,
> +  UINT8               *Buffer,
> +  UINTN               Bytes,
> +  BOOLEAN             Write
> +  )
> +{
> +  UINT64                    MmioOp;
> +  UINT64                    ExitInfo1, ExitInfo2;
> +  UINTN                     Status;
> +  GHCB                      *Ghcb;
> +  MSR_SEV_ES_GHCB_REGISTER  Msr;
> +
> +  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
> +  Ghcb = Msr.Ghcb;
> +
> +  if (Write) {
> +    MmioOp = SvmExitMmioWrite;
> +  } else {
> +    MmioOp = SvmExitMmioRead;
> +  }
> +
> +  ExitInfo1 = (UINT64) (UINTN) MmioAddress;
> +  ExitInfo2 = Bytes;
> +
> +  if (Write) {
> +    CopyMem (Ghcb->SharedBuffer, Buffer, Bytes);
> +  }
> +
> +  Ghcb->SaveArea.SwScratch = (UINT64) (UINTN) Ghcb->SharedBuffer;
> +  Status = VmgExit (Ghcb, MmioOp, ExitInfo1, ExitInfo2);
> +  if (Status != 0) {
> +    return Status;
> +  }
> +
> +  if (!Write) {
> +    CopyMem (Buffer, Ghcb->SharedBuffer, Bytes);
> +  }
> +
> +  return 0;
> +}
> +
> +VOID
> +EFIAPI
> +VmgMmioWrite (
> +  UINT8               *Dest,
> +  UINT8               *Src,
> +  UINTN                Bytes
> +  )
> +{
> +  VmgMmio (Dest, Src, Bytes, TRUE);
> +}
> +
> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
> new file mode 100644
> index 000000000000..e8656aae4726
> --- /dev/null
> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
> @@ -0,0 +1,15 @@
> +// /** @file
> +// VMGEXIT support library instance.
> +//
> +// VMGEXIT support library instance.
> +//
> +// Copyright (c) 2019, Advanced Micro Devices, 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."
> +
> 


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

* Re: [edk2-devel] [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase
  2019-11-20 20:06 ` [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
@ 2019-11-21 11:29   ` Laszlo Ersek
  0 siblings, 0 replies; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 11:29 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> 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 #VC exception handler routines assume that a per-CPU
> variable area is immediately after the GHCB, this per-CPU variable area
> must also 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 and per-CPU variable pages. After breaking down
> the 2MB page, update the GHCB page table entry to remove the encryption
> mask.
> 
> The GHCB page will be used by the SEC #VC exception handler. The #VC
> exception handler will fill in the necessary fields of the GHCB and exit
> to the hypervisor using the VMGEXIT instruction. The hypervisor then
> accesses the GHCB in order to perform the requested function.
> 
> 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                       |  5 ++
>  OvmfPkg/OvmfPkgX64.fdf                    |  6 ++
>  OvmfPkg/ResetVector/ResetVector.inf       |  5 ++
>  OvmfPkg/ResetVector/Ia32/PageTables64.asm | 76 +++++++++++++++++++++++
>  OvmfPkg/ResetVector/ResetVector.nasmb     | 16 +++++
>  5 files changed, 108 insertions(+)
> 
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index d5fee805ef4a..19723786d729 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -228,6 +228,11 @@ [PcdsFixedAtBuild]
>    ## Number of page frames to use for storing grant table entries.
>    gUefiOvmfPkgTokenSpaceGuid.PcdXenGrantFrames|4|UINT32|0x33
>  
> +  ## 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|0x34
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|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 e49adc425fce..973b19fdbf19 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|0x002000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
> +
>  0x010000|0x010000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>  
> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
> index 960b47cd0797..266c5fc5c8b3 100644
> --- a/OvmfPkg/ResetVector/ResetVector.inf
> +++ b/OvmfPkg/ResetVector/ResetVector.inf
> @@ -26,6 +26,7 @@ [Sources]
>  [Packages]
>    OvmfPkg/OvmfPkg.dec
>    MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
>    UefiCpuPkg/UefiCpuPkg.dec
>  
>  [BuildOptions]
> @@ -33,7 +34,11 @@ [BuildOptions]
>     *_*_X64_NASMB_FLAGS = -I$(WORKSPACE)/UefiCpuPkg/ResetVector/Vtf0/
>  
>  [Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
> diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
> index c902fa68d556..b064ca65b88d 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 + \
> @@ -123,6 +128,37 @@ SevExit:
>  
>      OneTimeCallRet CheckSevFeature
>  
> +; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
> +; is enabled.
> +;
> +; Modified:  EAX, EBX, ECX
> +;
> +; 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
>  ;
> @@ -187,6 +223,46 @@ 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 GHCB_BASE and needs to be un-encrypted.
> +    ; This requires the 2MB page for this range be broken down into 512 4KB
> +    ; pages.  All will be marked encrypted, except for the GHCB.
> +    ;
> +    mov     ecx, (GHCB_BASE >> 21)
> +    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
> +    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
> +
> +    ;
> +    ; Page Table Entries (512 * 4KB entries => 2MB)
> +    ;
> +    mov     ecx, 512
> +pageTableEntries4kLoop:
> +    mov     eax, ecx
> +    dec     eax
> +    shl     eax, 12
> +    add     eax, GHCB_BASE & 0xFFE0_0000
> +    add     eax, PAGE_4K_PDE_ATTR
> +    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
> +    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
> +    loop    pageTableEntries4kLoop
> +
> +    ;
> +    ; Clear the encryption bit from the GHCB entry
> +    ;
> +    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
> +    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
> +
> +    mov     ecx, GHCB_SIZE / 4
> +    xor     eax, eax
> +clearGhcbMemoryLoop:
> +    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
> +    loop    clearGhcbMemoryLoop
> +
> +SetCr3:
>      ;
>      ; Set CR3 now that the paging structures are available
>      ;
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 579c75f5ba0c..708bbda6208f 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -53,9 +53,25 @@
>      %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"
>    %endif
>  
> +  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)
> +    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"
> +  %endif
> +
> +  %if (FixedPcdGet32 (PcdSecGhcbSize) != 0x2000)
> +    %error "This implementation inherently depends on PcdSecGhcbSize"
> +  %endif
> +
> +  %if ((FixedPcdGet32 (PcdSecGhcbBase) >> 21) != \
> +       ((FixedPcdGet32 (PcdSecGhcbBase) + FixedPcdGet32 (PcdSecGhcbSize) - 1) >> 21))
> +    %error "This implementation inherently depends on PcdSecGhcbBase not straddling a 2MB boundary"
> +  %endif
> +
>    %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
>  %include "Ia32/Flat32ToFlat64.asm"
>  
> +  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
> +  %define GHCB_BASE (FixedPcdGet32 (PcdSecGhcbBase))
> +  %define GHCB_SIZE (FixedPcdGet32 (PcdSecGhcbSize))
>    %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
>  %include "Ia32/PageTables64.asm"
>  %endif
> 

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


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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-20 20:06 ` [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
@ 2019-11-21 12:06   ` Laszlo Ersek
  2019-11-21 20:46     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 12:06 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> 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.
> 
> 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 bae9764577f0..db319030ee58 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,

(1) The problem here is that we call multiple library APIs before
calling ProcessLibraryConstructorList() -- namely CopyMem(),
AsmWriteIdtr(), and InitializeCpuExceptionHandlers().

(See also the "SetMem" reference in the leading context, in the source
file -- it is not quoted in this patch.)

Thus, would it be possible to move all the "+" lines, quoted above, just
below the ProcessLibraryConstructorList() call?


(2) If possible I'd like to restrict the
InitializeCpuExceptionHandlers() call to SevEsIsEnabled().

(Unless you're implying that InitializeCpuExceptionHandlers() is useful
even without SEV-ES -- but then the commit message should be reworded
accordingly.)

If you agree to that restriction, then I further suggest reordering this
patch against the next one:

  [edk2-devel] [RFC PATCH v3 31/43]
  OvmfPkg/Sec: Enable cache early to speed up booting

Namely, if you put that patch first, then in the present patch you can
extend the already existing SevEsIsEnabled()-dependent scope, with a
call to InitializeCpuExceptionHandlers().

The end result would be something like:

  ProcessLibraryConstructorList();

  //
  // Initialize IDT
  // ...
  //

  if (SevEsIsEnabled()) {
    //
    // non-automatic exit events (NAE) can occur during SEC ...
    //
    InitializeCpuExceptionHandlers (NULL);

    //
    // Under SEV-ES, the hypervisor can't modify CR0 ...
    //
    AsmEnableCache ();
  }

What's your opinion?

Thanks!
Laszlo

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


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

* Re: [edk2-devel] [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting
  2019-11-20 20:06 ` [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
@ 2019-11-21 12:08   ` Laszlo Ersek
  0 siblings, 0 replies; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 12:08 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> 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.c | 45 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
> 
> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index db319030ee58..53c850134897 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -25,6 +25,9 @@
>  #include <Library/ExtractGuidedSectionLib.h>
>  #include <Library/LocalApicLib.h>
>  #include <Library/CpuExceptionHandlerLib.h>
> +#include <Register/Cpuid.h>
> +#include <Register/Amd/Cpuid.h>
> +#include <Register/Amd/Fam17Msr.h>
>  
>  #include <Ppi/TemporaryRamSupport.h>
>  
> @@ -713,6 +716,39 @@ FindAndReportEntryPoints (
>    return;
>  }
>  
> +STATIC
> +BOOLEAN
> +SevEsIsEnabled (
> +  VOID
> +  )
> +{
> +  UINT32                            RegEax;
> +  CPUID_MEMORY_ENCRYPTION_INFO_EAX  Eax;
> +  MSR_SEV_STATUS_REGISTER           Msr;
> +
> +  //
> +  // Check if the memory encryption leaf exist
> +  //
> +  AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
> +  if (RegEax >= CPUID_MEMORY_ENCRYPTION_INFO) {
> +    //
> +    // CPUID Fn8000_001F[EAX] Bit 1 (Sev supported)
> +    //
> +    AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, &Eax.Uint32, NULL, NULL, NULL);
> +    if (Eax.Bits.SevBit && Eax.Bits.SevEsBit) {
> +      //
> +      // Check MSR_0xC0010131 Bit 1 (Sev-Es Enabled)
> +      //
> +      Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
> +      if (Msr.Bits.SevEsBit) {
> +        return TRUE;
> +      }
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
>  VOID
>  EFIAPI
>  SecCoreStartupWithStack (
> @@ -755,6 +791,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 (SevEsIsEnabled()) {
> +    AsmEnableCache ();
> +  }
> +
>    DEBUG ((EFI_D_INFO,
>      "SecCoreStartupWithStack(0x%x, 0x%x)\n",
>      (UINT32)(UINTN)BootFv,
> 

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

(If you agree with the suggestions I made for the previous patch in the
series, then you may have to move the comment block added here inside
the braces -- that's OK, it won't invalidate my R-b given here.)

Thanks!
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled
  2019-11-20 20:06 ` [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled Lendacky, Thomas
@ 2019-11-21 12:31   ` Laszlo Ersek
  2019-11-21 21:11     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 12:31 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> The flash detection routine will attempt to determine how the flash
> device behaves (e.g. ROM, RAM, Flash). But when SEV-ES is enabled and
> the flash device behaves as a ROM device (meaning it is marked read-only
> by the hypervisor), this check may result in an infinite nested page fault
> because of the attempted write. Since the instruction cannot be emulated
> when SEV-ES is enabled, the RIP is never advanced, resulting in repeated
> nested page faults.
> 
> When SEV-ES is enabled, exit the flash detection early and assume that
> the FD behaves as Flash. This will result in QemuFlashWrite() being called
> to store EFI variables, which will also result in an infinite nested page
> fault when the write is performed. In this case, update QemuFlashWrite()
> to use the VmgMmioWrite function from the VmgExitLib library to have the
> hypervisor perform the write without having to emulate the instruction.

(1) Please include the Bugzilla link in the commit message:

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

> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  OvmfPkg/OvmfPkgIa32.dsc                       |  1 +
>  OvmfPkg/OvmfPkgIa32X64.dsc                    |  1 +
>  OvmfPkg/OvmfPkgX64.dsc                        |  1 +
>  .../FvbServicesRuntimeDxe.inf                 |  2 +
>  .../QemuFlash.c                               | 38 +++++++++++++++++--
>  5 files changed, 40 insertions(+), 3 deletions(-)
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 56670eefde6b..ff2814c6246e 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -320,6 +320,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>  
>  [LibraryClasses.common.UEFI_DRIVER]
>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 9897e6889573..212952cfaacd 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>  
>  [LibraryClasses.common.UEFI_DRIVER]
>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 59c4f9207fc3..8331fc0b663e 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>  
>  [LibraryClasses.common.UEFI_DRIVER]
>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
> index ca6326e833ed..0b7741ac07f8 100644
> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
> @@ -38,6 +38,7 @@ [Sources]
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
>    OvmfPkg/OvmfPkg.dec
>  
>  [LibraryClasses]
> @@ -52,6 +53,7 @@ [LibraryClasses]
>    UefiBootServicesTableLib
>    UefiDriverEntryPoint
>    UefiRuntimeLib
> +  VmgExitLib
>  
>  [Guids]
>    gEfiEventVirtualAddressChangeGuid   # ALWAYS_CONSUMED

These hunks look good.

> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
> index c81c58972bf2..4f3bf690fcad 100644
> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
> @@ -9,7 +9,9 @@
>  
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/MemEncryptSevLib.h>
>  #include <Library/PcdLib.h>
> +#include <Library/VmgExitLib.h>
>  
>  #include "QemuFlash.h"
>  
> @@ -80,6 +82,20 @@ QemuFlashDetected (
>  
>    DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
>  
> +  if (MemEncryptSevEsIsEnabled()) {
> +    //
> +    // When SEV-ES is enabled, the check below can result in an infinite
> +    // loop with respect to a nested page fault. When the FD behaves as
> +    // a ROM, the nested page table entry is read-only. The check below

(2) I suggest a slight change to the wording above. Please replace

  when the FD behaves as a ROM

with

  when the memslot is mapped read-only

(It's OK to make qemu / kvm references in this code: the name of the
file includes "Qemu".)

> +    // will cause a nested page fault that cannot be emulated, causing
> +    // the instruction to retried over and over. For SEV-ES, assume that
> +    // the FD does not behave as FLASH.

(3) I would recommend

  For SEV-ES, acknowledge that the FD appears as ROM and not as FLASH,
  but report FLASH anyway.

> +    //
> +    DEBUG ((DEBUG_INFO,
> +      "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"));
> +    return TRUE;
> +  }
> +
>    OriginalUint8 = *Ptr;
>    *Ptr = CLEAR_STATUS_CMD;
>    ProbeUint8 = *Ptr;
> @@ -147,6 +163,21 @@ QemuFlashRead (
>  }
>  
>  
> +STATIC
> +VOID
> +QemuFlashPtrWrite (
> +  IN        volatile UINT8                      *Ptr,
> +  IN        UINT8                               Value
> +  )
> +{
> +  if (MemEncryptSevEsIsEnabled()) {
> +    VmgMmioWrite ((UINT8 *) Ptr, &Value, 1);
> +  } else {
> +    *Ptr = Value;
> +  }
> +}
> +
> +
>  /**
>    Write to QEMU Flash
>  

(4) This change will break the "FvbServicesSmm.inf" build of this module.

(Because, you have -- correctly -- added the VmgExitLib class to
"FvbServicesRuntimeDxe.inf" only.)

Please:

- create two implementations of the QemuFlashPtrWrite() function, one in
"QemuFlashDxe.c", and another in "QemuFlashSmm.c".

- the former should be the function shown above, the latter should only
perform the direct assignment.

- the '#include <Library/VmgExitLib.h>' directive should also be moved
to "QemuFlashDxe.c".

- the prototype for QemuFlashPtrWrite() should be added to "QemuFlash.h"
please.

> @@ -181,8 +212,9 @@ QemuFlashWrite (
>    //
>    Ptr = QemuFlashPtr (Lba, Offset);
>    for (Loop = 0; Loop < *NumBytes; Loop++) {
> -    *Ptr = WRITE_BYTE_CMD;
> -    *Ptr = Buffer[Loop];
> +    QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
> +    QemuFlashPtrWrite (Ptr, Buffer[Loop]);
> +
>      Ptr++;
>    }
>  
> @@ -190,7 +222,7 @@ QemuFlashWrite (
>    // Restore flash to read mode
>    //
>    if (*NumBytes > 0) {
> -    *(Ptr - 1) = READ_ARRAY_CMD;
> +    QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
>    }
>  
>    return EFI_SUCCESS;
> 

With (1) and (4) fixed, and with (2) and (3) optionally fixed (i.e., if
you agree):

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

Thanks
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support
  2019-11-21  1:53 ` [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support Nate DeSimone
@ 2019-11-21 15:50   ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-21 15:50 UTC (permalink / raw)
  To: Desimone, Nathaniel L, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Ni, Ray, Brijesh Singh, You, Benjamin,
	Bi, Dandan, Dong, Guo, Wu, Hao A, Wang, Jian J, Ma, Maurice

On 11/20/19 7:53 PM, Desimone, Nathaniel L wrote:
> Hi Tom,

Hi Nate,

> 
> EFI_CPU_ARCH_PROTOCOL is a PI spec defined protocol. Please see Volume 2, Section 12.3 of the UEFI Platform Initialization Specification. Generally we strictly adhere to the spec when a PPI or protocol is spec defined. If not already done, I would recommend submitting a spec change request with the UEFI Forum. I don't think we can merge the patch series as-is without your change being ratified by the UEFI Forum.
> 
> Another option would be to define a separate protocol with the EDKII_ prefix instead of the EFI_ prefix as the EFI_ prefix is exclusively reserved for PPIs and protocols that are defined by either the UEFI spec or the PI spec. In which case, the protocol would need to be moved to either MdeModulePkg or UefiCpuPkg, as only spec defined PPIs and protocols are allowed in MdePkg.

Thanks for the heads up on this. Lets see if there's any feedback over
email or in the design meeting over what would be the best approach to
take and go from there.

Thanks,
Tom

> 
> Regards,
> Nate
> 
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lendacky, Thomas
> Sent: Wednesday, November 20, 2019 12:06 PM
> To: devel@edk2.groups.io
> Cc: Justen, Jordan L <jordan.l.justen@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Brijesh Singh <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: [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support
> 
> 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:
> cc6854506c2b ("Readme.md: remove positional references from submodule description")
> 
> Proper execution of SEV-ES relies on Bugzilla 2340 being fixed.
> 
> A version of the tree (with an extra patch to workaround Bugzilla 2340) can be found at:
> https://github.com/AMDESE/ovmf/tree/sev-es-v9
> 
> 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 v2:
> - Added a way to locate the SEV-ES fixed AP RIP address for starting
>   AP's to avoid updating the actual flash image (build time location
>   that is identified with a GUID value).
> - Create a VmgExit library to replace static inline functions.
> - Move some PCDs to the appropriate packages
> - Add support for writing to QEMU flash under SEV-ES
> - Add additional MMIO opcode support
> - Cleaned up the GHCB MSR CPUID protocol support
> 
> 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 (43):
>   MdePkg: Create PCDs to be used in support of SEV-ES
>   MdePkg: Add the MSR definition for the GHCB register
>   MdePkg: Add a structure definition for the GHCB
>   MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
>   MdePkg/BaseLib: Add support for the XGETBV instruction
>   MdePkg/BaseLib: Add support for the VMGEXIT instruction
>   UefiCpuPkg: Implement library support for VMGEXIT
>   UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception
>   UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events
>   UefiCpuPkg/CpuExceptionHandler: Support string IO for IOIO_PROT NAE
>     events
>   UefiCpuPkg/CpuExceptionHandler: Add support for CPUID NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO)
>   UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for INVD NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP NAE events
>   UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX NAE
>     events
>   UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX NAE
>     events
>   UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE
>     events
>   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
>   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
>   OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled
>   OvmfPkg/Sec: Add #VC exception handling for Sec phase
>   OvmfPkg/Sec: Enable cache early to speed up booting
>   OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with
>     SEV-ES is enabled
>   MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
>   UefiCpuPkg: Add a 16-bit protected mode code segment descriptor
>   UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is
>     enabled
>   UefiCpuPkg: Allow AP booting under SEV-ES
>   OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
>   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                 |   23 +
>  OvmfPkg/OvmfPkg.dec                           |    5 +
>  UefiCpuPkg/UefiCpuPkg.dec                     |    8 +
>  OvmfPkg/OvmfPkgIa32.dsc                       |   11 +
>  OvmfPkg/OvmfPkgIa32X64.dsc                    |   11 +
>  OvmfPkg/OvmfPkgX64.dsc                        |   11 +
>  UefiCpuPkg/UefiCpuPkg.dsc                     |    5 +
>  UefiPayloadPkg/UefiPayloadPkgIa32.dsc         |    2 +
>  UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc      |    2 +
>  OvmfPkg/OvmfPkgX64.fdf                        |    9 +
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |    2 +
>  MdePkg/Library/BaseLib/BaseLib.inf            |    4 +
>  OvmfPkg/PlatformPei/PlatformPei.inf           |    7 +
>  .../FvbServicesRuntimeDxe.inf                 |    2 +
>  OvmfPkg/ResetVector/ResetVector.inf           |    9 +
>  OvmfPkg/Sec/SecMain.inf                       |    1 +
>  .../DxeCpuExceptionHandlerLib.inf             |    5 +
>  .../PeiCpuExceptionHandlerLib.inf             |    5 +
>  .../SecPeiCpuExceptionHandlerLib.inf          |    8 +
>  UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |    4 +
>  UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |    4 +
>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf  |   33 +
>  .../Core/DxeIplPeim/X64/VirtualMemory.h       |   12 +-
>  MdePkg/Include/Library/BaseLib.h              |   31 +
>  MdePkg/Include/Protocol/Cpu.h                 |   18 +
>  MdePkg/Include/Register/Amd/Fam17Msr.h        |   28 +
>  MdePkg/Include/Register/Amd/Ghcb.h            |  117 ++
>  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       |   96 ++
>  .../CpuExceptionHandlerLib/AMDSevVcCommon.h   |   26 +
>  .../CpuExceptionCommon.h                      |    2 +
>  UefiCpuPkg/Library/MpInitLib/MpLib.h          |   79 +-
>  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                  |   82 ++
>  OvmfPkg/PlatformPei/MemDetect.c               |   23 +
>  .../QemuFlash.c                               |   38 +-
>  OvmfPkg/Sec/SecMain.c                         |   74 +-
>  UefiCpuPkg/CpuDxe/CpuDxe.c                    |   21 +-
>  UefiCpuPkg/CpuDxe/CpuGdt.c                    |    8 +-
>  .../CpuExceptionCommon.c                      |    2 +-
>  .../Ia32/AMDSevVcCommon.c                     |   20 +
>  .../PeiDxeAMDSevVcHandler.c                   |   29 +
>  .../PeiDxeSmmCpuException.c                   |   16 +
>  .../SecAMDSevVcHandler.c                      |   50 +
>  .../SecPeiCpuException.c                      |   16 +
>  .../X64/AMDSevVcCommon.c                      | 1230 +++++++++++++++++
>  UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  136 +-
>  UefiCpuPkg/Library/MpInitLib/MpLib.c          |  280 +++-
>  UefiCpuPkg/Library/MpInitLib/PeiMpLib.c       |   35 +
>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c    |  132 ++
>  UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |    2 +-
>  MdePkg/Library/BaseLib/Ia32/VmgExit.nasm      |   37 +
>  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  |   94 ++
>  OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  337 ++++-
>  OvmfPkg/ResetVector/ResetVector.nasmb         |   19 +
>  .../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 |  370 ++++-
>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni  |   15 +
>  .../ResetVector/Vtf0/Ia16/Real16ToFlat32.asm  |    9 +
>  74 files changed, 3969 insertions(+), 101 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] 82+ messages in thread

* Re: [edk2-devel] [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT
  2019-11-21 11:15   ` [edk2-devel] " Laszlo Ersek
@ 2019-11-21 16:48     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-21 16:48 UTC (permalink / raw)
  To: devel, lersek
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 5:15 AM, Laszlo Ersek via Groups.Io wrote:
> On 11/20/19 21:06, Lendacky, Thomas wrote:
>> 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.
>>
>> Additionally, two VMGEXIT / MMIO related functions are created to support
>> flash emulation. Flash emulation currently is done by marking the flash
>> area as read-only and taking a nested page fault to perform the emulation
>> of the instruction. However, emulation cannot be performed because there
>> is no instruction decode assist support when SEV-ES is enabled. Provide
>> routines to initiate an MMIO request to perform actual writes to flash.
>>
>> 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      |  96 ++++++++++++++
>>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c   | 132 +++++++++++++++++++
>>  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni |  15 +++
>>  6 files changed, 284 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 12f4413ea5b0..90feb9166dc8 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 d28cb5cccb52..5ab7e423e8ab 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
>> @@ -136,6 +140,7 @@ [Components.IA32, Components.X64]
>>    UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
>>    UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
>>    UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
>> +  UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>    UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf
>>    UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf
>>    UefiCpuPkg/SecCore/SecCore.inf
>> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>> new file mode 100644
>> index 000000000000..6acfa779e75a
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>> @@ -0,0 +1,33 @@
>> +## @file
>> +#  VMGEXIT Support Library.
>> +#
>> +#  Copyright (c) 2019, Advanced Micro Devices, 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..b5639fbfa1a5
>> --- /dev/null
>> +++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
>> @@ -0,0 +1,96 @@
>> +/** @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, Advanced Micro Devices, 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
>> +  );
>> +
>> +#define VMGMMIO_READ   False
>> +#define VMGMMIO_WRITE  True
>> +
>> +/**
>> +  Perform MMIO write of a buffer to a non-MMIO marked range.
>> +
>> +  Performs an MMIO write without taking a #VC. This is useful
>> +  for Flash devices, which are marked read-only.
>> +
>> +  @param[in]  UINT8      A pointer to the destination buffer
>> +  @param[in]  UINTN      The immediate value to write
>> +  @param[in]  UINTN      Number of bytes to write
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +VmgMmioWrite (
>> +  UINT8               *Dest,
>> +  UINT8               *Src,
>> +  UINTN                Bytes
>> +  );
>> +
>> +#endif
>> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
>> new file mode 100644
>> index 000000000000..23965b7ff022
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.c
>> @@ -0,0 +1,132 @@
>> +/** @file
>> +  VMGEXIT Support Library.
>> +
>> +  Copyright (c) 2019, Advanced Micro Devices, Inc. All rights reserved.<BR>
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Base.h>
>> +#include <Uefi.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Register/Amd/Ghcb.h>
>> +#include <Register/Amd/Msr.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 ();
> 
> This patch looks good to me (and, in general, I'd like to defer to Ray
> and Eric on the UefiCpuPkg patches); just one comment:
> 
> AsmVmgExit() orchestrates guest-host communication in guest RAM, and in
> that sense, it is somewhat similar to virtio. In virtio (per spec), we
> use MemoryFence() calls carefully.
> 
> Now, if you check the MemoryFence() implementation in
> "MdePkg/Library/BaseLib/X64/GccInline.c", it is only
> 
>   __asm__ __volatile__ ("":::"memory");
> 
> which is already part of AsmVmgExit(), from the previous patch:
> 
>   [edk2-devel] [RFC PATCH v3 06/43]
>   MdePkg/BaseLib: Add support for the VMGEXIT instruction
> 
>   __asm__ __volatile__ ("rep; vmmcall":::"memory");
> 
> So, I think it's not necessary *in practice* to add a MemoryFence()
> ahead of the AsmVmgExit(). But, I think it is needed afterwards.
> 
> The comment in "MdePkg/Library/BaseLib/X64/GccInline.c" says, "it is
> more about the compiler that it is actually processor synchronization".
> With that in mind, I'd like to suggest one of two alternatives:
> 
> - modify the AsmVmgExit() documentation (function level comment in the
> lib class header) so that it spell out that all barriers (before &
> after) are contained within,
> 
> - or please modify the call site so that it is both preceded and
> succeeded by MemoryFence().

I'll update VmgExit() in VmgExitLib.c to add the MemoryFence() calls
around the invocation of AsmVmgExit().

Thanks,
Tom

> 
> With either option implemented:
> 
> Acked-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks
> Laszlo
> 
> 
> 
>> +
>> +  return VmgExitErrorCheck (Ghcb);
>> +}
>> +
>> +VOID
>> +EFIAPI
>> +VmgInit (
>> +  GHCB                *Ghcb
>> +  )
>> +{
>> +  SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
>> +}
>> +
>> +VOID
>> +EFIAPI
>> +VmgDone (
>> +  GHCB                *Ghcb
>> +  )
>> +{
>> +}
>> +
>> +UINTN
>> +EFIAPI
>> +VmgMmio (
>> +  UINT8               *MmioAddress,
>> +  UINT8               *Buffer,
>> +  UINTN               Bytes,
>> +  BOOLEAN             Write
>> +  )
>> +{
>> +  UINT64                    MmioOp;
>> +  UINT64                    ExitInfo1, ExitInfo2;
>> +  UINTN                     Status;
>> +  GHCB                      *Ghcb;
>> +  MSR_SEV_ES_GHCB_REGISTER  Msr;
>> +
>> +  Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
>> +  Ghcb = Msr.Ghcb;
>> +
>> +  if (Write) {
>> +    MmioOp = SvmExitMmioWrite;
>> +  } else {
>> +    MmioOp = SvmExitMmioRead;
>> +  }
>> +
>> +  ExitInfo1 = (UINT64) (UINTN) MmioAddress;
>> +  ExitInfo2 = Bytes;
>> +
>> +  if (Write) {
>> +    CopyMem (Ghcb->SharedBuffer, Buffer, Bytes);
>> +  }
>> +
>> +  Ghcb->SaveArea.SwScratch = (UINT64) (UINTN) Ghcb->SharedBuffer;
>> +  Status = VmgExit (Ghcb, MmioOp, ExitInfo1, ExitInfo2);
>> +  if (Status != 0) {
>> +    return Status;
>> +  }
>> +
>> +  if (!Write) {
>> +    CopyMem (Buffer, Ghcb->SharedBuffer, Bytes);
>> +  }
>> +
>> +  return 0;
>> +}
>> +
>> +VOID
>> +EFIAPI
>> +VmgMmioWrite (
>> +  UINT8               *Dest,
>> +  UINT8               *Src,
>> +  UINTN                Bytes
>> +  )
>> +{
>> +  VmgMmio (Dest, Src, Bytes, TRUE);
>> +}
>> +
>> diff --git a/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
>> new file mode 100644
>> index 000000000000..e8656aae4726
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/VmgExitLib/VmgExitLib.uni
>> @@ -0,0 +1,15 @@
>> +// /** @file
>> +// VMGEXIT support library instance.
>> +//
>> +// VMGEXIT support library instance.
>> +//
>> +// Copyright (c) 2019, Advanced Micro Devices, 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."
>> +
>>
> 
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  2019-11-20 20:06 ` [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector Lendacky, Thomas
@ 2019-11-21 19:27   ` Laszlo Ersek
  2019-11-21 22:49     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-21 19:27 UTC (permalink / raw)
  To: devel, thomas.lendacky
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/20/19 21:06, Lendacky, Thomas wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Reserve a fixed area of memory for the SEV-ES AP reset vector and set
> the fixed PCD, PcdSevEsResetRipBase, to this value.
> 
> A hypervisor is not allowed to update an SEV-ES guest's 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) I suggest replacing "Provide reset vector code" with "Provide
*memory for* reset vector code"

> 
> This new reset vector code is used in place of the original code because

(2) I suggest replacing "reset vector code" with "source file".

> of the include path order set in OvmfPkg/ResetVector/ResetVector.inf
> under "[BuildOptions]".
> 
> 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                       |  3 +
>  OvmfPkg/ResetVector/ResetVector.inf          |  2 +
>  OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 94 ++++++++++++++++++++
>  OvmfPkg/ResetVector/ResetVector.nasmb        |  1 +
>  4 files changed, 100 insertions(+)
>  create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
> 
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 973b19fdbf19..b7618b376430 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -82,6 +82,9 @@ [FD.MEMFD]
>  0x009000|0x002000
>  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
>  
> +0x00B000|0x001000
> +gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize
> +
>  0x010000|0x010000
>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>  
> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
> index 266c5fc5c8b3..284f03c4fb1e 100644
> --- a/OvmfPkg/ResetVector/ResetVector.inf
> +++ b/OvmfPkg/ResetVector/ResetVector.inf
> @@ -36,6 +36,8 @@ [BuildOptions]
>  [Pcd]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
> +  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase
> +  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize

(3) "RipSize" looks quite strange; how about:

- PcdSevEsResetVectorBase
- PcdSevEsResetVectorSize

(i.e. s/Rip/Vector/)


(4) I think the module will not actually use the "size" PCD, so we can
remove it from the INF file.

>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
> diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
> new file mode 100644
> index 000000000000..2a3c9bafb451
> --- /dev/null
> +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
> @@ -0,0 +1,94 @@
> +;------------------------------------------------------------------------------
> +; @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>
> +; 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
> +;
> +; sevEsResetBlock:
> +;   For the initial boot of an AP under SEV-ES, the "reset" RIP must be
> +;   programmed to the RAM area defined by SEV_ES_RESET_IP. A known offset
> +;   and GUID will be used to locate this block in the firmware and extract
> +;   the build time RIP value. The GUID must always be 48 bytes from the
> +;   end of the firmware.
> +;
> +;   0xffffffca (-0x36) - IP value
> +;   0xffffffcc (-0x34) - CS selector value

(5) I think the documentation of these four bytes is incorrect.
(Similarly in the previous patch, in the commit message.) We populate
these bytes with the *linear address* of the "reset trampoline" where
the host will have to boot the AP for the first time. It's not expressed
in real mode CS:IP notation / meaning.


(6) Which brings me to my main point... Value 0x00B000 (for the "base"
PCD) is relative to the base address of FD.MEMFD, namely 8MB (see
MEMFD_BASE_ADDRESS).

IOW, the ultimate value of SEV_ES_RESET_IP will be 0x0x0080_B000. That
address is larger than 1MB.

Therefore, the host will have to launch the AP (for the first time)
above 1MB (in guest-phys address space).

How can that work, if the AP is supposed to start in real mode? The
linear address 0x0x0080_B000 cannot be expressed in 16-bit real mode
CS:IP notation at all.

Does the hypervisor start the AP in "big real mode" (16-bit mode with
4GB segment limits, and CS containing a segment selector, not the actual
segment base)?

... I guess that would answer my question (6) -- and the last few
patches in this series, before this one, *do* suggest "big real mode" to
me --, but the documentation around (5), and in the commit message of
the previous patch, still doesn't match that.

... AFAICS I'm only requesting small cleanups for this patch (naming,
documentation, PCD listing), thus, conditional on everything addressed,
I feel comfortable giving

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

in advance.

Thanks!
Laszlo

> +;   0xffffffce (-0x32) - Size of SEV-ES reset block
> +;   0xffffffd0 (-0x30) - SEV-ES reset block GUID
> +;                        (00f771de-1a7e-4fcb-890e-68c77e2fb44e)
> +;
> +
> +TIMES (32 - (sevEsResetBlockEnd - sevEsResetBlockStart)) DB 0
> +
> +sevEsResetBlockStart:
> +    DD      SEV_ES_RESET_IP
> +    DW      sevEsResetBlockEnd - sevEsResetBlockStart
> +    DB      0xDE, 0x71, 0xF7, 0x00, 0x7E, 0x1A, 0xCB, 0x4F
> +    DB      0x89, 0x0E, 0x68, 0xC7, 0x7E, 0x2F, 0xB4, 0x4E
> +sevEsResetBlockEnd:
> +
> +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
> +;
> +    nop
> +    nop
> +    jmp     EarlyBspInitReal16
> +
> +ALIGN   16
> +
> +fourGigabytes:
> +
> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
> index 708bbda6208f..2bf14681099e 100644
> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
> @@ -81,5 +81,6 @@
>  
>  %include "Main.asm"
>  
> +  %define SEV_ES_RESET_IP  FixedPcdGet32 (PcdSevEsResetRipBase)
>  %include "Ia16/ResetVectorVtf0.asm"
>  
> 


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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-21 12:06   ` [edk2-devel] " Laszlo Ersek
@ 2019-11-21 20:46     ` Lendacky, Thomas
  2019-11-22 12:52       ` Laszlo Ersek
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-21 20:46 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 6:06 AM, Laszlo Ersek wrote:
> On 11/20/19 21:06, Lendacky, Thomas wrote:
>> 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.
>>
>> 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 bae9764577f0..db319030ee58 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,
> 
> (1) The problem here is that we call multiple library APIs before
> calling ProcessLibraryConstructorList() -- namely CopyMem(),
> AsmWriteIdtr(), and InitializeCpuExceptionHandlers().
> 
> (See also the "SetMem" reference in the leading context, in the source
> file -- it is not quoted in this patch.)
> 
> Thus, would it be possible to move all the "+" lines, quoted above, just
> below the ProcessLibraryConstructorList() call?

Unfortunately, I can't. The invocation of ProcessLibraryConstructorList()
results in #VC exceptions and so the exception handler needs to be in
place before invoking ProcessLibraryConstructorList(). It looks like there
are some SerialPort I/O writes to initialize the serial port and some PCI
I/O reads and writes from AcpiTimerLibConstructor() in
OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.c.

> 
> 
> (2) If possible I'd like to restrict the
> InitializeCpuExceptionHandlers() call to SevEsIsEnabled().
> 
> (Unless you're implying that InitializeCpuExceptionHandlers() is useful
> even without SEV-ES -- but then the commit message should be reworded
> accordingly.)

It does give you earlier exception handling and displays the exception
information should an exception occur during SEC.

But, it might require some tricks to somehow communicate from the
ResetVector code to the SecMain code that SEV-ES is enabled. This is
because you need to do a CPUID instruction to determine if SEV-ES is
enabled, which will generate a #VC, which requires an exception handler...

Thanks,
Tom

> 
> If you agree to that restriction, then I further suggest reordering this
> patch against the next one:
> 
>   [edk2-devel] [RFC PATCH v3 31/43]
>   OvmfPkg/Sec: Enable cache early to speed up booting
> 
> Namely, if you put that patch first, then in the present patch you can
> extend the already existing SevEsIsEnabled()-dependent scope, with a
> call to InitializeCpuExceptionHandlers().
> 
> The end result would be something like:
> 
>   ProcessLibraryConstructorList();
> 
>   //
>   // Initialize IDT
>   // ...
>   //
> 
>   if (SevEsIsEnabled()) {
>     //
>     // non-automatic exit events (NAE) can occur during SEC ...
>     //
>     InitializeCpuExceptionHandlers (NULL);
> 
>     //
>     // Under SEV-ES, the hypervisor can't modify CR0 ...
>     //
>     AsmEnableCache ();
>   }
> 
> What's your opinion?
> 
> Thanks!
> Laszlo
> 
>> @@ -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
>>
> 

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

* Re: [edk2-devel] [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled
  2019-11-21 12:31   ` [edk2-devel] " Laszlo Ersek
@ 2019-11-21 21:11     ` Lendacky, Thomas
  2019-11-22 12:20       ` Laszlo Ersek
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-21 21:11 UTC (permalink / raw)
  To: devel, lersek
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 6:31 AM, Laszlo Ersek via Groups.Io wrote:
> On 11/20/19 21:06, Lendacky, Thomas wrote:
>> The flash detection routine will attempt to determine how the flash
>> device behaves (e.g. ROM, RAM, Flash). But when SEV-ES is enabled and
>> the flash device behaves as a ROM device (meaning it is marked read-only
>> by the hypervisor), this check may result in an infinite nested page fault
>> because of the attempted write. Since the instruction cannot be emulated
>> when SEV-ES is enabled, the RIP is never advanced, resulting in repeated
>> nested page faults.
>>
>> When SEV-ES is enabled, exit the flash detection early and assume that
>> the FD behaves as Flash. This will result in QemuFlashWrite() being called
>> to store EFI variables, which will also result in an infinite nested page
>> fault when the write is performed. In this case, update QemuFlashWrite()
>> to use the VmgMmioWrite function from the VmgExitLib library to have the
>> hypervisor perform the write without having to emulate the instruction.
> 
> (1) Please include the Bugzilla link in the commit message:
> 
> https://bugzilla.tianocore.org/show_bug.cgi?id=2198

Yup, will do. I'm also missing the Cc:'s, so I'll add those as well.

> 
>>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>> ---
>>  OvmfPkg/OvmfPkgIa32.dsc                       |  1 +
>>  OvmfPkg/OvmfPkgIa32X64.dsc                    |  1 +
>>  OvmfPkg/OvmfPkgX64.dsc                        |  1 +
>>  .../FvbServicesRuntimeDxe.inf                 |  2 +
>>  .../QemuFlash.c                               | 38 +++++++++++++++++--
>>  5 files changed, 40 insertions(+), 3 deletions(-)
>>
>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>> index 56670eefde6b..ff2814c6246e 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -320,6 +320,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>  
>>  [LibraryClasses.common.UEFI_DRIVER]
>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index 9897e6889573..212952cfaacd 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>  
>>  [LibraryClasses.common.UEFI_DRIVER]
>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index 59c4f9207fc3..8331fc0b663e 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>  
>>  [LibraryClasses.common.UEFI_DRIVER]
>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> index ca6326e833ed..0b7741ac07f8 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> @@ -38,6 +38,7 @@ [Sources]
>>  [Packages]
>>    MdePkg/MdePkg.dec
>>    MdeModulePkg/MdeModulePkg.dec
>> +  UefiCpuPkg/UefiCpuPkg.dec
>>    OvmfPkg/OvmfPkg.dec
>>  
>>  [LibraryClasses]
>> @@ -52,6 +53,7 @@ [LibraryClasses]
>>    UefiBootServicesTableLib
>>    UefiDriverEntryPoint
>>    UefiRuntimeLib
>> +  VmgExitLib
>>  
>>  [Guids]
>>    gEfiEventVirtualAddressChangeGuid   # ALWAYS_CONSUMED
> 
> These hunks look good.
> 
>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> index c81c58972bf2..4f3bf690fcad 100644
>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> @@ -9,7 +9,9 @@
>>  
>>  #include <Library/BaseMemoryLib.h>
>>  #include <Library/DebugLib.h>
>> +#include <Library/MemEncryptSevLib.h>
>>  #include <Library/PcdLib.h>
>> +#include <Library/VmgExitLib.h>
>>  
>>  #include "QemuFlash.h"
>>  
>> @@ -80,6 +82,20 @@ QemuFlashDetected (
>>  
>>    DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
>>  
>> +  if (MemEncryptSevEsIsEnabled()) {
>> +    //
>> +    // When SEV-ES is enabled, the check below can result in an infinite
>> +    // loop with respect to a nested page fault. When the FD behaves as
>> +    // a ROM, the nested page table entry is read-only. The check below
> 
> (2) I suggest a slight change to the wording above. Please replace
> 
>   when the FD behaves as a ROM
> 
> with
> 
>   when the memslot is mapped read-only
> 
> (It's OK to make qemu / kvm references in this code: the name of the
> file includes "Qemu".)

Ok.

> 
>> +    // will cause a nested page fault that cannot be emulated, causing
>> +    // the instruction to retried over and over. For SEV-ES, assume that
>> +    // the FD does not behave as FLASH.
> 
> (3) I would recommend
> 
>   For SEV-ES, acknowledge that the FD appears as ROM and not as FLASH,
>   but report FLASH anyway.

How about if I expand on this to add "because FLASH behavior can be
simulated using VMGEXIT.", too.

> 
>> +    //
>> +    DEBUG ((DEBUG_INFO,
>> +      "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"));
>> +    return TRUE;
>> +  }
>> +
>>    OriginalUint8 = *Ptr;
>>    *Ptr = CLEAR_STATUS_CMD;
>>    ProbeUint8 = *Ptr;
>> @@ -147,6 +163,21 @@ QemuFlashRead (
>>  }
>>  
>>  
>> +STATIC
>> +VOID
>> +QemuFlashPtrWrite (
>> +  IN        volatile UINT8                      *Ptr,
>> +  IN        UINT8                               Value
>> +  )
>> +{
>> +  if (MemEncryptSevEsIsEnabled()) {
>> +    VmgMmioWrite ((UINT8 *) Ptr, &Value, 1);
>> +  } else {
>> +    *Ptr = Value;
>> +  }
>> +}
>> +
>> +
>>  /**
>>    Write to QEMU Flash
>>  
> 
> (4) This change will break the "FvbServicesSmm.inf" build of this module.
> 
> (Because, you have -- correctly -- added the VmgExitLib class to
> "FvbServicesRuntimeDxe.inf" only.)
> 
> Please:
> 
> - create two implementations of the QemuFlashPtrWrite() function, one in
> "QemuFlashDxe.c", and another in "QemuFlashSmm.c".
> 
> - the former should be the function shown above, the latter should only
> perform the direct assignment.
> 
> - the '#include <Library/VmgExitLib.h>' directive should also be moved
> to "QemuFlashDxe.c".
> 
> - the prototype for QemuFlashPtrWrite() should be added to "QemuFlash.h"
> please.

Ah, nice catch.  I'll do that.

Thanks,
Tom

> 
>> @@ -181,8 +212,9 @@ QemuFlashWrite (
>>    //
>>    Ptr = QemuFlashPtr (Lba, Offset);
>>    for (Loop = 0; Loop < *NumBytes; Loop++) {
>> -    *Ptr = WRITE_BYTE_CMD;
>> -    *Ptr = Buffer[Loop];
>> +    QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
>> +    QemuFlashPtrWrite (Ptr, Buffer[Loop]);
>> +
>>      Ptr++;
>>    }
>>  
>> @@ -190,7 +222,7 @@ QemuFlashWrite (
>>    // Restore flash to read mode
>>    //
>>    if (*NumBytes > 0) {
>> -    *(Ptr - 1) = READ_ARRAY_CMD;
>> +    QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
>>    }
>>  
>>    return EFI_SUCCESS;
>>
> 
> With (1) and (4) fixed, and with (2) and (3) optionally fixed (i.e., if
> you agree):
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks
> Laszlo
> 
> 
> 
> 

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

* Re: [edk2-devel] [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  2019-11-21 19:27   ` [edk2-devel] " Laszlo Ersek
@ 2019-11-21 22:49     ` Lendacky, Thomas
  2019-11-22 16:06       ` Laszlo Ersek
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-21 22:49 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 1:27 PM, Laszlo Ersek wrote:
> On 11/20/19 21:06, Lendacky, Thomas wrote:
>> 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%7C0b8d41fe61b5434f088908d76eb8ee62%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637099612867835131&amp;sdata=6A9VajzefK968qLjGCnZ4cAoL4AGGyRbtl%2FLYW2RC6Y%3D&amp;reserved=0
>>
>> Reserve a fixed area of memory for the SEV-ES AP reset vector and set
>> the fixed PCD, PcdSevEsResetRipBase, to this value.
>>
>> A hypervisor is not allowed to update an SEV-ES guest's 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) I suggest replacing "Provide reset vector code" with "Provide
> *memory for* reset vector code"

Will do.

> 
>>
>> This new reset vector code is used in place of the original code because
> 
> (2) I suggest replacing "reset vector code" with "source file".

Yup, makes sense.

> 
>> of the include path order set in OvmfPkg/ResetVector/ResetVector.inf
>> under "[BuildOptions]".
>>
>> 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                       |  3 +
>>  OvmfPkg/ResetVector/ResetVector.inf          |  2 +
>>  OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 94 ++++++++++++++++++++
>>  OvmfPkg/ResetVector/ResetVector.nasmb        |  1 +
>>  4 files changed, 100 insertions(+)
>>  create mode 100644 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>>
>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
>> index 973b19fdbf19..b7618b376430 100644
>> --- a/OvmfPkg/OvmfPkgX64.fdf
>> +++ b/OvmfPkg/OvmfPkgX64.fdf
>> @@ -82,6 +82,9 @@ [FD.MEMFD]
>>  0x009000|0x002000
>>  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
>>  
>> +0x00B000|0x001000
>> +gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize
>> +
>>  0x010000|0x010000
>>  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>>  
>> diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
>> index 266c5fc5c8b3..284f03c4fb1e 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.inf
>> +++ b/OvmfPkg/ResetVector/ResetVector.inf
>> @@ -36,6 +36,8 @@ [BuildOptions]
>>  [Pcd]
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize
>> +  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipBase
>> +  gUefiCpuPkgTokenSpaceGuid.PcdSevEsResetRipSize
> 
> (3) "RipSize" looks quite strange; how about:
> 
> - PcdSevEsResetVectorBase
> - PcdSevEsResetVectorSize
> 
> (i.e. s/Rip/Vector/)

Yup, I'll change that.

> 
> 
> (4) I think the module will not actually use the "size" PCD, so we can
> remove it from the INF file.

Done.

> 
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>> diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>> new file mode 100644
>> index 000000000000..2a3c9bafb451
>> --- /dev/null
>> +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
>> @@ -0,0 +1,94 @@
>> +;------------------------------------------------------------------------------
>> +; @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>
>> +; 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
>> +;
>> +; sevEsResetBlock:
>> +;   For the initial boot of an AP under SEV-ES, the "reset" RIP must be
>> +;   programmed to the RAM area defined by SEV_ES_RESET_IP. A known offset
>> +;   and GUID will be used to locate this block in the firmware and extract
>> +;   the build time RIP value. The GUID must always be 48 bytes from the
>> +;   end of the firmware.
>> +;
>> +;   0xffffffca (-0x36) - IP value
>> +;   0xffffffcc (-0x34) - CS selector value
> 
> (5) I think the documentation of these four bytes is incorrect.
> (Similarly in the previous patch, in the commit message.) We populate
> these bytes with the *linear address* of the "reset trampoline" where
> the host will have to boot the AP for the first time. It's not expressed
> in real mode CS:IP notation / meaning.

This is correct. The code will be in "big real mode" as you note below
(the reset vector is actually 0xfffffff0, just below 4GB and running in
16-bit mode).

If you look in Qemu, target/i386/cpu.c, x86_cpu_reset(), you'll see where
the CS segment is being loaded with a base of 0xffff0000 and the eip gets
loaded with 0xfff0.

So the change to Qemu takes the "CS selector value" and effectively left
shifts it 16-bits to set the base and sets the eip to the "IP value" (in
actuality, Qemu reads this as a 32-bit value starting at the IP value and
ANDs it with 0xffff0000 to get the base and 0x0000ffff to get the eip.

> 
> 
> (6) Which brings me to my main point... Value 0x00B000 (for the "base"
> PCD) is relative to the base address of FD.MEMFD, namely 8MB (see
> MEMFD_BASE_ADDRESS).
> 
> IOW, the ultimate value of SEV_ES_RESET_IP will be 0x0x0080_B000. That
> address is larger than 1MB.

Which is ok since Qemu will set up CS appropriately.

> 
> Therefore, the host will have to launch the AP (for the first time)
> above 1MB (in guest-phys address space).

Which is also OK, just like the BSP was launched at 0xFFFF_FFF0.

> 
> How can that work, if the AP is supposed to start in real mode? The
> linear address 0x0x0080_B000 cannot be expressed in 16-bit real mode
> CS:IP notation at all.
> 
> Does the hypervisor start the AP in "big real mode" (16-bit mode with
> 4GB segment limits, and CS containing a segment selector, not the actual
> segment base)?
> 
> ... I guess that would answer my question (6) -- and the last few
> patches in this series, before this one, *do* suggest "big real mode" to
> me --, but the documentation around (5), and in the commit message of
> the previous patch, still doesn't match that.

I'll expand on the commit message to indicate that Qemu, or others, must
do something similar relative to the CS register setup.

Thanks,
Tom

> 
> ... AFAICS I'm only requesting small cleanups for this patch (naming,
> documentation, PCD listing), thus, conditional on everything addressed,
> I feel comfortable giving
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> in advance.
> 
> Thanks!
> Laszlo
> 
>> +;   0xffffffce (-0x32) - Size of SEV-ES reset block
>> +;   0xffffffd0 (-0x30) - SEV-ES reset block GUID
>> +;                        (00f771de-1a7e-4fcb-890e-68c77e2fb44e)
>> +;
>> +
>> +TIMES (32 - (sevEsResetBlockEnd - sevEsResetBlockStart)) DB 0
>> +
>> +sevEsResetBlockStart:
>> +    DD      SEV_ES_RESET_IP
>> +    DW      sevEsResetBlockEnd - sevEsResetBlockStart
>> +    DB      0xDE, 0x71, 0xF7, 0x00, 0x7E, 0x1A, 0xCB, 0x4F
>> +    DB      0x89, 0x0E, 0x68, 0xC7, 0x7E, 0x2F, 0xB4, 0x4E
>> +sevEsResetBlockEnd:
>> +
>> +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
>> +;
>> +    nop
>> +    nop
>> +    jmp     EarlyBspInitReal16
>> +
>> +ALIGN   16
>> +
>> +fourGigabytes:
>> +
>> diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
>> index 708bbda6208f..2bf14681099e 100644
>> --- a/OvmfPkg/ResetVector/ResetVector.nasmb
>> +++ b/OvmfPkg/ResetVector/ResetVector.nasmb
>> @@ -81,5 +81,6 @@
>>  
>>  %include "Main.asm"
>>  
>> +  %define SEV_ES_RESET_IP  FixedPcdGet32 (PcdSevEsResetRipBase)
>>  %include "Ia16/ResetVectorVtf0.asm"
>>  
>>
> 

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

* Re: [edk2-devel] [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled
  2019-11-21 21:11     ` Lendacky, Thomas
@ 2019-11-22 12:20       ` Laszlo Ersek
  0 siblings, 0 replies; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-22 12:20 UTC (permalink / raw)
  To: Tom Lendacky, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 22:11, Tom Lendacky wrote:
> On 11/21/19 6:31 AM, Laszlo Ersek via Groups.Io wrote:
>> On 11/20/19 21:06, Lendacky, Thomas wrote:
>>> The flash detection routine will attempt to determine how the flash
>>> device behaves (e.g. ROM, RAM, Flash). But when SEV-ES is enabled and
>>> the flash device behaves as a ROM device (meaning it is marked read-only
>>> by the hypervisor), this check may result in an infinite nested page fault
>>> because of the attempted write. Since the instruction cannot be emulated
>>> when SEV-ES is enabled, the RIP is never advanced, resulting in repeated
>>> nested page faults.
>>>
>>> When SEV-ES is enabled, exit the flash detection early and assume that
>>> the FD behaves as Flash. This will result in QemuFlashWrite() being called
>>> to store EFI variables, which will also result in an infinite nested page
>>> fault when the write is performed. In this case, update QemuFlashWrite()
>>> to use the VmgMmioWrite function from the VmgExitLib library to have the
>>> hypervisor perform the write without having to emulate the instruction.
>>
>> (1) Please include the Bugzilla link in the commit message:
>>
>> https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Yup, will do. I'm also missing the Cc:'s, so I'll add those as well.
> 
>>
>>>
>>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  OvmfPkg/OvmfPkgIa32.dsc                       |  1 +
>>>  OvmfPkg/OvmfPkgIa32X64.dsc                    |  1 +
>>>  OvmfPkg/OvmfPkgX64.dsc                        |  1 +
>>>  .../FvbServicesRuntimeDxe.inf                 |  2 +
>>>  .../QemuFlash.c                               | 38 +++++++++++++++++--
>>>  5 files changed, 40 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>>> index 56670eefde6b..ff2814c6246e 100644
>>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>>> @@ -320,6 +320,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>>
>>>  [LibraryClasses.common.UEFI_DRIVER]
>>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>>> index 9897e6889573..212952cfaacd 100644
>>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>>> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>>
>>>  [LibraryClasses.common.UEFI_DRIVER]
>>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>>> index 59c4f9207fc3..8331fc0b663e 100644
>>> --- a/OvmfPkg/OvmfPkgX64.dsc
>>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>>> @@ -325,6 +325,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>>    BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
>>>    PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
>>>    QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
>>> +  VmgExitLib|UefiCpuPkg/Library/VmgExitLib/VmgExitLib.inf
>>>
>>>  [LibraryClasses.common.UEFI_DRIVER]
>>>    PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
>>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>>> index ca6326e833ed..0b7741ac07f8 100644
>>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>>> @@ -38,6 +38,7 @@ [Sources]
>>>  [Packages]
>>>    MdePkg/MdePkg.dec
>>>    MdeModulePkg/MdeModulePkg.dec
>>> +  UefiCpuPkg/UefiCpuPkg.dec
>>>    OvmfPkg/OvmfPkg.dec
>>>
>>>  [LibraryClasses]
>>> @@ -52,6 +53,7 @@ [LibraryClasses]
>>>    UefiBootServicesTableLib
>>>    UefiDriverEntryPoint
>>>    UefiRuntimeLib
>>> +  VmgExitLib
>>>
>>>  [Guids]
>>>    gEfiEventVirtualAddressChangeGuid   # ALWAYS_CONSUMED
>>
>> These hunks look good.
>>
>>> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>>> index c81c58972bf2..4f3bf690fcad 100644
>>> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>>> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>>> @@ -9,7 +9,9 @@
>>>
>>>  #include <Library/BaseMemoryLib.h>
>>>  #include <Library/DebugLib.h>
>>> +#include <Library/MemEncryptSevLib.h>
>>>  #include <Library/PcdLib.h>
>>> +#include <Library/VmgExitLib.h>
>>>
>>>  #include "QemuFlash.h"
>>>
>>> @@ -80,6 +82,20 @@ QemuFlashDetected (
>>>
>>>    DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
>>>
>>> +  if (MemEncryptSevEsIsEnabled()) {
>>> +    //
>>> +    // When SEV-ES is enabled, the check below can result in an infinite
>>> +    // loop with respect to a nested page fault. When the FD behaves as
>>> +    // a ROM, the nested page table entry is read-only. The check below
>>
>> (2) I suggest a slight change to the wording above. Please replace
>>
>>   when the FD behaves as a ROM
>>
>> with
>>
>>   when the memslot is mapped read-only
>>
>> (It's OK to make qemu / kvm references in this code: the name of the
>> file includes "Qemu".)
> 
> Ok.
> 
>>
>>> +    // will cause a nested page fault that cannot be emulated, causing
>>> +    // the instruction to retried over and over. For SEV-ES, assume that
>>> +    // the FD does not behave as FLASH.
>>
>> (3) I would recommend
>>
>>   For SEV-ES, acknowledge that the FD appears as ROM and not as FLASH,
>>   but report FLASH anyway.
> 
> How about if I expand on this to add "because FLASH behavior can be
> simulated using VMGEXIT.", too.

Sure! Thanks!
Laszlo

> 
>>
>>> +    //
>>> +    DEBUG ((DEBUG_INFO,
>>> +      "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"));
>>> +    return TRUE;
>>> +  }
>>> +
>>>    OriginalUint8 = *Ptr;
>>>    *Ptr = CLEAR_STATUS_CMD;
>>>    ProbeUint8 = *Ptr;
>>> @@ -147,6 +163,21 @@ QemuFlashRead (
>>>  }
>>>
>>>
>>> +STATIC
>>> +VOID
>>> +QemuFlashPtrWrite (
>>> +  IN        volatile UINT8                      *Ptr,
>>> +  IN        UINT8                               Value
>>> +  )
>>> +{
>>> +  if (MemEncryptSevEsIsEnabled()) {
>>> +    VmgMmioWrite ((UINT8 *) Ptr, &Value, 1);
>>> +  } else {
>>> +    *Ptr = Value;
>>> +  }
>>> +}
>>> +
>>> +
>>>  /**
>>>    Write to QEMU Flash
>>>
>>
>> (4) This change will break the "FvbServicesSmm.inf" build of this module.
>>
>> (Because, you have -- correctly -- added the VmgExitLib class to
>> "FvbServicesRuntimeDxe.inf" only.)
>>
>> Please:
>>
>> - create two implementations of the QemuFlashPtrWrite() function, one in
>> "QemuFlashDxe.c", and another in "QemuFlashSmm.c".
>>
>> - the former should be the function shown above, the latter should only
>> perform the direct assignment.
>>
>> - the '#include <Library/VmgExitLib.h>' directive should also be moved
>> to "QemuFlashDxe.c".
>>
>> - the prototype for QemuFlashPtrWrite() should be added to "QemuFlash.h"
>> please.
> 
> Ah, nice catch.  I'll do that.
> 
> Thanks,
> Tom
> 
>>
>>> @@ -181,8 +212,9 @@ QemuFlashWrite (
>>>    //
>>>    Ptr = QemuFlashPtr (Lba, Offset);
>>>    for (Loop = 0; Loop < *NumBytes; Loop++) {
>>> -    *Ptr = WRITE_BYTE_CMD;
>>> -    *Ptr = Buffer[Loop];
>>> +    QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
>>> +    QemuFlashPtrWrite (Ptr, Buffer[Loop]);
>>> +
>>>      Ptr++;
>>>    }
>>>
>>> @@ -190,7 +222,7 @@ QemuFlashWrite (
>>>    // Restore flash to read mode
>>>    //
>>>    if (*NumBytes > 0) {
>>> -    *(Ptr - 1) = READ_ARRAY_CMD;
>>> +    QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
>>>    }
>>>
>>>    return EFI_SUCCESS;
>>>
>>
>> With (1) and (4) fixed, and with (2) and (3) optionally fixed (i.e., if
>> you agree):
>>
>> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>>
>> Thanks
>> Laszlo
>>
>>
>> 
>>
> 


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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-21 20:46     ` Lendacky, Thomas
@ 2019-11-22 12:52       ` Laszlo Ersek
  2019-11-22 16:30         ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-22 12:52 UTC (permalink / raw)
  To: Tom Lendacky, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 21:46, Tom Lendacky wrote:
> On 11/21/19 6:06 AM, Laszlo Ersek wrote:
>> On 11/20/19 21:06, Lendacky, Thomas wrote:
>>> 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.
>>>
>>> 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 bae9764577f0..db319030ee58 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,
>>
>> (1) The problem here is that we call multiple library APIs before
>> calling ProcessLibraryConstructorList() -- namely CopyMem(),
>> AsmWriteIdtr(), and InitializeCpuExceptionHandlers().
>>
>> (See also the "SetMem" reference in the leading context, in the
>> source file -- it is not quoted in this patch.)
>>
>> Thus, would it be possible to move all the "+" lines, quoted above,
>> just below the ProcessLibraryConstructorList() call?
>
> Unfortunately, I can't. The invocation of
> ProcessLibraryConstructorList() results in #VC exceptions and so the
> exception handler needs to be in place before invoking
> ProcessLibraryConstructorList(). It looks like there are some
> SerialPort I/O writes to initialize the serial port and some PCI I/O
> reads and writes from AcpiTimerLibConstructor() in
> OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.c.

I have to accept what you're saying, but this makes the code quite
brittle. It's a tenet that we don't call library APIs before the library
constructor had a chance to initialize whatever memory or hardware the
library APIs rely on.

So, in this case,

(a) please add a comment above this block that we're making an exception
with CopyMem(), AsmWriteIdtr() and InitializeCpuExceptionHandlers(),

(b) I'd still like to see this pre-constructor logic restricted to
SEV-ES. (More on that below.)

So something like:

  if (SevEs) {
    //
    // We have to initialize the IDT and set up exception handlers here,
    // i.e. before calling library constructors, because those library
    // constructors may access hardware such that #VC exceptions are
    // triggered.
    //
    // Due to this code executing before library constructors, *all*
    // library API calls are theoretically interface contract
    // violations. However, because we are in SEC (executing in flash),
    // those constructors cannot write variables with static storage
    // duration anyway. Furthermore, we call a small, restricted set of
    // APIs, such as CopyMem(), AsmWriteIdtr(),
    // InitializeCpuExceptionHandlers(), where we require that the
    // underlying library instance not trigger any #VC exceptions.
    //
    InitIdt ();
    InitExceptionHandlers ();
  }
  ProcessLibraryConstructorList ();
  if (!SevEs) {
    InitIdt ();
  }

This makes me feel safer because:
- we're explicit about the principles we (have to) break,
- even our limited assumptions are restricted to SEV-ES.

>
>>
>>
>> (2) If possible I'd like to restrict the
>> InitializeCpuExceptionHandlers() call to SevEsIsEnabled().
>>
>> (Unless you're implying that InitializeCpuExceptionHandlers() is
>> useful even without SEV-ES -- but then the commit message should be
>> reworded accordingly.)
>
> It does give you earlier exception handling and displays the exception
> information should an exception occur during SEC.
>
> But, it might require some tricks to somehow communicate from the
> ResetVector code to the SecMain code that SEV-ES is enabled. This is
> because you need to do a CPUID instruction to determine if SEV-ES is
> enabled, which will generate a #VC, which requires an exception
> handler...

So even *checking* whether SEV-ES is enabled requires a #VC handler to
be set up. Thanks for the reminder. How about this idea: in

  [edk2-devel] [RFC PATCH v3 37/43]
  OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector

you are carving out a page at PcdSevEsResetRipBase -- only in
"OvmfPkgX64.fdf". And, a very small (leading) stretch of that page is
used as the SEV_ES_AP_JMP_FAR structure.

Now, could we implement the following?

(1) Append a UINT8 ("BOOLEAN") field to the SEV_ES_AP_JMP_FAR structure
(and possibly rename the structure),

(2) in the OvmfPkgX64 reset vector, where you determine SEV-ES anyway,
explicitly set this field to zero if SEV-ES is disabled, and set it to
one, if SEV-ES is enabled,

(3) In OvmfPkg/Sec, introduce a new (local) header file declaring the
function SevEsIsEnabled(),

(4) Provide two C-language implementations (under the Ia32 and X64
directories): in the 32-bit version, return constant FALSE; in the
64-bit version, return the value of the new field. Something like:

  return ((SEV_ES_AP_JMP_FAR *)FixedPcdGet32 (PcdSevEsResetRipBase))->SevEsEnabled;

FixedPcdGet32() is explicitly safe to use without library constructors
having run.

Does this look viable? (It might require you to reshuffle patch 37 vs.
patch 30.)

Thanks!
Laszlo

>
> Thanks,
> Tom
>
>>
>> If you agree to that restriction, then I further suggest reordering this
>> patch against the next one:
>>
>>   [edk2-devel] [RFC PATCH v3 31/43]
>>   OvmfPkg/Sec: Enable cache early to speed up booting
>>
>> Namely, if you put that patch first, then in the present patch you can
>> extend the already existing SevEsIsEnabled()-dependent scope, with a
>> call to InitializeCpuExceptionHandlers().
>>
>> The end result would be something like:
>>
>>   ProcessLibraryConstructorList();
>>
>>   //
>>   // Initialize IDT
>>   // ...
>>   //
>>
>>   if (SevEsIsEnabled()) {
>>     //
>>     // non-automatic exit events (NAE) can occur during SEC ...
>>     //
>>     InitializeCpuExceptionHandlers (NULL);
>>
>>     //
>>     // Under SEV-ES, the hypervisor can't modify CR0 ...
>>     //
>>     AsmEnableCache ();
>>   }
>>
>> What's your opinion?
>>
>> Thanks!
>> Laszlo
>>
>>> @@ -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
>>>
>>
>


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

* Re: [edk2-devel] [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  2019-11-21 22:49     ` Lendacky, Thomas
@ 2019-11-22 16:06       ` Laszlo Ersek
  2019-11-22 16:40         ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-22 16:06 UTC (permalink / raw)
  To: Tom Lendacky, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/21/19 23:49, Tom Lendacky wrote:
> On 11/21/19 1:27 PM, Laszlo Ersek wrote:
>> On 11/20/19 21:06, Lendacky, Thomas wrote:

>>> +; sevEsResetBlock:
>>> +;   For the initial boot of an AP under SEV-ES, the "reset" RIP must be
>>> +;   programmed to the RAM area defined by SEV_ES_RESET_IP. A known offset
>>> +;   and GUID will be used to locate this block in the firmware and extract
>>> +;   the build time RIP value. The GUID must always be 48 bytes from the
>>> +;   end of the firmware.
>>> +;
>>> +;   0xffffffca (-0x36) - IP value
>>> +;   0xffffffcc (-0x34) - CS selector value
>>
>> (5) I think the documentation of these four bytes is incorrect.
>> (Similarly in the previous patch, in the commit message.) We populate
>> these bytes with the *linear address* of the "reset trampoline" where
>> the host will have to boot the AP for the first time. It's not
>> expressed in real mode CS:IP notation / meaning.
>
> This is correct. The code will be in "big real mode" as you note below
> (the reset vector is actually 0xfffffff0, just below 4GB and running
> in 16-bit mode).
>
> If you look in Qemu, target/i386/cpu.c, x86_cpu_reset(), you'll see
> where the CS segment is being loaded with a base of 0xffff0000 and the
> eip gets loaded with 0xfff0.

That still doesn't explain the above field names to me ("IP value" and
"CS selector value"). Once the firmware image is built, we have:

- CS: 0x0080
- IP: 0xB000

I don't understand the CS=0x80 part as
- either a genuine segment selector
- or the linear segment base address 0x800 (formed per real-address
  mode).

> So the change to Qemu takes the "CS selector value" and effectively
> left shifts it 16-bits to set the base

This logic seems correct, as it translates 0x80 to 0x80_0000, i.e. 8 MB.

However, I still think it's wrong to call the 16-bit value 0x0080 that
we store at 0xffff_ffcc a "CS selector value". It is not a CS selector
value, because it neither points into a segment descriptor table, nor is
it left-shifted by 4-bits to form a linear base address, as in
real-address mode.

I would call this field

  most significant 16 bits of the CS base address                    [1]

> and sets the eip to the "IP value" (in actuality, Qemu reads this as a
> 32-bit value starting at the IP value and ANDs it with 0xffff0000 to
> get the base and 0x0000ffff to get the eip.

That seems correct to me.

So... to summarize my point (5), *all* I'm asking for is to change the
field description from "CS selector value" to [1] (or something to the
same effect).

>
>>
>>
>> (6) Which brings me to my main point... Value 0x00B000 (for the
>> "base" PCD) is relative to the base address of FD.MEMFD, namely 8MB
>> (see MEMFD_BASE_ADDRESS).
>>
>> IOW, the ultimate value of SEV_ES_RESET_IP will be 0x0x0080_B000.
>> That address is larger than 1MB.
>
> Which is ok since Qemu will set up CS appropriately.
>
>>
>> Therefore, the host will have to launch the AP (for the first time)
>> above 1MB (in guest-phys address space).
>
> Which is also OK, just like the BSP was launched at 0xFFFF_FFF0.
>
>>
>> How can that work, if the AP is supposed to start in real mode? The
>> linear address 0x0x0080_B000 cannot be expressed in 16-bit real mode
>> CS:IP notation at all.
>>
>> Does the hypervisor start the AP in "big real mode" (16-bit mode with
>> 4GB segment limits, and CS containing a segment selector, not the
>> actual segment base)?

Actually, I have to retract my question (6), because here I got lost in
the weeds. I keep forgetting the following quirk in the Intel SDM:

    9.1.4 First Instruction Executed

    The first instruction that is fetched and executed following a
    hardware reset is located at physical address FFFFFFF0H. This
    address is 16 bytes below the processors uppermost physical address.
    The EPROM containing the software- initialization code must be
    located at this address.

    The address FFFFFFF0H is beyond the 1-MByte addressable range of the
    processor while in real-address mode. The processor is initialized
    to this starting address as follows. The CS register has two parts:
    the visible segment selector part and the hidden base address part.
    In real-address mode, the base address is normally formed by
    shifting the 16-bit segment selector value 4 bits to the left to
    produce a 20-bit base address. However, during a hardware reset, the
    segment selector in the CS register is loaded with F000H and the
    base address is loaded with FFFF0000H. The starting address is thus
    formed by adding the base address to the value in the EIP register
    (that is, FFFF0000 + FFF0H = FFFFFFF0H).

    The first time the CS register is loaded with a new value after a
    hardware reset, the processor will follow the normal rule for
    address translation in real-address mode (that is, [CS base address
    = CS segment selector * 16]). To insure that the base address in the
    CS register remains unchanged until the EPROM based software-
    initialization code is completed, the code must not contain a far
    jump or far call or allow an interrupt to occur (which would cause
    the CS selector value to be changed).

I need to be reminded of this every once in a while!

While reviewing your patch, I thought that in real mode, the CS base
address played no part, only the CS selector did -- which would be
left-shifted by 4 bits directly, to form the segment base, in
real-address mode.

However, the fact is that the CS base address *always* plays a part
(even in real mode). The "left shifting by 4 bits" does not occur when
the CS:IP *reference* is made, but when the CS register is *loaded*
explicitly, in real-address mode.

And, at reset, CS is *pre-loaded*
- with selector=0xF000, and
- (as a quirk!) with base=0xFFFF_0000 (and *not* with base=0xF_0000, as
  the selector would otherwise dictate in real-address mode).

And the QEMU change is that, at first AP boot, the CS will be pre-loaded
- with selector=0x80 (which is a complete happenstance -- it's
  irrelevant!),
- and, importantly, with base=0x80_0000 (and *not* with base=0x800, as
  the selector would otherwise dictate in real-address mode).

So, it's all clear now (as long as you can please confirm that my
understanding is finally correct).

Thus, question (6) falls away.

>> ... I guess that would answer my question (6) -- and the last few
>> patches in this series, before this one, *do* suggest "big real mode"
>> to me --, but the documentation around (5), and in the commit message
>> of the previous patch, still doesn't match that.
>
> I'll expand on the commit message to indicate that Qemu, or others,
> must do something similar relative to the CS register setup.

To summarize, my request would be:

- in the previous patch, please replace, in the commit message,

    Reset CS

  with

    most significant 16 bits of the reset CS base address

- in this patch, please replace, in the code comment,

    CS selector value

  with

    most significant 16 bits of the CS base address

(I mean... you *could* keep the current language in both places, but
then you would have to describe this *entirely new* quirk for forming
the CS base address from the CS selector value. This new SEV-ES / QEMU
method does not match *any* { CS selector --> CS base address }
transformation from the SDM, so you'd have to be quite verbose in the
documenation.

Given that the CS selector value 0x80 is completely irrelevant here, and
we only care about the ultimate CS base address 0x80_0000, I'd suggest
defining the 16-bit field at 0xffffffcc in terms of the desired CS base
address [1], and not once mentioning "selector".)

Thanks!
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-22 12:52       ` Laszlo Ersek
@ 2019-11-22 16:30         ` Lendacky, Thomas
  2019-11-22 21:10           ` Laszlo Ersek
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-22 16:30 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/22/19 6:52 AM, Laszlo Ersek wrote:
> On 11/21/19 21:46, Tom Lendacky wrote:
>> On 11/21/19 6:06 AM, Laszlo Ersek wrote:
>>> On 11/20/19 21:06, Lendacky, Thomas wrote:
>>>> 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%7C86943210aff44681d5b908d76f4acf49%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637100239406633853&amp;sdata=8APpMBall%2F2urZh6V3kpuWpsBjOh8GVqhWGNBjL%2B30U%3D&amp;reserved=0
>>>>
>>>> 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.
>>>>
>>>> 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 bae9764577f0..db319030ee58 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,
>>>
>>> (1) The problem here is that we call multiple library APIs before
>>> calling ProcessLibraryConstructorList() -- namely CopyMem(),
>>> AsmWriteIdtr(), and InitializeCpuExceptionHandlers().

We can reduce this exposure a bit and replace the CopyMem() call with
something similar to the loop above it.  I could also use assembler
code directly in here to load the IDTR.

That would leave just InitializeCpuExceptionHandlers(). Is there
something that can added so as to warn when a library has a
CONSTRUCTOR added to/part of the definition?

>>>
>>> (See also the "SetMem" reference in the leading context, in the
>>> source file -- it is not quoted in this patch.)
>>>
>>> Thus, would it be possible to move all the "+" lines, quoted above,
>>> just below the ProcessLibraryConstructorList() call?
>>
>> Unfortunately, I can't. The invocation of
>> ProcessLibraryConstructorList() results in #VC exceptions and so the
>> exception handler needs to be in place before invoking
>> ProcessLibraryConstructorList(). It looks like there are some
>> SerialPort I/O writes to initialize the serial port and some PCI I/O
>> reads and writes from AcpiTimerLibConstructor() in
>> OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.c.
> 
> I have to accept what you're saying, but this makes the code quite
> brittle. It's a tenet that we don't call library APIs before the library
> constructor had a chance to initialize whatever memory or hardware the
> library APIs rely on.
> 
> So, in this case,
> 
> (a) please add a comment above this block that we're making an exception
> with CopyMem(), AsmWriteIdtr() and InitializeCpuExceptionHandlers(),

Can do.

> 
> (b) I'd still like to see this pre-constructor logic restricted to
> SEV-ES. (More on that below.)

Yup, propagating the SEV-ES status from the ResetVector seems to be the
way to go.

> 
> So something like:
> 
>    if (SevEs) {
>      //
>      // We have to initialize the IDT and set up exception handlers here,
>      // i.e. before calling library constructors, because those library
>      // constructors may access hardware such that #VC exceptions are
>      // triggered.
>      //
>      // Due to this code executing before library constructors, *all*
>      // library API calls are theoretically interface contract
>      // violations. However, because we are in SEC (executing in flash),
>      // those constructors cannot write variables with static storage
>      // duration anyway. Furthermore, we call a small, restricted set of
>      // APIs, such as CopyMem(), AsmWriteIdtr(),
>      // InitializeCpuExceptionHandlers(), where we require that the
>      // underlying library instance not trigger any #VC exceptions.
>      //
>      InitIdt ();
>      InitExceptionHandlers ();
>    }
>    ProcessLibraryConstructorList ();
>    if (!SevEs) {
>      InitIdt ();
>    }
> 
> This makes me feel safer because:
> - we're explicit about the principles we (have to) break,
> - even our limited assumptions are restricted to SEV-ES.
> 
>>
>>>
>>>
>>> (2) If possible I'd like to restrict the
>>> InitializeCpuExceptionHandlers() call to SevEsIsEnabled().
>>>
>>> (Unless you're implying that InitializeCpuExceptionHandlers() is
>>> useful even without SEV-ES -- but then the commit message should be
>>> reworded accordingly.)
>>
>> It does give you earlier exception handling and displays the exception
>> information should an exception occur during SEC.
>>
>> But, it might require some tricks to somehow communicate from the
>> ResetVector code to the SecMain code that SEV-ES is enabled. This is
>> because you need to do a CPUID instruction to determine if SEV-ES is
>> enabled, which will generate a #VC, which requires an exception
>> handler...
> 
> So even *checking* whether SEV-ES is enabled requires a #VC handler to
> be set up. Thanks for the reminder. How about this idea: in
> 
>    [edk2-devel] [RFC PATCH v3 37/43]
>    OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
> 
> you are carving out a page at PcdSevEsResetRipBase -- only in
> "OvmfPkgX64.fdf". And, a very small (leading) stretch of that page is
> used as the SEV_ES_AP_JMP_FAR structure.
> 
> Now, could we implement the following?
> 
> (1) Append a UINT8 ("BOOLEAN") field to the SEV_ES_AP_JMP_FAR structure
> (and possibly rename the structure),
> 
> (2) in the OvmfPkgX64 reset vector, where you determine SEV-ES anyway,
> explicitly set this field to zero if SEV-ES is disabled, and set it to
> one, if SEV-ES is enabled,
> 
> (3) In OvmfPkg/Sec, introduce a new (local) header file declaring the
> function SevEsIsEnabled(),
> 
> (4) Provide two C-language implementations (under the Ia32 and X64
> directories): in the 32-bit version, return constant FALSE; in the
> 64-bit version, return the value of the new field. Something like:
> 
>    return ((SEV_ES_AP_JMP_FAR *)FixedPcdGet32 (PcdSevEsResetRipBase))->SevEsEnabled;
> 
> FixedPcdGet32() is explicitly safe to use without library constructors
> having run.
> 
> Does this look viable? (It might require you to reshuffle patch 37 vs.
> patch 30.)

I think this does. Since this is SEC and the reset vector page isn't
needed until PEI and later we could even just use the first byte (make a
union with an SEC usage field) and make this even simpler. Then we don't
have to worry about positioning it. Let me work on that and see where I
get. Anything after the #VC is established would use the current method
of determine SEV-ES status.

Thanks!
Tom

> 
> Thanks!
> Laszlo
> 
>>
>> Thanks,
>> Tom
>>
>>>
>>> If you agree to that restriction, then I further suggest reordering this
>>> patch against the next one:
>>>
>>>    [edk2-devel] [RFC PATCH v3 31/43]
>>>    OvmfPkg/Sec: Enable cache early to speed up booting
>>>
>>> Namely, if you put that patch first, then in the present patch you can
>>> extend the already existing SevEsIsEnabled()-dependent scope, with a
>>> call to InitializeCpuExceptionHandlers().
>>>
>>> The end result would be something like:
>>>
>>>    ProcessLibraryConstructorList();
>>>
>>>    //
>>>    // Initialize IDT
>>>    // ...
>>>    //
>>>
>>>    if (SevEsIsEnabled()) {
>>>      //
>>>      // non-automatic exit events (NAE) can occur during SEC ...
>>>      //
>>>      InitializeCpuExceptionHandlers (NULL);
>>>
>>>      //
>>>      // Under SEV-ES, the hypervisor can't modify CR0 ...
>>>      //
>>>      AsmEnableCache ();
>>>    }
>>>
>>> What's your opinion?
>>>
>>> Thanks!
>>> Laszlo
>>>
>>>> @@ -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
>>>>
>>>
>>
> 

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

* Re: [edk2-devel] [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector
  2019-11-22 16:06       ` Laszlo Ersek
@ 2019-11-22 16:40         ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-22 16:40 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/22/19 10:06 AM, Laszlo Ersek wrote:
> On 11/21/19 23:49, Tom Lendacky wrote:
>> On 11/21/19 1:27 PM, Laszlo Ersek wrote:
>>> On 11/20/19 21:06, Lendacky, Thomas wrote:
> 
>>>> +; sevEsResetBlock:
>>>> +;   For the initial boot of an AP under SEV-ES, the "reset" RIP must be
>>>> +;   programmed to the RAM area defined by SEV_ES_RESET_IP. A known offset
>>>> +;   and GUID will be used to locate this block in the firmware and extract
>>>> +;   the build time RIP value. The GUID must always be 48 bytes from the
>>>> +;   end of the firmware.
>>>> +;
>>>> +;   0xffffffca (-0x36) - IP value
>>>> +;   0xffffffcc (-0x34) - CS selector value
>>>
>>> (5) I think the documentation of these four bytes is incorrect.
>>> (Similarly in the previous patch, in the commit message.) We populate
>>> these bytes with the *linear address* of the "reset trampoline" where
>>> the host will have to boot the AP for the first time. It's not
>>> expressed in real mode CS:IP notation / meaning.
>>
>> This is correct. The code will be in "big real mode" as you note below
>> (the reset vector is actually 0xfffffff0, just below 4GB and running
>> in 16-bit mode).
>>
>> If you look in Qemu, target/i386/cpu.c, x86_cpu_reset(), you'll see
>> where the CS segment is being loaded with a base of 0xffff0000 and the
>> eip gets loaded with 0xfff0.
> 
> That still doesn't explain the above field names to me ("IP value" and
> "CS selector value"). Once the firmware image is built, we have:
> 
> - CS: 0x0080
> - IP: 0xB000
> 
> I don't understand the CS=0x80 part as
> - either a genuine segment selector
> - or the linear segment base address 0x800 (formed per real-address
>    mode).
> 
>> So the change to Qemu takes the "CS selector value" and effectively
>> left shifts it 16-bits to set the base
> 
> This logic seems correct, as it translates 0x80 to 0x80_0000, i.e. 8 MB.
> 
> However, I still think it's wrong to call the 16-bit value 0x0080 that
> we store at 0xffff_ffcc a "CS selector value". It is not a CS selector
> value, because it neither points into a segment descriptor table, nor is
> it left-shifted by 4-bits to form a linear base address, as in
> real-address mode.
> 
> I would call this field
> 
>    most significant 16 bits of the CS base address                    [1]
> 
>> and sets the eip to the "IP value" (in actuality, Qemu reads this as a
>> 32-bit value starting at the IP value and ANDs it with 0xffff0000 to
>> get the base and 0x0000ffff to get the eip.
> 
> That seems correct to me.
> 
> So... to summarize my point (5), *all* I'm asking for is to change the
> field description from "CS selector value" to [1] (or something to the
> same effect).
> 
>>
>>>
>>>
>>> (6) Which brings me to my main point... Value 0x00B000 (for the
>>> "base" PCD) is relative to the base address of FD.MEMFD, namely 8MB
>>> (see MEMFD_BASE_ADDRESS).
>>>
>>> IOW, the ultimate value of SEV_ES_RESET_IP will be 0x0x0080_B000.
>>> That address is larger than 1MB.
>>
>> Which is ok since Qemu will set up CS appropriately.
>>
>>>
>>> Therefore, the host will have to launch the AP (for the first time)
>>> above 1MB (in guest-phys address space).
>>
>> Which is also OK, just like the BSP was launched at 0xFFFF_FFF0.
>>
>>>
>>> How can that work, if the AP is supposed to start in real mode? The
>>> linear address 0x0x0080_B000 cannot be expressed in 16-bit real mode
>>> CS:IP notation at all.
>>>
>>> Does the hypervisor start the AP in "big real mode" (16-bit mode with
>>> 4GB segment limits, and CS containing a segment selector, not the
>>> actual segment base)?
> 
> Actually, I have to retract my question (6), because here I got lost in
> the weeds. I keep forgetting the following quirk in the Intel SDM:
> 
>      9.1.4 First Instruction Executed
> 
>      The first instruction that is fetched and executed following a
>      hardware reset is located at physical address FFFFFFF0H. This
>      address is 16 bytes below the processors uppermost physical address.
>      The EPROM containing the software- initialization code must be
>      located at this address.
> 
>      The address FFFFFFF0H is beyond the 1-MByte addressable range of the
>      processor while in real-address mode. The processor is initialized
>      to this starting address as follows. The CS register has two parts:
>      the visible segment selector part and the hidden base address part.
>      In real-address mode, the base address is normally formed by
>      shifting the 16-bit segment selector value 4 bits to the left to
>      produce a 20-bit base address. However, during a hardware reset, the
>      segment selector in the CS register is loaded with F000H and the
>      base address is loaded with FFFF0000H. The starting address is thus
>      formed by adding the base address to the value in the EIP register
>      (that is, FFFF0000 + FFF0H = FFFFFFF0H).
> 
>      The first time the CS register is loaded with a new value after a
>      hardware reset, the processor will follow the normal rule for
>      address translation in real-address mode (that is, [CS base address
>      = CS segment selector * 16]). To insure that the base address in the
>      CS register remains unchanged until the EPROM based software-
>      initialization code is completed, the code must not contain a far
>      jump or far call or allow an interrupt to occur (which would cause
>      the CS selector value to be changed).
> 
> I need to be reminded of this every once in a while!
> 
> While reviewing your patch, I thought that in real mode, the CS base
> address played no part, only the CS selector did -- which would be
> left-shifted by 4 bits directly, to form the segment base, in
> real-address mode.
> 
> However, the fact is that the CS base address *always* plays a part
> (even in real mode). The "left shifting by 4 bits" does not occur when
> the CS:IP *reference* is made, but when the CS register is *loaded*
> explicitly, in real-address mode.
> 
> And, at reset, CS is *pre-loaded*
> - with selector=0xF000, and
> - (as a quirk!) with base=0xFFFF_0000 (and *not* with base=0xF_0000, as
>    the selector would otherwise dictate in real-address mode).
> 
> And the QEMU change is that, at first AP boot, the CS will be pre-loaded
> - with selector=0x80 (which is a complete happenstance -- it's
>    irrelevant!),
> - and, importantly, with base=0x80_0000 (and *not* with base=0x800, as
>    the selector would otherwise dictate in real-address mode).
> 
> So, it's all clear now (as long as you can please confirm that my
> understanding is finally correct).
> 
> Thus, question (6) falls away.
> 
>>> ... I guess that would answer my question (6) -- and the last few
>>> patches in this series, before this one, *do* suggest "big real mode"
>>> to me --, but the documentation around (5), and in the commit message
>>> of the previous patch, still doesn't match that.
>>
>> I'll expand on the commit message to indicate that Qemu, or others,
>> must do something similar relative to the CS register setup.
> 
> To summarize, my request would be:
> 
> - in the previous patch, please replace, in the commit message,
> 
>      Reset CS
> 
>    with
> 
>      most significant 16 bits of the reset CS base address
> 
> - in this patch, please replace, in the code comment,
> 
>      CS selector value
> 
>    with
> 
>      most significant 16 bits of the CS base address
> 
> (I mean... you *could* keep the current language in both places, but
> then you would have to describe this *entirely new* quirk for forming
> the CS base address from the CS selector value. This new SEV-ES / QEMU
> method does not match *any* { CS selector --> CS base address }
> transformation from the SDM, so you'd have to be quite verbose in the
> documenation.
> 
> Given that the CS selector value 0x80 is completely irrelevant here, and
> we only care about the ultimate CS base address 0x80_0000, I'd suggest
> defining the 16-bit field at 0xffffffcc in terms of the desired CS base
> address [1], and not once mentioning "selector".)

Let me work on the wording and see what I come up with. I'll pass it by
you to see if it makes sense.

Thanks,
Tom

> 
> Thanks!
> Laszlo
> 

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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-22 16:30         ` Lendacky, Thomas
@ 2019-11-22 21:10           ` Laszlo Ersek
  2019-11-22 22:48             ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Laszlo Ersek @ 2019-11-22 21:10 UTC (permalink / raw)
  To: Tom Lendacky, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/22/19 17:30, Tom Lendacky wrote:
> On 11/22/19 6:52 AM, Laszlo Ersek wrote:
>> On 11/21/19 21:46, Tom Lendacky wrote:
>>> On 11/21/19 6:06 AM, Laszlo Ersek wrote:
>>>> On 11/20/19 21:06, Lendacky, Thomas wrote:

>>>>> @@ -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,
>>>>
>>>> (1) The problem here is that we call multiple library APIs before
>>>> calling ProcessLibraryConstructorList() -- namely CopyMem(),
>>>> AsmWriteIdtr(), and InitializeCpuExceptionHandlers().
> 
> We can reduce this exposure a bit and replace the CopyMem() call with
> something similar to the loop above it.

That would be nice, if you're not too annoyed by the extra busywork.

> I could also use assembler code directly in here to load the IDTR.

I think it would be enough to copy

  MdePkg/Library/BaseLib/Ia32/WriteIdtr.nasm
  MdePkg/Library/BaseLib/X64/WriteIdtr.nasm

under OvmfPkg/Sec, and use a new function name.

> That would leave just InitializeCpuExceptionHandlers(). Is there
> something that can added so as to warn when a library has a
> CONSTRUCTOR added to/part of the definition?

Nothing comes to my mind :(

[...]

>> (1) Append a UINT8 ("BOOLEAN") field to the SEV_ES_AP_JMP_FAR structure
>> (and possibly rename the structure),
>>
>> (2) in the OvmfPkgX64 reset vector, where you determine SEV-ES anyway,
>> explicitly set this field to zero if SEV-ES is disabled, and set it to
>> one, if SEV-ES is enabled,
>>
>> (3) In OvmfPkg/Sec, introduce a new (local) header file declaring the
>> function SevEsIsEnabled(),
>>
>> (4) Provide two C-language implementations (under the Ia32 and X64
>> directories): in the 32-bit version, return constant FALSE; in the
>> 64-bit version, return the value of the new field. Something like:
>>
>>    return ((SEV_ES_AP_JMP_FAR *)FixedPcdGet32
>> (PcdSevEsResetRipBase))->SevEsEnabled;
>>
>> FixedPcdGet32() is explicitly safe to use without library constructors
>> having run.
>>
>> Does this look viable? (It might require you to reshuffle patch 37 vs.
>> patch 30.)
> 
> I think this does. Since this is SEC and the reset vector page isn't
> needed until PEI and later we could even just use the first byte (make a
> union with an SEC usage field) and make this even simpler. Then we don't
> have to worry about positioning it.

Ah, nice.

> Let me work on that and see where I
> get. Anything after the #VC is established would use the current method
> of determine SEV-ES status.

Thanks!
Laszlo


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

* Re: [edk2-devel] [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase
  2019-11-22 21:10           ` Laszlo Ersek
@ 2019-11-22 22:48             ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-11-22 22:48 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: Jordan Justen, Ard Biesheuvel, Michael D Kinney, Liming Gao,
	Eric Dong, Ray Ni, Brijesh Singh

On 11/22/19 3:10 PM, Laszlo Ersek wrote:
> On 11/22/19 17:30, Tom Lendacky wrote:
>> On 11/22/19 6:52 AM, Laszlo Ersek wrote:
>>> On 11/21/19 21:46, Tom Lendacky wrote:
>>>> On 11/21/19 6:06 AM, Laszlo Ersek wrote:
>>>>> On 11/20/19 21:06, Lendacky, Thomas wrote:
> 
>>>>>> @@ -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,
>>>>>
>>>>> (1) The problem here is that we call multiple library APIs before
>>>>> calling ProcessLibraryConstructorList() -- namely CopyMem(),
>>>>> AsmWriteIdtr(), and InitializeCpuExceptionHandlers().
>>
>> We can reduce this exposure a bit and replace the CopyMem() call with
>> something similar to the loop above it.
> 
> That would be nice, if you're not too annoyed by the extra busywork.
> 
>> I could also use assembler code directly in here to load the IDTR.
> 
> I think it would be enough to copy
> 
>    MdePkg/Library/BaseLib/Ia32/WriteIdtr.nasm
>    MdePkg/Library/BaseLib/X64/WriteIdtr.nasm
> 
> under OvmfPkg/Sec, and use a new function name.
> 
>> That would leave just InitializeCpuExceptionHandlers(). Is there
>> something that can added so as to warn when a library has a
>> CONSTRUCTOR added to/part of the definition?
> 
> Nothing comes to my mind :(
> 
> [...]
> 
>>> (1) Append a UINT8 ("BOOLEAN") field to the SEV_ES_AP_JMP_FAR structure
>>> (and possibly rename the structure),
>>>
>>> (2) in the OvmfPkgX64 reset vector, where you determine SEV-ES anyway,
>>> explicitly set this field to zero if SEV-ES is disabled, and set it to
>>> one, if SEV-ES is enabled,
>>>
>>> (3) In OvmfPkg/Sec, introduce a new (local) header file declaring the
>>> function SevEsIsEnabled(),
>>>
>>> (4) Provide two C-language implementations (under the Ia32 and X64
>>> directories): in the 32-bit version, return constant FALSE; in the
>>> 64-bit version, return the value of the new field. Something like:
>>>
>>>     return ((SEV_ES_AP_JMP_FAR *)FixedPcdGet32
>>> (PcdSevEsResetRipBase))->SevEsEnabled;
>>>
>>> FixedPcdGet32() is explicitly safe to use without library constructors
>>> having run.
>>>
>>> Does this look viable? (It might require you to reshuffle patch 37 vs.
>>> patch 30.)
>>
>> I think this does. Since this is SEC and the reset vector page isn't
>> needed until PEI and later we could even just use the first byte (make a
>> union with an SEC usage field) and make this even simpler. Then we don't
>> have to worry about positioning it.
> 
> Ah, nice.

I haven't done the WriteIdtr() stuff, yet, but the passing of the SEV-ES
status from the ResetVector code to the SEC code via the SEV-ES page at
0x0080_B000 is working nicely.

Thanks,
Tom

> 
>> Let me work on that and see where I
>> get. Anything after the #VC is established would use the current method
>> of determine SEV-ES status.
> 
> Thanks!
> Laszlo
> 

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

* Re: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-11-20 20:06 ` [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
@ 2019-12-12  6:53   ` Ni, Ray
  2019-12-12 20:27     ` Lendacky, Thomas
  2019-12-12  6:53   ` Ni, Ray
  1 sibling, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:53 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh

> 
>  ;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
> +    cmp     qword [rbp + 8], 29

Can you define a macro instead of using 29?

> +    je      VcDebugRegs          ; For SEV-ES (#VC) Debug registers ignored



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

* Re: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
  2019-11-20 20:06 ` [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
@ 2019-12-12  6:53   ` Ni, Ray
  2019-12-12 20:48     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:53 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A

Do you really need to define the PCD in MdePkg?
General guide lines are:
1. Avoid UefiCpuPkg depend on MdeModulePkg.
2. Do not define platform level PCD in core pkgs (MdePkg, MdeModulePkg, UefiCpuPkg, etc)


PcdSevEsIsEnabled seems to be used in OVMF pkg only so how about define that in OvmfPkg.dec?

Thanks,
Ray

> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Thursday, November 21, 2019 4:06 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>
> Subject: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Two new fixed PCSs are needed to support SEV-ES under OVMF:
>   - PcdSecGhcbBase  UINT64 value that is the base address of the GHCB
>                     used during the SEC phase.
>   - PcdSecGhcbSize  UINT64 value that is the size, in bytes, of the GHCB
>                     area used during the SEC phase.
> 
> Three new dynamic PCDs are needed to support SEV-ES under OVMF:
>   - PcdSevEsIsEnabled: BOOLEAN value used to indicate if SEV-ES is enabled
>   - 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 | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
> index 41b9e70a1ac8..c3bdfcc80971 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -1037,6 +1037,14 @@ [PcdsFixedAtBuild]
>    # @Prompt Enable UEFI Stack Guard.
>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055
> 
> +  ## The base address of the SEC GHCB page.
> +  # @Prompt SEC GHCB Base Address
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|0|UINT32|0x30001056
> +
> +  ## The total size of the SEC GHCB page.
> +  # @Prompt SEC GHCB Size
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize|0|UINT32|0x30001057
> +
>  [PcdsFixedAtBuild, PcdsPatchableInModule]
>    ## Dynamic type PCD can be registered callback function for Pcd setting action.
>    #  PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
> @@ -2053,6 +2061,21 @@ [PcdsDynamic, PcdsDynamicEx]
>    # @Prompt If there is any test key used by the platform.
>    gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed|FALSE|BOOLEAN|0x00030003
> 
> +  ## This dynamic PCD indicates whether SEV-ES is enabled
> +  #   TRUE  - SEV-ES is enabled
> +  #   FALSE - SEV-ES is not enabled
> +  # @Prompt SEV-ES Status
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x00030007
> +
> +  ## This dynamic PCD holds the base address of the GHCB pool allocation.
> +  # @Prompt GHCB Pool Base Address
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00030008
> +
> +  ## This dynamic PCD holds the total size of the GHCB pool allocation.
> +  #  The amount of memory allocated for GHCBs is dependent on the number of APs.
> +  # @Prompt GHCB Pool Size
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030009
> +
>  [PcdsDynamicEx]
>    ## This dynamic PCD enables the default variable setting.
>    #  Its value is the default store ID value. The default value is zero as Standard default.
> --
> 2.17.1


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

* Re: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-11-20 20:06 ` [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
  2019-12-12  6:53   ` Ni, Ray
@ 2019-12-12  6:53   ` Ni, Ray
  2019-12-12 20:39     ` Lendacky, Thomas
  1 sibling, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:53 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh

Tom,
Why all DR registers are not pushed to stack in VC handler?
I thought only DR7 pushing is skipped.

Thanks,
Ray

> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>
> Subject: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
> 
> 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 1d7c34e7e442..22393f72d795 100644
> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
> @@ -13,6 +13,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,
> @@ -1081,6 +1087,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,
> @@ -1097,6 +1157,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 19198f273137..a0549f7ae6bd 100644
> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> @@ -225,6 +225,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
> @@ -237,7 +240,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	[flat|nested] 82+ messages in thread

* Re: [edk2-devel] [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  2019-11-20 20:06 ` [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
@ 2019-12-12  6:53   ` Ni, Ray
  2019-12-12 20:58     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:53 UTC (permalink / raw)
  To: devel@edk2.groups.io, thomas.lendacky@amd.com
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A,
	Bi, Dandan

Tom,
When are GHCP pages are allocated? Can DxeIpl gets the address by reading the GHCB MSR?

Can the GHCB PCD be eliminated by updating all GHCB address consumer to read the GHCB MSR?

Thanks,
Ray

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lendacky, Thomas
> Sent: Thursday, November 21, 2019 4:06 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
> Subject: [edk2-devel] [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
> 
> 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 6e8ca824d469..284b34818ca7 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
> @@ -282,7 +282,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 f465eb1d8ac4..156a477d8467 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;
> 
>    //
>    // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
> @@ -81,12 +83,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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-11-20 20:06 ` [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
@ 2019-12-12  6:54   ` Ni, Ray
  2019-12-12 21:03     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:54 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh

> +  // Allocate GHCB and per-CPU variable pages.
> +  //
> +  GhcbPageCount = mMaxCpuCount * 2;
> +  GhcbBase = AllocatePages (GhcbPageCount);
> +  ASSERT (GhcbBase != NULL);
> +
> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
> +
> +  DecryptStatus = MemEncryptSevClearPageEncMask (
> +    0,
> +    GhcbBasePa,
> +    GhcbPageCount,
> +    TRUE
> +    );
> +  ASSERT_RETURN_ERROR (DecryptStatus);
> +
> +  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
> +
> +  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  DEBUG ((DEBUG_INFO,
> +    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
> +    (UINT64)GhcbPageCount, GhcbBase));
> +
> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);

As I said in the comments to PcdGhcbBase/Size, can all PCD consumers read the GHCB MSR instead?

Does the GHCB buffer contains size information? If no, how does CPU know the GHCB buffer size?
I am asking this because I want to see a way to remove the PcdGhcbSize.

Thanks,
Ray

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

* Re: [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  2019-11-20 20:06 ` [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
@ 2019-12-12  6:57   ` Ni, Ray
  2019-12-12 21:19     ` [edk2-devel] " Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  6:57 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A,
	Bi, Dandan

Is the 16bit code segment descriptor needed in early DXE before CpuDxe (DXE MP)?

> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
> Subject: [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
> 
> 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 284b34818ca7..c9cf2e36214f 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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled
  2019-11-20 20:06 ` [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
@ 2019-12-12  7:01   ` Ni, Ray
  2019-12-12 21:21     ` Lendacky, Thomas
  0 siblings, 1 reply; 82+ messages in thread
From: Ni, Ray @ 2019-12-12  7:01 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh

OK I see now the Enable PCD is defined in MdeModulePkg, produced in platform and consumed in MpInitLib.

Is there a way to easily detect whether SEV-ES is enabled? (without triggering CPUID as what SEC does)

If no, can you define the PCD in UefiCpuPkg?


> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>
> Subject: [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled
> 
> 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
> enabled. This new field is set during MP library initialization with the
> PCD value PcdSevEsIsEnabled. This flag can then be used to determine if
> SEV-ES is enabled.
> 
> 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 cd912ab0c5ee..f84dbb09ae49 100644
> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
> @@ -69,4 +69,5 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> index 1538185ef99a..9c1215ec75d0 100644
> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> @@ -60,6 +60,7 @@ [Pcd]
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
> 
>  [Guids]
>    gEdkiiS3SmmInitDoneGuid
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index 8fa07b12c5e1..c10fe894cf9b 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -259,6 +259,8 @@ struct _CPU_MP_DATA {
>    // driver.
>    //
>    BOOLEAN                        WakeUpByInitSipiSipi;
> +
> +  BOOLEAN                        SevEsIsEnabled;
>  };
> 
>  extern EFI_GUID mCpuInitMpLibHobGuid;
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index 49be5d5385d9..aa25bf9b3671 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -1708,6 +1708,7 @@ MpInitLibInitialize (
>      CpuMpData->MicrocodePatchAddress    = OldCpuMpData->MicrocodePatchAddress;
>    }
>    InitializeSpinLock(&CpuMpData->MpLock);
> +  CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
> 
>    //
>    // Make sure no memory usage outside of the allocated buffer.
> --
> 2.17.1


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

* Re: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-12-12  6:53   ` Ni, Ray
@ 2019-12-12 20:27     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 20:27 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, Brijesh Singh



On 12/12/19 12:53 AM, Ni, Ray wrote:
>>
>>  ;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
>> +    cmp     qword [rbp + 8], 29
> 
> Can you define a macro instead of using 29?

Yes, I can do that.

Thanks,
Tom

> 
>> +    je      VcDebugRegs          ; For SEV-ES (#VC) Debug registers ignored
> 
> 

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

* Re: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
  2019-12-12  6:53   ` Ni, Ray
@ 2019-12-12 20:39     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 20:39 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, Brijesh Singh

On 12/12/19 12:53 AM, Ni, Ray wrote:
> Tom,
> Why all DR registers are not pushed to stack in VC handler?
> I thought only DR7 pushing is skipped.

It was probably just to be on the safe side in case the hypervisor didn't
remove the intercept for them. And since none of the other debug registers
are used by the #VC handler and their values aren't restored on exit, I
just decided not to push them. But I can push them if you think it best.

Thanks,
Tom

> 
> Thanks,
> Ray
> 
>> -----Original Message-----
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>
>> Subject: [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write NAE events
>>
>> 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%7C6858e5b903674581483b08d77ed0123b%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117304434355086&amp;sdata=jRdTglBwajIycWATDilfbyC%2BrvPOTFCUl0MqhhuE5nA%3D&amp;reserved=0
>>
>> 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 1d7c34e7e442..22393f72d795 100644
>> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
>> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c
>> @@ -13,6 +13,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,
>> @@ -1081,6 +1087,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,
>> @@ -1097,6 +1157,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 19198f273137..a0549f7ae6bd 100644
>> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
>> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
>> @@ -225,6 +225,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
>> @@ -237,7 +240,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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
  2019-12-12  6:53   ` Ni, Ray
@ 2019-12-12 20:48     ` Lendacky, Thomas
  2019-12-13  1:21       ` Ni, Ray
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 20:48 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, Brijesh Singh, Wang, Jian J, Wu, Hao A

On 12/12/19 12:53 AM, Ni, Ray wrote:
> Do you really need to define the PCD in MdePkg?
> General guide lines are:
> 1. Avoid UefiCpuPkg depend on MdeModulePkg.
> 2. Do not define platform level PCD in core pkgs (MdePkg, MdeModulePkg, UefiCpuPkg, etc)
> 
> 
> PcdSevEsIsEnabled seems to be used in OVMF pkg only so how about define that in OvmfPkg.dec?

PcdSevEsIsEnabled is used by the UefiCpuPkg in the MP library. I can move
it from MdeModulePkg and into UefiCpuPkg if that's preferred?

Thanks,
Tom

> 
> Thanks,
> Ray
> 
>> -----Original Message-----
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>> Sent: Thursday, November 21, 2019 4:06 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
>> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>
>> Subject: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
>>
>> 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%7Cf366369db18d403f73f808d77ed01213%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117304445443903&amp;sdata=MlMdAafNmnwELGgm0I2qngT41Zr%2FuhjcUgYnOxfaMbY%3D&amp;reserved=0
>>
>> Two new fixed PCSs are needed to support SEV-ES under OVMF:
>>   - PcdSecGhcbBase  UINT64 value that is the base address of the GHCB
>>                     used during the SEC phase.
>>   - PcdSecGhcbSize  UINT64 value that is the size, in bytes, of the GHCB
>>                     area used during the SEC phase.
>>
>> Three new dynamic PCDs are needed to support SEV-ES under OVMF:
>>   - PcdSevEsIsEnabled: BOOLEAN value used to indicate if SEV-ES is enabled
>>   - 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 | 23 +++++++++++++++++++++++
>>  1 file changed, 23 insertions(+)
>>
>> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
>> index 41b9e70a1ac8..c3bdfcc80971 100644
>> --- a/MdeModulePkg/MdeModulePkg.dec
>> +++ b/MdeModulePkg/MdeModulePkg.dec
>> @@ -1037,6 +1037,14 @@ [PcdsFixedAtBuild]
>>    # @Prompt Enable UEFI Stack Guard.
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055
>>
>> +  ## The base address of the SEC GHCB page.
>> +  # @Prompt SEC GHCB Base Address
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|0|UINT32|0x30001056
>> +
>> +  ## The total size of the SEC GHCB page.
>> +  # @Prompt SEC GHCB Size
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize|0|UINT32|0x30001057
>> +
>>  [PcdsFixedAtBuild, PcdsPatchableInModule]
>>    ## Dynamic type PCD can be registered callback function for Pcd setting action.
>>    #  PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
>> @@ -2053,6 +2061,21 @@ [PcdsDynamic, PcdsDynamicEx]
>>    # @Prompt If there is any test key used by the platform.
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed|FALSE|BOOLEAN|0x00030003
>>
>> +  ## This dynamic PCD indicates whether SEV-ES is enabled
>> +  #   TRUE  - SEV-ES is enabled
>> +  #   FALSE - SEV-ES is not enabled
>> +  # @Prompt SEV-ES Status
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x00030007
>> +
>> +  ## This dynamic PCD holds the base address of the GHCB pool allocation.
>> +  # @Prompt GHCB Pool Base Address
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00030008
>> +
>> +  ## This dynamic PCD holds the total size of the GHCB pool allocation.
>> +  #  The amount of memory allocated for GHCBs is dependent on the number of APs.
>> +  # @Prompt GHCB Pool Size
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030009
>> +
>>  [PcdsDynamicEx]
>>    ## This dynamic PCD enables the default variable setting.
>>    #  Its value is the default store ID value. The default value is zero as Standard default.
>> --
>> 2.17.1
> 

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

* Re: [edk2-devel] [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
  2019-12-12  6:53   ` [edk2-devel] " Ni, Ray
@ 2019-12-12 20:58     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 20:58 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, Brijesh Singh, Wang, Jian J, Wu, Hao A,
	Bi, Dandan

On 12/12/19 12:53 AM, Ni, Ray wrote:
> Tom,
> When are GHCP pages are allocated? Can DxeIpl gets the address by reading the GHCB MSR?
> 
> Can the GHCB PCD be eliminated by updating all GHCB address consumer to read the GHCB MSR?

The non-SEC GHCB pages are allocated in PEI. DxeIpl should be able to get
the GHCB address by reading the GHCB MSR, but it wouldn't know the size of
the area that needs to be marked un-encrypted, which is what PcdGhcbSize
is used for.

An alternative is to have some sort of callback service that can modify
the newly built pagetables before they are made active.

Thanks,
Tom

> 
> Thanks,
> Ray
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lendacky, Thomas
>> Sent: Thursday, November 21, 2019 4:06 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
>> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
>> Subject: [edk2-devel] [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables
>>
>> 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%7C46d86f04a1a048b7b77508d77ed015d7%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117304489595635&amp;sdata=Lcco5pprtKfjuAwDFxDJy4b%2B0bcWabyG2F0Z5wmGGAs%3D&amp;reserved=0
>>
>> 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 6e8ca824d469..284b34818ca7 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
>> @@ -282,7 +282,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 f465eb1d8ac4..156a477d8467 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;
>>
>>    //
>>    // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
>> @@ -81,12 +83,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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase
  2019-12-12  6:54   ` Ni, Ray
@ 2019-12-12 21:03     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 21:03 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, Brijesh Singh

On 12/12/19 12:54 AM, Ni, Ray wrote:
>> +  // Allocate GHCB and per-CPU variable pages.
>> +  //
>> +  GhcbPageCount = mMaxCpuCount * 2;
>> +  GhcbBase = AllocatePages (GhcbPageCount);
>> +  ASSERT (GhcbBase != NULL);
>> +
>> +  GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
>> +
>> +  DecryptStatus = MemEncryptSevClearPageEncMask (
>> +    0,
>> +    GhcbBasePa,
>> +    GhcbPageCount,
>> +    TRUE
>> +    );
>> +  ASSERT_RETURN_ERROR (DecryptStatus);
>> +
>> +  ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
>> +
>> +  PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +  PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
>> +  ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> +  DEBUG ((DEBUG_INFO,
>> +    "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
>> +    (UINT64)GhcbPageCount, GhcbBase));
>> +
>> +  AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
> 
> As I said in the comments to PcdGhcbBase/Size, can all PCD consumers read the GHCB MSR instead?
> 
> Does the GHCB buffer contains size information? If no, how does CPU know the GHCB buffer size?
> I am asking this because I want to see a way to remove the PcdGhcbSize.

The GHCB is one page in size and is a defined structure. The PcdGhcbSize
represents the total size of the allocation, which is one GHCB page per
CPU and one page per CPU to hold per-CPU data (currently the DR7 value).

Thanks,
Tom

> 
> Thanks,
> Ray
> 

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

* Re: [edk2-devel] [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  2019-12-12  6:57   ` Ni, Ray
@ 2019-12-12 21:19     ` Lendacky, Thomas
  2019-12-13  1:20       ` Ni, Ray
  0 siblings, 1 reply; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 21:19 UTC (permalink / raw)
  To: devel, ray.ni
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A,
	Bi, Dandan

On 12/12/19 12:57 AM, Ni, Ray via Groups.Io wrote:
> Is the 16bit code segment descriptor needed in early DXE before CpuDxe (DXE MP)?

I don't believe it is. I did this to keep all of the CS descriptors
consistent since the ones here seemed to line up with the ones in
UefiCpuPkg/CpuDxe/CpuGdt.c.  I can remove this change if that isn't
a requirement.

Thanks,
Tom

> 
>> -----Original Message-----
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
>> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
>> Subject: [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
>>
>> 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%7C8ec88e8912cd4b99eb0f08d77ed09b2c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117306738013792&amp;sdata=PwSQc53mtPMUTALaRhQrcQzGI3ooPUMhcktYLi1ezfk%3D&amp;reserved=0
>>
>> 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 284b34818ca7..c9cf2e36214f 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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled
  2019-12-12  7:01   ` Ni, Ray
@ 2019-12-12 21:21     ` Lendacky, Thomas
  0 siblings, 0 replies; 82+ messages in thread
From: Lendacky, Thomas @ 2019-12-12 21:21 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, Brijesh Singh

On 12/12/19 1:01 AM, Ni, Ray wrote:
> OK I see now the Enable PCD is defined in MdeModulePkg, produced in platform and consumed in MpInitLib.
> 
> Is there a way to easily detect whether SEV-ES is enabled? (without triggering CPUID as what SEC does)

No, I would need to read an MSR and I really should be certain the MSR is
valid before trying to do that - and that requires checking CPUID.

> 
> If no, can you define the PCD in UefiCpuPkg?

I should be able to do that. Let me give it a try.

Thanks,
Tom

> 
> 
>> -----Original Message-----
>> From: Tom Lendacky <thomas.lendacky@amd.com>
>> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>
>> Subject: [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled
>>
>> 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%7C8541911e903d4d05cb4708d77ed10ec4%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637117308681418556&amp;sdata=Vt3vjZ7afbFWT59nR%2F332FMHm%2F%2FBkq62%2BN6oKEfiraE%3D&amp;reserved=0
>>
>> 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
>> enabled. This new field is set during MP library initialization with the
>> PCD value PcdSevEsIsEnabled. This flag can then be used to determine if
>> SEV-ES is enabled.
>>
>> 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 cd912ab0c5ee..f84dbb09ae49 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
>> @@ -69,4 +69,5 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
>>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                  ## CONSUMES
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
>>
>> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> index 1538185ef99a..9c1215ec75d0 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
>> @@ -60,6 +60,7 @@ [Pcd]
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES
>>    gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled                 ## CONSUMES
>>
>>  [Guids]
>>    gEdkiiS3SmmInitDoneGuid
>> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> index 8fa07b12c5e1..c10fe894cf9b 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
>> @@ -259,6 +259,8 @@ struct _CPU_MP_DATA {
>>    // driver.
>>    //
>>    BOOLEAN                        WakeUpByInitSipiSipi;
>> +
>> +  BOOLEAN                        SevEsIsEnabled;
>>  };
>>
>>  extern EFI_GUID mCpuInitMpLibHobGuid;
>> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
>> index 49be5d5385d9..aa25bf9b3671 100644
>> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
>> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
>> @@ -1708,6 +1708,7 @@ MpInitLibInitialize (
>>      CpuMpData->MicrocodePatchAddress    = OldCpuMpData->MicrocodePatchAddress;
>>    }
>>    InitializeSpinLock(&CpuMpData->MpLock);
>> +  CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
>>
>>    //
>>    // Make sure no memory usage outside of the allocated buffer.
>> --
>> 2.17.1
> 

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

* Re: [edk2-devel] [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
  2019-12-12 21:19     ` [edk2-devel] " Lendacky, Thomas
@ 2019-12-13  1:20       ` Ni, Ray
  0 siblings, 0 replies; 82+ messages in thread
From: Ni, Ray @ 2019-12-13  1:20 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A,
	Bi, Dandan

It's not a requirement.

> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Friday, December 13, 2019 5:19 AM
> To: devel@edk2.groups.io; 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>; Dong,
> Eric <eric.dong@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J <jian.j.wang@intel.com>; Wu, Hao A
> <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
> Subject: Re: [edk2-devel] [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
> 
> On 12/12/19 12:57 AM, Ni, Ray via Groups.Io wrote:
> > Is the 16bit code segment descriptor needed in early DXE before CpuDxe (DXE MP)?
> 
> I don't believe it is. I did this to keep all of the CS descriptors
> consistent since the ones here seemed to line up with the ones in
> UefiCpuPkg/CpuDxe/CpuGdt.c.  I can remove this change if that isn't
> a requirement.
> 
> Thanks,
> Tom
> 
> >
> >> -----Original Message-----
> >> From: Tom Lendacky <thomas.lendacky@amd.com>
> >> Sent: Thursday, November 21, 2019 4:07 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
> >> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Bi, Dandan <dandan.bi@intel.com>
> >> Subject: [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor
> >>
> >> BZ:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D21
> 98&amp;data=02%7C01%7Cthomas.lendacky%40amd.com%7C8ec88e8912cd4b99eb0f08d77ed09b2c%7C3dd8961fe4884e60
> 8e11a82d994e183d%7C0%7C0%7C637117306738013792&amp;sdata=PwSQc53mtPMUTALaRhQrcQzGI3ooPUMhcktYLi1ezfk
> %3D&amp;reserved=0
> >>
> >> 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 284b34818ca7..c9cf2e36214f 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	[flat|nested] 82+ messages in thread

* Re: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
  2019-12-12 20:48     ` Lendacky, Thomas
@ 2019-12-13  1:21       ` Ni, Ray
  0 siblings, 0 replies; 82+ messages in thread
From: Ni, Ray @ 2019-12-13  1:21 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Justen, Jordan L, Laszlo Ersek, Ard Biesheuvel, Kinney, Michael D,
	Gao, Liming, Dong, Eric, Brijesh Singh, Wang, Jian J, Wu, Hao A

yes.

> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Friday, December 13, 2019 4:48 AM
> To: Ni, Ray <ray.ni@intel.com>; 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J <jian.j.wang@intel.com>; Wu, Hao A
> <hao.a.wu@intel.com>
> Subject: Re: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
> 
> On 12/12/19 12:53 AM, Ni, Ray wrote:
> > Do you really need to define the PCD in MdePkg?
> > General guide lines are:
> > 1. Avoid UefiCpuPkg depend on MdeModulePkg.
> > 2. Do not define platform level PCD in core pkgs (MdePkg, MdeModulePkg, UefiCpuPkg, etc)
> >
> >
> > PcdSevEsIsEnabled seems to be used in OVMF pkg only so how about define that in OvmfPkg.dec?
> 
> PcdSevEsIsEnabled is used by the UefiCpuPkg in the MP library. I can move
> it from MdeModulePkg and into UefiCpuPkg if that's preferred?
> 
> Thanks,
> Tom
> 
> >
> > Thanks,
> > Ray
> >
> >> -----Original Message-----
> >> From: Tom Lendacky <thomas.lendacky@amd.com>
> >> Sent: Thursday, November 21, 2019 4:06 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>; Brijesh Singh <brijesh.singh@amd.com>; Wang, Jian J
> >> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>
> >> Subject: [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES
> >>
> >> BZ:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D21
> 98&amp;data=02%7C01%7Cthomas.lendacky%40amd.com%7Cf366369db18d403f73f808d77ed01213%7C3dd8961fe4884e60
> 8e11a82d994e183d%7C0%7C0%7C637117304445443903&amp;sdata=MlMdAafNmnwELGgm0I2qngT41Zr%2FuhjcUgYnOxfa
> MbY%3D&amp;reserved=0
> >>
> >> Two new fixed PCSs are needed to support SEV-ES under OVMF:
> >>   - PcdSecGhcbBase  UINT64 value that is the base address of the GHCB
> >>                     used during the SEC phase.
> >>   - PcdSecGhcbSize  UINT64 value that is the size, in bytes, of the GHCB
> >>                     area used during the SEC phase.
> >>
> >> Three new dynamic PCDs are needed to support SEV-ES under OVMF:
> >>   - PcdSevEsIsEnabled: BOOLEAN value used to indicate if SEV-ES is enabled
> >>   - 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 | 23 +++++++++++++++++++++++
> >>  1 file changed, 23 insertions(+)
> >>
> >> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
> >> index 41b9e70a1ac8..c3bdfcc80971 100644
> >> --- a/MdeModulePkg/MdeModulePkg.dec
> >> +++ b/MdeModulePkg/MdeModulePkg.dec
> >> @@ -1037,6 +1037,14 @@ [PcdsFixedAtBuild]
> >>    # @Prompt Enable UEFI Stack Guard.
> >>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055
> >>
> >> +  ## The base address of the SEC GHCB page.
> >> +  # @Prompt SEC GHCB Base Address
> >> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbBase|0|UINT32|0x30001056
> >> +
> >> +  ## The total size of the SEC GHCB page.
> >> +  # @Prompt SEC GHCB Size
> >> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSecGhcbSize|0|UINT32|0x30001057
> >> +
> >>  [PcdsFixedAtBuild, PcdsPatchableInModule]
> >>    ## Dynamic type PCD can be registered callback function for Pcd setting action.
> >>    #  PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
> >> @@ -2053,6 +2061,21 @@ [PcdsDynamic, PcdsDynamicEx]
> >>    # @Prompt If there is any test key used by the platform.
> >>    gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed|FALSE|BOOLEAN|0x00030003
> >>
> >> +  ## This dynamic PCD indicates whether SEV-ES is enabled
> >> +  #   TRUE  - SEV-ES is enabled
> >> +  #   FALSE - SEV-ES is not enabled
> >> +  # @Prompt SEV-ES Status
> >> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x00030007
> >> +
> >> +  ## This dynamic PCD holds the base address of the GHCB pool allocation.
> >> +  # @Prompt GHCB Pool Base Address
> >> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00030008
> >> +
> >> +  ## This dynamic PCD holds the total size of the GHCB pool allocation.
> >> +  #  The amount of memory allocated for GHCBs is dependent on the number of APs.
> >> +  # @Prompt GHCB Pool Size
> >> +  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030009
> >> +
> >>  [PcdsDynamicEx]
> >>    ## This dynamic PCD enables the default variable setting.
> >>    #  Its value is the default store ID value. The default value is zero as Standard default.
> >> --
> >> 2.17.1
> >

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

end of thread, other threads:[~2019-12-13  1:21 UTC | newest]

Thread overview: 82+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-11-20 20:06 [RFC PATCH v3 00/43] SEV-ES guest support Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 01/43] MdePkg: Create PCDs to be used in support of SEV-ES Lendacky, Thomas
2019-12-12  6:53   ` Ni, Ray
2019-12-12 20:48     ` Lendacky, Thomas
2019-12-13  1:21       ` Ni, Ray
2019-11-20 20:06 ` [RFC PATCH v3 02/43] MdePkg: Add the MSR definition for the GHCB register Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 03/43] MdePkg: Add a structure definition for the GHCB Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 04/43] MdeModulePkg/DxeIplPeim: Support GHCB pages when creating page tables Lendacky, Thomas
2019-12-12  6:53   ` [edk2-devel] " Ni, Ray
2019-12-12 20:58     ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 05/43] MdePkg/BaseLib: Add support for the XGETBV instruction Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 06/43] MdePkg/BaseLib: Add support for the VMGEXIT instruction Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 07/43] UefiCpuPkg: Implement library support for VMGEXIT Lendacky, Thomas
2019-11-21 11:15   ` [edk2-devel] " Laszlo Ersek
2019-11-21 16:48     ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 08/43] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VC exception Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 09/43] UefiCpuPkg/CpuExceptionHandler: Add support for IOIO_PROT NAE events Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 10/43] UefiCpuPkg/CpuExceptionHandler: Support string IO " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 11/43] UefiCpuPkg/CpuExceptionHandler: Add support for CPUID " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 12/43] UefiCpuPkg/CpuExceptionHandler: Add support for MSR_PROT " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 13/43] UefiCpuPkg/CpuExceptionHandler: Add support for NPF NAE events (MMIO) Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 14/43] UefiCpuPkg/CpuExceptionHandler: Add support for WBINVD NAE events Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 15/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSC " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 16/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDPMC " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 17/43] UefiCpuPkg/CpuExceptionHandler: Add support for INVD " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 18/43] UefiCpuPkg/CpuExceptionHandler: Add support for VMMCALL " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 19/43] UefiCpuPkg/CpuExceptionHandler: Add support for RDTSCP " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 20/43] UefiCpuPkg/CpuExceptionHandler: Add support for MONITOR/MONITORX " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 21/43] UefiCpuPkg/CpuExceptionHandler: Add support for MWAIT/MWAITX " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 22/43] UefiCpuPkg/CpuExceptionHandler: Add support for DR7 Read/Write " Lendacky, Thomas
2019-12-12  6:53   ` Ni, Ray
2019-12-12 20:27     ` Lendacky, Thomas
2019-12-12  6:53   ` Ni, Ray
2019-12-12 20:39     ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 23/43] OvmfPkg/MemEncryptSevLib: Add an SEV-ES guest indicator function Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 24/43] OvmfPkg: Add support to perform SEV-ES initialization Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 25/43] OvmfPkg/ResetVector: Add support for a 32-bit SEV check Lendacky, Thomas
2019-11-21 11:02   ` [edk2-devel] " Laszlo Ersek
2019-11-20 20:06 ` [RFC PATCH v3 26/43] OvmfPkg: Create a GHCB page for use during Sec phase Lendacky, Thomas
2019-11-21 11:29   ` [edk2-devel] " Laszlo Ersek
2019-11-20 20:06 ` [RFC PATCH v3 27/43] OvmfPkg/PlatformPei: Reserve GHCB-related areas if S3 is supported Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 28/43] OvmfPkg: Create GHCB pages for use during Pei and Dxe phase Lendacky, Thomas
2019-12-12  6:54   ` Ni, Ray
2019-12-12 21:03     ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 29/43] OvmfPkg/PlatformPei: Move early GDT into ram when SEV-ES is enabled Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 30/43] OvmfPkg/Sec: Add #VC exception handling for Sec phase Lendacky, Thomas
2019-11-21 12:06   ` [edk2-devel] " Laszlo Ersek
2019-11-21 20:46     ` Lendacky, Thomas
2019-11-22 12:52       ` Laszlo Ersek
2019-11-22 16:30         ` Lendacky, Thomas
2019-11-22 21:10           ` Laszlo Ersek
2019-11-22 22:48             ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 31/43] OvmfPkg/Sec: Enable cache early to speed up booting Lendacky, Thomas
2019-11-21 12:08   ` [edk2-devel] " Laszlo Ersek
2019-11-20 20:06 ` [RFC PATCH v3 32/43] OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Bypass flash detection with SEV-ES is enabled Lendacky, Thomas
2019-11-21 12:31   ` [edk2-devel] " Laszlo Ersek
2019-11-21 21:11     ` Lendacky, Thomas
2019-11-22 12:20       ` Laszlo Ersek
2019-11-20 20:06 ` [RFC PATCH v3 33/43] MdeModulePkg: Reserve a 16-bit protected mode code segment descriptor Lendacky, Thomas
2019-12-12  6:57   ` Ni, Ray
2019-12-12 21:19     ` [edk2-devel] " Lendacky, Thomas
2019-12-13  1:20       ` Ni, Ray
2019-11-20 20:06 ` [RFC PATCH v3 34/43] UefiCpuPkg: Add " Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 35/43] UefiCpuPkg/MpInitLib: Add a CPU MP data flag to indicate if SEV-ES is enabled Lendacky, Thomas
2019-12-12  7:01   ` Ni, Ray
2019-12-12 21:21     ` Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 36/43] UefiCpuPkg: Allow AP booting under SEV-ES Lendacky, Thomas
2019-11-20 20:06 ` [RFC PATCH v3 37/43] OvmfPkg: Reserve a page in memory for the SEV-ES AP reset vector Lendacky, Thomas
2019-11-21 19:27   ` [edk2-devel] " Laszlo Ersek
2019-11-21 22:49     ` Lendacky, Thomas
2019-11-22 16:06       ` Laszlo Ersek
2019-11-22 16:40         ` Lendacky, Thomas
2019-11-20 20:07 ` [RFC PATCH v3 38/43] OvmfPkg: Move the GHCB allocations into reserved memory Lendacky, Thomas
2019-11-20 20:07 ` [RFC PATCH v3 39/43] MdePkg: Add a finalization function to the CPU protocol Lendacky, Thomas
2019-11-20 21:32 ` [RFC PATCH v3 40/43] UefiCpuPkg/MpInitLib: Add MP finalization interface to MpInitLib Lendacky, Thomas
2019-11-20 21:32 ` [RFC PATCH v3 41/43] UefiCpuPkg/MpInitLib: Prepare SEV-ES guest APs for OS use Lendacky, Thomas
2019-11-20 21:32 ` [RFC PATCH v3 42/43] UefiCpuPkg/CpuDxe: Provide an DXE MP finalization routine to support SEV-ES Lendacky, Thomas
2019-11-20 21:32 ` [RFC PATCH v3 43/43] MdeModulePkg/DxeCore: Perform the CPU protocol finalization support Lendacky, Thomas
2019-11-21  1:53 ` [edk2-devel] [RFC PATCH v3 00/43] SEV-ES guest support Nate DeSimone
2019-11-21 15:50   ` Lendacky, Thomas
2019-11-21  9:45 ` Laszlo Ersek
2019-11-21  9:48   ` Laszlo Ersek

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