]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VmgExitLib: Support string IO for IOIO_PROT NAE events
authorTom Lendacky <thomas.lendacky@amd.com>
Wed, 12 Aug 2020 20:21:37 +0000 (15:21 -0500)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 17 Aug 2020 02:46:39 +0000 (02:46 +0000)
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: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c

index 04e8b8aebf7db6b84e5342d06e12cca2bcf9a01c..bc2e270a7ce87da42297ab4c3f3bde10e18cc879 100644 (file)
@@ -397,6 +397,26 @@ IoioExitInfo (
   ExitInfo = 0;\r
 \r
   switch (*(InstructionData->OpCodes)) {\r
+  //\r
+  // INS opcodes\r
+  //\r
+  case 0x6C:\r
+  case 0x6D:\r
+    ExitInfo |= IOIO_TYPE_INS;\r
+    ExitInfo |= IOIO_SEG_ES;\r
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+    break;\r
+\r
+  //\r
+  // OUTS opcodes\r
+  //\r
+  case 0x6E:\r
+  case 0x6F:\r
+    ExitInfo |= IOIO_TYPE_OUTS;\r
+    ExitInfo |= IOIO_SEG_DS;\r
+    ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+    break;\r
+\r
   //\r
   // IN immediate opcodes\r
   //\r
@@ -445,6 +465,8 @@ IoioExitInfo (
   //\r
   // Single-byte opcodes\r
   //\r
+  case 0x6C:\r
+  case 0x6E:\r
   case 0xE4:\r
   case 0xE6:\r
   case 0xEC:\r
@@ -506,30 +528,70 @@ IoioExit (
   IN     SEV_ES_INSTRUCTION_DATA  *InstructionData\r
   )\r
 {\r
-  UINT64  ExitInfo1, Status;\r
+  UINT64   ExitInfo1, ExitInfo2, Status;\r
+  BOOLEAN  IsString;\r
 \r
   ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
   if (ExitInfo1 == 0) {\r
     return UnsupportedExit (Ghcb, Regs, InstructionData);\r
   }\r
 \r
-  if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
-    Ghcb->SaveArea.Rax = 0;\r
+  IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
+  if (IsString) {\r
+    UINTN  IoBytes, VmgExitBytes;\r
+    UINTN  GhcbCount, OpCount;\r
+\r
+    Status = 0;\r
+\r
+    IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
+    GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
+\r
+    OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
+    while (OpCount != 0) {\r
+      ExitInfo2 = MIN (OpCount, GhcbCount);\r
+      VmgExitBytes = ExitInfo2 * IoBytes;\r
+\r
+      if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
+        CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);\r
+        Regs->Rsi += VmgExitBytes;\r
+      }\r
+\r
+      Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+      Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
+      if (Status != 0) {\r
+        return Status;\r
+      }\r
+\r
+      if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+        CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
+        Regs->Rdi += VmgExitBytes;\r
+      }\r
+\r
+      if ((ExitInfo1 & IOIO_REP) != 0) {\r
+        Regs->Rcx -= ExitInfo2;\r
+      }\r
+\r
+      OpCount -= ExitInfo2;\r
+    }\r
   } else {\r
-    CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
-  }\r
-  GhcbSetRegValid (Ghcb, GhcbRax);\r
+    if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+      Ghcb->SaveArea.Rax = 0;\r
+    } else {\r
+      CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
+    }\r
+    GhcbSetRegValid (Ghcb, GhcbRax);\r
 \r
-  Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
-  if (Status != 0) {\r
-    return Status;\r
-  }\r
+    Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
+    if (Status != 0) {\r
+      return Status;\r
+    }\r
 \r
-  if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
-    if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
-      return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+    if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+      if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+        return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+      }\r
+      CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
     }\r
-    CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
   }\r
 \r
   return 0;\r