Re: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support

Lendacky, Thomas
 

Hi Ray,

On 8/19/19 4:47 PM, Ni, Ray wrote:
Tom,
1. It's not a common practice to have static inline functions defined in header file. Who is going to call them?
The functions are called from two locations, so that's why I made them
static inline. I'm new to EDK2 programming, so I'm sure there will be a
number of things I do that will need to be changed.

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

2. Recently I made a change to move the AMD registers definitions to MdePkg/Include/Register/Amd from UefiCpuPkg. Do you think that's a good idea and can you please put your new register definitions to MdePkg as well?
Ok, let me pull the latest tree and rebase. This patchset is currently
based on a July 17th patch:

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

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

3. What happens if the "rep; vmmcall" is executed in Intel processor?
Good question, I'm not sure. Is there a way that EDK2 has to prevent
execution of unsupported instructions? Currently, this instruction will
only be invoked when it is known that SEV-ES is active.

Thanks,
Tom


Thanks,
Ray

-----Original Message-----
From: Lendacky, Thomas <Thomas.Lendacky@...>
Sent: Monday, August 19, 2019 2:36 PM
To: devel@edk2.groups.io
Cc: Justen, Jordan L <jordan.l.justen@...>; Laszlo Ersek <lersek@...>; Ard Biesheuvel
<ard.biesheuvel@...>; Kinney, Michael D <michael.d.kinney@...>; Gao, Liming <liming.gao@...>; Dong,
Eric <eric.dong@...>; Ni, Ray <ray.ni@...>; Singh, Brijesh <brijesh.singh@...>
Subject: [RFC PATCH 08/28] MdePkg/BaseLib: Implement the VMGEXIT support

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

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

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

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

diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 3586beb0ab5c..a41401340f95 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -286,6 +286,7 @@ [Sources.X64]
X64/ReadCr2.nasm| MSFT
X64/ReadCr0.nasm| MSFT
X64/ReadEflags.nasm| MSFT
+ X64/VmgExit.nasm | MSFT


X64/Non-existing.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 2a75bc023f56..80bd5cf57a72 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7880,6 +7880,20 @@ AsmLfence (
VOID
);

