public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Min Xu" <min.m.xu@intel.com>
To: devel@edk2.groups.io
Cc: Min Xu <min.m.xu@intel.com>,
	Ard Biesheuvel <ardb+tianocore@kernel.org>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Jordan Justen <jordan.l.justen@intel.com>,
	Brijesh Singh <brijesh.singh@amd.com>,
	Erdem Aktas <erdemaktas@google.com>,
	James Bottomley <jejb@linux.ibm.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH V8 05/47] OvmfPkg: Extend VmgExitLib to handle #VE exception
Date: Sat, 12 Mar 2022 09:53:30 +0800	[thread overview]
Message-ID: <0f7abb8e1ac372e35dafc28e2368270bdff2683b.1647047482.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1647047481.git.min.m.xu@intel.com>

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

The base VmgExitLib library provides a default limited interface to
handle #VE exception. To provide full support, the OVMF version of
VmgExitLib is extended to provide full support of #VE handler.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   3 +-
 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
 .../Library/VmgExitLib/VmTdExitVeHandler.c    | 559 ++++++++++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   2 +
 .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++++
 5 files changed, 741 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
 create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm

diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
index 78207fa0f9c9..f9bd4974f6dc 100644
--- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
@@ -25,6 +25,8 @@
   VmgExitVcHandler.c
   VmgExitVcHandler.h
   SecVmgExitVcHandler.c
