]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
OvmfPkg/VmgExitLib: Set the SwScratch valid bit for MMIO events
[mirror_edk2.git] / OvmfPkg / Library / VmgExitLib / VmgExitVcHandler.c
index 1e8b8ce424c3849c29b344608aee37d022af8a59..9bf9d160179c1f036a404a7e56e1c70f2024f3c3 100644 (file)
@@ -126,62 +126,14 @@ UINT64
   SEV_ES_INSTRUCTION_DATA  *InstructionData\r
   );\r
 \r
+//\r
+// Per-CPU data mapping structure\r
+//\r
+typedef struct {\r
+  BOOLEAN  Dr7Cached;\r
+  UINT64   Dr7;\r
+} SEV_ES_PER_CPU_DATA;\r
 \r
-/**\r
-  Checks the GHCB to determine if the specified register has been marked valid.\r
-\r
-  The ValidBitmap area represents the areas of the GHCB that have been marked\r
-  valid. Return an indication of whether the area of the GHCB that holds the\r
-  specified register has been marked valid.\r
-\r
-  @param[in] Ghcb    Pointer to the Guest-Hypervisor Communication Block\r
-  @param[in] Reg     Offset in the GHCB of the register to check\r
-\r
-  @retval TRUE       Register has been marked vald in the GHCB\r
-  @retval FALSE      Register has not been marked valid in the GHCB\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-GhcbIsRegValid (\r
-  IN GHCB                *Ghcb,\r
-  IN GHCB_REGISTER       Reg\r
-  )\r
-{\r
-  UINT32  RegIndex;\r
-  UINT32  RegBit;\r
-\r
-  RegIndex = Reg / 8;\r
-  RegBit   = Reg & 0x07;\r
-\r
-  return ((Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit)) != 0);\r
-}\r
-\r
-/**\r
-  Marks a register as valid in the GHCB.\r
-\r
-  The ValidBitmap area represents the areas of the GHCB that have been marked\r
-  valid. Set the area of the GHCB that holds the specified register as valid.\r
-\r
-  @param[in, out] Ghcb    Pointer to the Guest-Hypervisor Communication Block\r
-  @param[in] Reg          Offset in the GHCB of the register to mark valid\r
-\r
-**/\r
-STATIC\r
-VOID\r
-GhcbSetRegValid (\r
-  IN OUT GHCB                *Ghcb,\r
-  IN     GHCB_REGISTER       Reg\r
-  )\r
-{\r
-  UINT32  RegIndex;\r
-  UINT32  RegBit;\r
-\r
-  RegIndex = Reg / 8;\r
-  RegBit   = Reg & 0x07;\r
-\r
-  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);\r
-}\r
 \r
 /**\r
   Return a pointer to the contents of the specified register.\r
@@ -712,6 +664,7 @@ MmioExit (
     CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
 \r
     Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
     Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
     if (Status != 0) {\r
       return Status;\r
@@ -741,6 +694,7 @@ MmioExit (
     CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
 \r
     Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
     Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
     if (Status != 0) {\r
       return Status;\r
@@ -773,6 +727,7 @@ MmioExit (
     ExitInfo2 = Bytes;\r
 \r
     Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
     Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
     if (Status != 0) {\r
       return Status;\r
@@ -803,6 +758,7 @@ MmioExit (
     ExitInfo2 = Bytes;\r
 \r
     Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
     Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
     if (Status != 0) {\r
       return Status;\r
@@ -828,6 +784,7 @@ MmioExit (
     ExitInfo2 = Bytes;\r
 \r
     Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
     Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
     if (Status != 0) {\r
       return Status;\r
@@ -858,6 +815,38 @@ MmioExit (
   return Status;\r
 }\r
 \r
+/**\r
+  Handle a MWAIT event.\r
+\r
+  Use the VMGEXIT instruction to handle a MWAIT event.\r
+\r
+  @param[in, out] Ghcb             Pointer to the Guest-Hypervisor Communication\r
+                                   Block\r
+  @param[in, out] Regs             x64 processor context\r
+  @param[in]      InstructionData  Instruction parsing context\r
+\r
+  @retval 0                        Event handled successfully\r
+  @return                          New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MwaitExit (\r
+  IN OUT GHCB                     *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64   *Regs,\r
+  IN     SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  )\r
+{\r
+  DecodeModRm (Regs, InstructionData);\r
+\r
+  Ghcb->SaveArea.Rax = Regs->Rax;\r
+  VmgSetOffsetValid (Ghcb, GhcbRax);\r
+  Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+  VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+\r
+  return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
+}\r
+\r
 /**\r
   Handle a MONITOR event.\r
 \r
@@ -883,11 +872,11 @@ MonitorExit (
   DecodeModRm (Regs, InstructionData);\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;  // Identity mapped, so VA = PA\r
-  GhcbSetRegValid (Ghcb, GhcbRax);\r
+  VmgSetOffsetValid (Ghcb, GhcbRax);\r
   Ghcb->SaveArea.Rcx = Regs->Rcx;\r
-  GhcbSetRegValid (Ghcb, GhcbRcx);\r
+  VmgSetOffsetValid (Ghcb, GhcbRcx);\r
   Ghcb->SaveArea.Rdx = Regs->Rdx;\r
-  GhcbSetRegValid (Ghcb, GhcbRdx);\r
+  VmgSetOffsetValid (Ghcb, GhcbRdx);\r
 \r
   return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
 }\r
@@ -948,9 +937,9 @@ RdtscpExit (
     return Status;\r
   }\r
 \r
-  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRcx) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+  if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
   Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -987,16 +976,16 @@ VmmCallExit (
   DecodeModRm (Regs, InstructionData);\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;\r
-  GhcbSetRegValid (Ghcb, GhcbRax);\r
+  VmgSetOffsetValid (Ghcb, GhcbRax);\r
   Ghcb->SaveArea.Cpl = (UINT8) (Regs->Cs & 0x3);\r
-  GhcbSetRegValid (Ghcb, GhcbCpl);\r
+  VmgSetOffsetValid (Ghcb, GhcbCpl);\r
 \r
   Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
   if (Status != 0) {\r
     return Status;\r
   }\r
 \r
-  if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+  if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
   Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -1034,15 +1023,15 @@ MsrExit (
   case 0x30: // WRMSR\r
     ExitInfo1 = 1;\r
     Ghcb->SaveArea.Rax = Regs->Rax;\r
-    GhcbSetRegValid (Ghcb, GhcbRax);\r
+    VmgSetOffsetValid (Ghcb, GhcbRax);\r
     Ghcb->SaveArea.Rdx = Regs->Rdx;\r
-    GhcbSetRegValid (Ghcb, GhcbRdx);\r
+    VmgSetOffsetValid (Ghcb, GhcbRdx);\r
     //\r
     // fall through\r
     //\r
   case 0x32: // RDMSR\r
     Ghcb->SaveArea.Rcx = Regs->Rcx;\r
-    GhcbSetRegValid (Ghcb, GhcbRcx);\r
+    VmgSetOffsetValid (Ghcb, GhcbRcx);\r
     break;\r
   default:\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
@@ -1054,8 +1043,8 @@ MsrExit (
   }\r
 \r
   if (ExitInfo1 == 0) {\r
-    if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
-        !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+    if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+        !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
       return UnsupportedExit (Ghcb, Regs, InstructionData);\r
     }\r
     Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -1249,6 +1238,7 @@ IoioExit (
       }\r
 \r
       Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+      VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
       Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
       if (Status != 0) {\r
         return Status;\r
@@ -1271,7 +1261,7 @@ IoioExit (
     } else {\r
       CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
     }\r
-    GhcbSetRegValid (Ghcb, GhcbRax);\r
+    VmgSetOffsetValid (Ghcb, GhcbRax);\r
 \r
     Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
     if (Status != 0) {\r
@@ -1279,7 +1269,7 @@ IoioExit (
     }\r
 \r
     if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
-      if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+      if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
         return UnsupportedExit (Ghcb, Regs, InstructionData);\r
       }\r
       CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
@@ -1339,15 +1329,15 @@ CpuidExit (
   UINT64  Status;\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;\r
-  GhcbSetRegValid (Ghcb, GhcbRax);\r
+  VmgSetOffsetValid (Ghcb, GhcbRax);\r
   Ghcb->SaveArea.Rcx = Regs->Rcx;\r
-  GhcbSetRegValid (Ghcb, GhcbRcx);\r
+  VmgSetOffsetValid (Ghcb, GhcbRcx);\r
   if (Regs->Rax == CPUID_EXTENDED_STATE) {\r
     IA32_CR4  Cr4;\r
 \r
     Cr4.UintN = AsmReadCr4 ();\r
     Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
-    GhcbSetRegValid (Ghcb, GhcbXCr0);\r
+    VmgSetOffsetValid (Ghcb, GhcbXCr0);\r
   }\r
 \r
   Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
@@ -1355,10 +1345,10 @@ CpuidExit (
     return Status;\r
   }\r
 \r
-  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRbx) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRcx) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+  if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
   Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -1394,15 +1384,15 @@ RdpmcExit (
   UINT64  Status;\r
 \r
   Ghcb->SaveArea.Rcx = Regs->Rcx;\r
-  GhcbSetRegValid (Ghcb, GhcbRcx);\r
+  VmgSetOffsetValid (Ghcb, GhcbRcx);\r
 \r
   Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
   if (Status != 0) {\r
     return Status;\r
   }\r
 \r
-  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+  if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
   Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -1440,8 +1430,8 @@ RdtscExit (
     return Status;\r
   }\r
 \r
-  if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
-      !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+  if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+      !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
   Regs->Rax = Ghcb->SaveArea.Rax;\r
@@ -1450,6 +1440,104 @@ RdtscExit (
   return 0;\r
 }\r
 \r
+/**\r
+  Handle a DR7 register write event.\r
+\r
+  Use the VMGEXIT instruction to handle a DR7 write event.\r
+\r
+  @param[in, out] Ghcb             Pointer to the Guest-Hypervisor Communication\r
+                                   Block\r
+  @param[in, out] Regs             x64 processor context\r
+  @param[in]      InstructionData  Instruction parsing context\r
+\r
+  @retval 0                        Event handled successfully\r
+  @return                          New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7WriteExit (\r
+  IN OUT GHCB                     *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64   *Regs,\r
+  IN     SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  )\r
+{\r
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext;\r
+  SEV_ES_PER_CPU_DATA            *SevEsData;\r
+  UINT64                         *Register;\r
+  UINT64                         Status;\r
+\r
+  Ext = &InstructionData->Ext;\r
+  SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+\r
+  DecodeModRm (Regs, InstructionData);\r
+\r
+  //\r
+  // MOV DRn always treats MOD == 3 no matter how encoded\r
+  //\r
+  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+  //\r
+  // Using a value of 0 for ExitInfo1 means RAX holds the value\r
+  //\r
+  Ghcb->SaveArea.Rax = *Register;\r
+  VmgSetOffsetValid (Ghcb, GhcbRax);\r
+\r
+  Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
+  if (Status != 0) {\r
+    return Status;\r
+  }\r
+\r
+  SevEsData->Dr7 = *Register;\r
+  SevEsData->Dr7Cached = TRUE;\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Handle a DR7 register read event.\r
+\r
+  Use the VMGEXIT instruction to handle a DR7 read event.\r
+\r
+  @param[in, out] Ghcb             Pointer to the Guest-Hypervisor Communication\r
+                                   Block\r
+  @param[in, out] Regs             x64 processor context\r
+  @param[in]      InstructionData  Instruction parsing context\r
+\r
+  @retval 0                        Event handled successfully\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7ReadExit (\r
+  IN OUT GHCB                     *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64   *Regs,\r
+  IN     SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  )\r
+{\r
+  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext;\r
+  SEV_ES_PER_CPU_DATA            *SevEsData;\r
+  UINT64                         *Register;\r
+\r
+  Ext = &InstructionData->Ext;\r
+  SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+\r
+  DecodeModRm (Regs, InstructionData);\r
+\r
+  //\r
+  // MOV DRn always treats MOD == 3 no matter how encoded\r
+  //\r
+  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+  //\r
+  // If there is a cached valued for DR7, return that. Otherwise return the\r
+  // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
+  //\r
+  *Register = (SevEsData->Dr7Cached) ? SevEsData->Dr7 : 0x400;\r
+\r
+  return 0;\r
+}\r
+\r
 /**\r
   Handle a #VC exception.\r
 \r
@@ -1494,6 +1582,14 @@ VmgExitHandleVc (
 \r
   ExitCode = Regs->ExceptionData;\r
   switch (ExitCode) {\r
+  case SVM_EXIT_DR7_READ:\r
+    NaeExit = Dr7ReadExit;\r
+    break;\r
+\r
+  case SVM_EXIT_DR7_WRITE:\r
+    NaeExit = Dr7WriteExit;\r
+    break;\r
+\r
   case SVM_EXIT_RDTSC:\r
     NaeExit = RdtscExit;\r
     break;\r
@@ -1534,6 +1630,10 @@ VmgExitHandleVc (
     NaeExit = MonitorExit;\r
     break;\r
 \r
+  case SVM_EXIT_MWAIT:\r
+    NaeExit = MwaitExit;\r
+    break;\r
+\r
   case SVM_EXIT_NPF:\r
     NaeExit = MmioExit;\r
     break;\r