+/**
+ Executes a VMGEXIT instruction (VMMCALL with a REP prefix)
+
+ Executes a VMGEXIT instruction. This function is only available on IA-32 and
+ x64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+ VOID
+ );
+
+
/**
Patch the immediate operand of an IA32 or X64 instruction such that the byte,
word, dword or qword operand is encoded at the end of the instruction's
diff --git a/UefiCpuPkg/Include/Register/Amd/Ghcb.h b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
new file mode 100644
index 000000000000..e9fd116fac25
--- /dev/null
+++ b/UefiCpuPkg/Include/Register/Amd/Ghcb.h
@@ -0,0 +1,197 @@
+
+#ifndef __GHCB_H__
+#define __GHCB_H__
+
+#include <Protocol/DebugSupport.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#define UD_EXCEPTION 6
+#define GP_EXCEPTION 13
+
+#define GHCB_VERSION_MIN 1
+#define GHCB_VERSION_MAX 1
+
+#define GHCB_STANDARD_USAGE 0
+
+typedef enum {
+ SvmExitDr7Read = 0x27,
+ SvmExitDr7Write = 0x37,
+ SvmExitRdtsc = 0x6E,
+ SvmExitRdpmc,
+ SvmExitCpuid = 0x72,
+ SvmExitInvd = 0x76,
+ SvmExitIoioProt = 0x7B,
+ SvmExitMsr,
+ SvmExitVmmCall = 0x81,
+ SvmExitRdtscp = 0x87,
+ SvmExitWbinvd = 0x89,
+ SvmExitMonitor,
+ SvmExitMwait,
+ SvmExitNpf = 0x400,
+
+ // VMG special exits
+ SvmExitMmioRead = 0x80000001,
+ SvmExitMmioWrite,
+ SvmExitNmiComplete,
+ SvmExitApResetHold,
+
+ SvmExitUnsupported = 0x8000FFFF,
+} SVM_EXITCODE;
+
+typedef enum {
+ GhcbCpl = 25,
+ GhcbRflags = 46,
+ GhcbRip,
+ GhcbRsp = 59,
+ GhcbRax = 63,
+ GhcbRcx = 97,
+ GhcbRdx,
+ GhcbRbx,
+ GhcbRbp = 101,
+ GhcbRsi,
+ GhcbRdi,
+ GhcbR8,
+ GhcbR9,
+ GhcbR10,
+ GhcbR11,
+ GhcbR12,
+ GhcbR13,
+ GhcbR14,
+ GhcbR15,
+ GhcbXCr0 = 125,
+} GHCB_REGISTER;
+
+typedef struct {
+ UINT8 Reserved1[203];
+ UINT8 Cpl;
+ UINT8 Reserved2[148];
+ UINT64 Dr7;
+ UINT8 Reserved3[144];
+ UINT64 Rax;
+ UINT8 Reserved4[264];
+ UINT64 Rcx;
+ UINT64 Rdx;
+ UINT64 Rbx;
+ UINT8 Reserved5[112];
+ UINT64 SwExitCode;
+ UINT64 SwExitInfo1;
+ UINT64 SwExitInfo2;
+ UINT64 SwScratch;
+ UINT8 Reserved6[56];
+ UINT64 XCr0;
+ UINT8 ValidBitmap[16];
+ UINT64 X87StateGpa;
+ UINT8 Reserved7[1016];
+} __attribute__ ((__packed__)) GHCB_SAVE_AREA;
+
+typedef struct {
+ GHCB_SAVE_AREA SaveArea;
+ UINT8 SharedBuffer[2032];
+ UINT8 Reserved1[10];
+ UINT16 ProtocolVersion;
+ UINT32 GhcbUsage;
+} __attribute__ ((__packed__)) __attribute__ ((aligned(SIZE_4KB))) GHCB;
+
+typedef union {
+ struct {
+ UINT32 Lower32Bits;
+ UINT32 Upper32Bits;
+ } Elements;
+
+ UINT64 Uint64;
+} GHCB_EXIT_INFO;
+
+static inline
+BOOLEAN
+GhcbIsRegValid(
+ GHCB *Ghcb,
+ GHCB_REGISTER Reg
+ )
+{
+ UINT32 RegIndex = Reg / 8;
+ UINT32 RegBit = Reg & 0x07;
+
+ return (Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit));
+}
+
+static inline
+VOID
+GhcbSetRegValid(
+ GHCB *Ghcb,
+ GHCB_REGISTER Reg
+ )
+{
+ UINT32 RegIndex = Reg / 8;
+ UINT32 RegBit = Reg & 0x07;
+
+ Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
+}
+
+static inline
+VOID
+VmgException(
+ UINTN Exception
+ )
+{
+ switch (Exception) {
+ case UD_EXCEPTION:
+ case GP_EXCEPTION:
+ break;
+ default:
+ ASSERT (0);
+ }
+}
+
+static inline
+UINTN
+VmgExit(
+ GHCB *Ghcb,
+ UINT64 ExitCode,
+ UINT64 ExitInfo1,
+ UINT64 ExitInfo2
+ )
+{
+ GHCB_EXIT_INFO ExitInfo;
+ UINTN Reason, Action;
+
+ Ghcb->SaveArea.SwExitCode = ExitCode;
+ Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
+ Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
+ AsmVmgExit ();
+
+ if (!Ghcb->SaveArea.SwExitInfo1) {
+ return 0;
+ }
+
+ ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
+ Reason = ExitInfo.Elements.Upper32Bits;
+ Action = ExitInfo.Elements.Lower32Bits;
+ switch (Action) {
+ case 1:
+ VmgException (Reason);
+ break;
+ default:
+ ASSERT (0);
+ }
+
+ return Reason;
+}
+
+static inline
+VOID
+VmgInit(
+ GHCB *Ghcb
+ )
+{
+ SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
+}
+
+static inline
+VOID
+VmgDone(
+ GHCB *Ghcb
+ )
+{
+}
+#endif
diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c
index 154ce1f57e92..17539caa0798 100644
--- a/MdePkg/Library/BaseLib/X64/GccInline.c
+++ b/MdePkg/Library/BaseLib/X64/GccInline.c
@@ -1798,3 +1798,20 @@ AsmFlushCacheLine (
}


+/**
+ Executes a VMGEXIT instruction.
+
+ Executes a VMGEXIT instruction. This function is only available on IA-32 and
+ X64.
+
+**/
+VOID
+EFIAPI
+AsmVmgExit (
+ VOID
+ )
+{
+ __asm__ __volatile__ ("rep; vmmcall":::"memory");
+}
+
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExit.nasm b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
new file mode 100644
index 000000000000..b673bb94b60d
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/VmgExit.nasm
@@ -0,0 +1,38 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; VmgExit.Asm
+;
+; Abstract:
+;
+; AsmVmgExit function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; AsmVmgExit (
+; VOID
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExit)
+ASM_PFX(AsmVmgExit):
+ rep; vmmcall
+ ret
+
--
2.17.1

Join devel@edk2.groups.io to automatically receive all group messages.