+  VmTdExitVeHandler.c
+  X64/TdVmcallCpuid.nasm
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -44,4 +46,3 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
-
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
new file mode 100644
index 000000000000..7eacd0872f46
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
@@ -0,0 +1,32 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VMTD_EXIT_HANDLER_H_
+#define VMTD_EXIT_HANDLER_H_
+
+#include <Base.h>
+#include <Uefi.h>
+
+/**
+  This function enable the TD guest to request the VMM to emulate CPUID
+  operation, especially for non-architectural, CPUID leaves.
+
+  @param[in]  Eax        Main leaf of the CPUID
+  @param[in]  Ecx        Sub-leaf of the CPUID
+  @param[out] Results    Returned result of CPUID operation
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdVmCallCpuid (
+  IN UINT64  Eax,
+  IN UINT64  Ecx,
+  OUT VOID   *Results
+  );
+
+#endif
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
new file mode 100644
index 000000000000..b73e877c093b
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,559 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "VmTdExitHandler.h"
+#include <Library/VmgExitLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/InstructionParsing.h>
+
+typedef union {
+  struct {
+    UINT32    Eax;
+    UINT32    Edx;
+  } Regs;
+  UINT64    Val;
+} MSR_DATA;
+
+typedef union {
+  UINT8    Val;
+  struct {
+    UINT8    B : 1;
+    UINT8    X : 1;
+    UINT8    R : 1;
+    UINT8    W : 1;
+  } Bits;
+} REX;
+
+typedef union {
+  UINT8    Val;
+  struct {
+    UINT8    Rm  : 3;
+    UINT8    Reg : 3;
+    UINT8    Mod : 2;
+  } Bits;
+} MODRM;
+
+typedef struct {
+  UINT64    Regs[4];
+} CPUID_DATA;
+
+/**
+  Handle an CPUID event.
+
+  Use the TDVMCALL instruction to handle cpuid #ve
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+CpuIdExit (
+  IN EFI_SYSTEM_CONTEXT_X64     *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA  *Veinfo
+  )
+{
+  CPUID_DATA  CpuIdData;
+  UINT64      Status;
+
+  Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);
+
+  if (Status == 0) {
+    Regs->Rax = CpuIdData.Regs[0];
+    Regs->Rbx = CpuIdData.Regs[1];
+    Regs->Rcx = CpuIdData.Regs[2];
+    Regs->Rdx = CpuIdData.Regs[3];
+  }
+
+  return Status;
+}
+
+/**
+  Handle an IO event.
+
+  Use the TDVMCALL instruction to handle either an IO read or an IO write.
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+IoExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  BOOLEAN  Write;
+  UINTN    Size;
+  UINTN    Port;
+  UINT64   Val;
+  UINT64   RepCnt;
+  UINT64   Status;
+
+  Val   = 0;
+  Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;
+  Size  = Veinfo->ExitQualification.Io.Size + 1;
+  Port  = Veinfo->ExitQualification.Io.Port;
+
+  if (Veinfo->ExitQualification.Io.String) {
+    //
+    // If REP is set, get rep-cnt from Rcx
+    //
+    RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;
+
+    while (RepCnt) {
+      Val = 0;
+      if (Write == TRUE) {
+        CopyMem (&Val, (VOID *)Regs->Rsi, Size);
+        Regs->Rsi += Size;
+      }
+
+      Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+      if (Status != 0) {
+        break;
+      }
+
+      if (Write == FALSE) {
+        CopyMem ((VOID *)Regs->Rdi, &Val, Size);
+        Regs->Rdi += Size;
+      }
+
+      if (Veinfo->ExitQualification.Io.Rep) {
+        Regs->Rcx -= 1;
+      }
+
+      RepCnt -= 1;
+    }
+  } else {
+    if (Write == TRUE) {
+      CopyMem (&Val, (VOID *)&Regs->Rax, Size);
+    }
+
+    Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+    if ((Status == 0) && (Write == FALSE)) {
+      CopyMem ((VOID *)&Regs->Rax, &Val, Size);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Handle an READ MSR event.
+
+  Use the TDVMCALL instruction to handle msr read
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+ReadMsrExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  MSR_DATA  Data;
+  UINT64    Status;
+
+  Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);
+  if (Status == 0) {
+    Regs->Rax = Data.Regs.Eax;
+    Regs->Rdx = Data.Regs.Edx;
+  }
+
+  return Status;
+}
+
+/**
+  Handle an WRITE MSR event.
+
+  Use the TDVMCALL instruction to handle msr write
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+WriteMsrExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  UINT64    Status;
+  MSR_DATA  Data;
+
+  Data.Regs.Eax = (UINT32)Regs->Rax;
+  Data.Regs.Edx = (UINT32)Regs->Rdx;
+
+  Status =  TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);
+
+  return Status;
+}
+
+STATIC
+VOID
+EFIAPI
+TdxDecodeInstruction (
+  IN UINT8  *Rip
+  )
+{
+  UINTN  i;
+
+  DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));
+  for (i = 0; i < 15; i++) {
+    DEBUG ((DEBUG_INFO, "%02x:", Rip[i]));
+  }
+
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+#define TDX_DECODER_BUG_ON(x)               \
+  if ((x)) {                                \
+    TdxDecodeInstruction(Rip);              \
+    TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \
+  }
+
+STATIC
+UINT64 *
+EFIAPI
+GetRegFromContext (
+  IN EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN UINTN                   RegIndex
+  )
+{
+  switch (RegIndex) {
+    case 0: return &Regs->Rax;
+      break;
+    case 1: return &Regs->Rcx;
+      break;
+    case 2: return &Regs->Rdx;
+      break;
+    case 3: return &Regs->Rbx;
+      break;
+    case 4: return &Regs->Rsp;
+      break;
+    case 5: return &Regs->Rbp;
+      break;
+    case 6: return &Regs->Rsi;
+      break;
+    case 7: return &Regs->Rdi;
+      break;
+    case 8: return &Regs->R8;
+      break;
+    case 9: return &Regs->R9;
+      break;
+    case 10: return &Regs->R10;
+      break;
+    case 11: return &Regs->R11;
+      break;
+    case 12: return &Regs->R12;
+      break;
+    case 13: return &Regs->R13;
+      break;
+    case 14: return &Regs->R14;
+      break;
+    case 15: return &Regs->R15;
+      break;
+  }
+
+  return NULL;
+}
+
+/**
+  Handle an MMIO event.
+
+  Use the TDVMCALL instruction to handle either an mmio read or an mmio write.
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+INTN
+EFIAPI
+MmioExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  UINT64   Status;
+  UINT32   MmioSize;
+  UINT32   RegSize;
+  UINT8    OpCode;
+  BOOLEAN  SeenRex;
+  UINT64   *Reg;
+  UINT8    *Rip;
+  UINT64   Val;
+  UINT32   OpSize;
+  MODRM    ModRm;
+  REX      Rex;
+
+  Rip     = (UINT8 *)Regs->Rip;
+  Val     = 0;
+  Rex.Val = 0;
+  SeenRex = FALSE;
+
+  //
+  // Default to 32bit transfer
+  //
+  OpSize = 4;
+
+  do {
+    OpCode = *Rip++;
+    if (OpCode == 0x66) {
+      OpSize = 2;
+    } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) {
+      continue;
+    } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) {
+      SeenRex = TRUE;
+      Rex.Val = OpCode;
+    } else {
+      break;
+    }
+  } while (TRUE);
+
+  //
+  // We need to have at least 2 more bytes for this instruction
+  //
+  TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13);
+
+  OpCode = *Rip++;
+  //
+  // Two-byte opecode, get next byte
+  //
+  if (OpCode == 0x0F) {
+    OpCode = *Rip++;
+  }
+
+  switch (OpCode) {
+    case 0x88:
+    case 0x8A:
+    case 0xB6:
+      MmioSize = 1;
+      break;
+    case 0xB7:
+      MmioSize = 2;
+      break;
+    default:
+      MmioSize = Rex.Bits.W ? 8 : OpSize;
+      break;
+  }
+
+  /* Punt on AH/BH/CH/DH unless it shows up. */
+  ModRm.Val = *Rip++;
+  TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6);
+  Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3));
+  TDX_DECODER_BUG_ON (!Reg);
+
+  if (ModRm.Bits.Rm == 4) {
+    ++Rip; /* SIB byte */
+  }
+
+  if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) {
+    Rip += 4; /* DISP32 */
+  } else if (ModRm.Bits.Mod == 1) {
+    ++Rip;  /* DISP8 */
+  }
+
+  switch (OpCode) {
+    case 0x88:
+    case 0x89:
+      CopyMem ((void *)&Val, Reg, MmioSize);
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+      break;
+    case 0xC7:
+      CopyMem ((void *)&Val, Rip, OpSize);
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+      Rip   += OpSize;
+    default:
+      //
+      // 32-bit write registers are zero extended to the full register
+      // Hence 'MOVZX r[32/64], r/m16' is
+      // hardcoded to reg size 8, and the straight MOV case has a reg
+      // size of 8 in the 32-bit read case.
+      //
+      switch (OpCode) {
+        case 0xB6:
+          RegSize = Rex.Bits.W ? 8 : OpSize;
+          break;
+        case 0xB7:
+          RegSize =  8;
+          break;
+        default:
+          RegSize = MmioSize == 4 ? 8 : MmioSize;
+          break;
+      }
+
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val);
+      if (Status == 0) {
+        ZeroMem (Reg, RegSize);
+        CopyMem (Reg, (void *)&Val, MmioSize);
+      }
+  }
+
+  if (Status == 0) {
+    TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);
+
+    //
+    // We change instruction length to reflect true size so handler can
+    // bump rip
+    //
+    Veinfo->ExitInstructionLength =  (UINT32)((UINT64)Rip - Regs->Rip);
+  }
+
+  return Status;
+}
+
+/**
+  Handle a #VE exception.
+
+  Performs the necessary processing to handle a #VE exception.
+
+  @param[in, out]  ExceptionType  Pointer to an EFI_EXCEPTION_TYPE to be set
+                                  as value to use on error.
+  @param[in, out]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT
+
+  @retval  EFI_SUCCESS            Exception handled
+  @retval  EFI_UNSUPPORTED        #VE not supported, (new) exception value to
+                                  propagate provided
+  @retval  EFI_PROTOCOL_ERROR     #VE handling failed, (new) exception value to
+                                  propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+  IN OUT EFI_EXCEPTION_TYPE  *ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  UINT64                  Status;
+  TD_RETURN_DATA          ReturnData;
+  EFI_SYSTEM_CONTEXT_X64  *Regs;
+
+  Regs   = SystemContext.SystemContextX64;
+  Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);
+  ASSERT (Status == 0);
+  if (Status != 0) {
+    DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  switch (ReturnData.VeInfo.ExitReason) {
+    case EXIT_REASON_CPUID:
+      Status = CpuIdExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_HLT:
+      Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);
+      break;
+
+    case EXIT_REASON_IO_INSTRUCTION:
+      Status = IoExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_MSR_READ:
+      Status = ReadMsrExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val,
+        Regs->Rcx,
+        Status
+        ));
+      break;
+
+    case EXIT_REASON_MSR_WRITE:
+      Status = WriteMsrExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val,
+        Regs->Rcx,
+        Status
+        ));
+      break;
+
+    case EXIT_REASON_EPT_VIOLATION:
+      Status = MmioExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_VMCALL:
+    case EXIT_REASON_MWAIT_INSTRUCTION:
+    case EXIT_REASON_MONITOR_INSTRUCTION:
+    case EXIT_REASON_WBINVD:
+    case EXIT_REASON_RDPMC:
+      /* Handle as nops. */
+      break;
+
+    default:
+      DEBUG ((
+        DEBUG_ERROR,
+        "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+
+      ASSERT (FALSE);
+      CpuDeadLoop ();
+  }
+
+  if (Status) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",
+      Status,
+      ReturnData.VeInfo.ExitReason,
+      ReturnData.VeInfo.ExitQualification.Val
+      ));
+
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
index 7963670e7d30..255b0c1a2f7f 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -25,6 +25,8 @@
   VmgExitVcHandler.c
   VmgExitVcHandler.h
   PeiDxeVmgExitVcHandler.c
+  VmTdExitVeHandler.c
+  X64/TdVmcallCpuid.nasm
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
new file mode 100644
index 000000000000..fa86440904fe
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
@@ -0,0 +1,146 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
+%define TDVMCALL                        0x0
+%define EXIT_REASON_CPUID               0xa
+
+%macro tdcall 0
+    db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters  4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+  ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+  ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    xor rcx, rcx
+    mov ecx, %2
+
+    ; R10 = 0 (standard TDVMCALL)
+
+    xor r10d, r10d
+
+    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+    ; secrets to the VMM.
+
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor edx, edx
+    xor ebp, ebp
+    xor r8d, r8d
+    xor r9d, r9d
+    xor r14, r14
+    xor r15, r15
+%endmacro
+
+%macro tdcall_regs_postamble 0
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor ecx, ecx
+    xor edx, edx
+    xor r8d,  r8d
+    xor r9d,  r9d
+    xor r10d, r10d
+    xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0   => RAX = TDCALL leaf / TDVMCALL
+; M   => RCX = TDVMCALL register behavior
+; 0xa => R11 = TDVMCALL function / CPUID
+; RCX => R12 = p1
+; RDX => R13 = p2
+;
+;  UINT64
+;  EFIAPI
+;  TdVmCallCpuid (
+;    UINT64  EaxIn,    // Rcx
+;    UINT64  EcxIn,    // Rdx
+;    UINT64  *Results  // R8
+;    )
+global ASM_PFX(TdVmCallCpuid)
+ASM_PFX(TdVmCallCpuid):
+       tdcall_push_regs
+
+       mov r11, EXIT_REASON_CPUID
+       mov r12, rcx
+       mov r13, rdx
+
+       ; Save *results pointers
+       push r8
+
+       tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+       tdcall
+
+       ; ignore return data if TDCALL reports failure.
+       test rax, rax
+       jnz .no_return_data
+
+       ; Propagate TDVMCALL success/failure to return value.
+       mov rax, r10
+       test rax, rax
+       jnz .no_return_data
+
+       ; Retrieve *Results
+       pop r8
+       test r8, r8
+       jz .no_return_data
+       ; Caller pass in buffer so store results r12-r15 contains eax-edx
+       mov [r8 +  0], r12
+       mov [r8 +  8], r13
+       mov [r8 + 16], r14
+       mov [r8 + 24], r15
+
+.no_return_data:
+       tdcall_regs_postamble
+
+       tdcall_pop_regs
+
+       ret
-- 
2.29.2.windows.2


  parent reply	other threads:[~2022-03-12  1:54 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-12  1:53 [PATCH V8 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2022-03-12  1:53 ` [PATCH V8 01/47] MdePkg: Add Tdx.h Min Xu
2022-03-12  1:53 ` [PATCH V8 02/47] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
2022-03-15  7:41   ` [edk2-devel] " Ni, Ray
2022-03-16  1:18     ` Min Xu
2022-03-16  1:26       ` Ni, Ray
2022-03-15  7:44   ` Ni, Ray
2022-03-16  2:15     ` Min Xu
2022-03-12  1:53 ` [PATCH V8 03/47] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2022-03-12  1:53 ` [PATCH V8 04/47] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
2022-03-12  1:53 ` Min Xu [this message]
2022-03-12  1:53 ` [PATCH V8 06/47] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
2022-03-12  1:53 ` [PATCH V8 07/47] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
2022-03-12  1:53 ` [PATCH V8 08/47] MdePkg: Support mmio " Min Xu
2022-03-12  1:53 ` [PATCH V8 09/47] MdePkg: Support IoFifo " Min Xu
2022-03-12  1:53 ` [PATCH V8 10/47] MdePkg: Support IoRead/IoWrite " Min Xu
2022-03-12  1:53 ` [PATCH V8 11/47] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2022-03-12  1:53 ` [PATCH V8 12/47] MdePkg: Add macro to check SEV / TDX guest Min Xu
2022-03-12  1:53 ` [PATCH V8 13/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2022-03-15  7:57   ` Ni, Ray
2022-03-16  8:32     ` Min Xu
2022-03-16  8:36       ` Ni, Ray
2022-03-16 11:53         ` Min Xu
2022-03-12  1:53 ` [PATCH V8 14/47] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2022-03-12  1:53 ` [PATCH V8 15/47] OvmfPkg: Add TdxMailboxLib Min Xu
2022-03-12  1:53 ` [PATCH V8 16/47] OvmfPkg: Create initial version of PlatformInitLib Min Xu
2022-03-15  7:41   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 17/47] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
2022-03-15  7:42   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 18/47] OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob Min Xu
2022-03-15  7:57   ` Gerd Hoffmann
2022-03-16  5:26     ` [edk2-devel] " Min Xu
2022-03-12  1:53 ` [PATCH V8 19/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
2022-03-15  7:59   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 20/47] OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV Min Xu
2022-03-15  7:59   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 21/47] OvmfPkg/PlatformPei: Refactor AddressWidthInitialization Min Xu
2022-03-15  8:04   ` Gerd Hoffmann
2022-03-16  5:56     ` [edk2-devel] " Min Xu
2022-03-12  1:53 ` [PATCH V8 22/47] OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization Min Xu
2022-03-15  8:04   ` Gerd Hoffmann
2022-03-16  6:25     ` Min Xu
2022-03-12  1:53 ` [PATCH V8 23/47] OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization Min Xu
2022-03-15  8:05   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 25/47] OvmfPkg/PlatformPei: Refactor MemMapInitialization Min Xu
2022-03-15  8:06   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 26/47] OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization Min Xu
2022-03-15  8:13   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 27/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
2022-03-15  8:14   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 28/47] OvmfPkg/PlatformInitLib: Create MemDetect.c Min Xu
2022-03-15  8:14   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 29/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c Min Xu
2022-03-15  8:15   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 30/47] MdePkg: Add EFI_RESOURCE_MEMORY_UNACCEPTED defition Min Xu
2022-03-15  8:15   ` Gerd Hoffmann
2022-03-12  1:53 ` [PATCH V8 31/47] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
2022-03-12  1:53 ` [PATCH V8 32/47] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
2022-03-12  1:53 ` [PATCH V8 33/47] OvmfPkg: Update Sec to support Tdx Min Xu
2022-03-12  1:53 ` [PATCH V8 34/47] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2022-03-12  1:54 ` [PATCH V8 35/47] MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set Min Xu
2022-03-15  5:16   ` Wang, Jian J
2022-03-12  1:54 ` [PATCH V8 36/47] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
2022-03-15  5:16   ` Wang, Jian J
2022-03-12  1:54 ` [PATCH V8 37/47] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
2022-03-12  1:54 ` [PATCH V8 38/47] OvmfPkg: Update PlatformInitLib for Tdx guest Min Xu
2022-03-12  1:54 ` [PATCH V8 39/47] OvmfPkg: Update PlatformPei to support " Min Xu
2022-03-12  1:54 ` [PATCH V8 40/47] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
2022-03-15  3:55 ` 回复: [edk2-devel] [PATCH V8 00/47] Enable Intel TDX in OvmfPkg (Config-A) gaoliming
2022-03-15  7:11   ` Min Xu
2022-03-17  1:00     ` 回复: " gaoliming
2022-03-17  1:16       ` Min Xu
     [not found] ` <5cf66f701073359f385e7ff28b5173555ab483c3.1647047482.git.min.m.xu@intel.com>
2022-03-15  8:05   ` [PATCH V8 24/47] OvmfPkg/PlatformPei: Refactor InitializeRamRegions Gerd Hoffmann
     [not found] ` <16DB7F586DEAD807.23528@groups.io>
2022-03-17  5:31   ` [edk2-devel] [PATCH V8 12/47] MdePkg: Add macro to check SEV / TDX guest Min Xu
2022-03-18  1:13     ` 回复: " gaoliming

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0f7abb8e1ac372e35dafc28e2368270bdff2683b.1647047482.git.min.m.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox