[edk2-devel] [PATCH v3 2/5] OvmfPkg/VmgExitLib: Add support for new MMIO MOV opcodes

Lendacky, Thomas posted 5 patches 4 years, 9 months ago
[edk2-devel] [PATCH v3 2/5] OvmfPkg/VmgExitLib: Add support for new MMIO MOV opcodes
Posted by Lendacky, Thomas 4 years, 9 months ago
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3345

Enabling TPM support results in guest termination of an SEV-ES guest
because it uses MMIO opcodes that are not currently supported.

Add support for the new MMIO opcodes (0xA0 - 0xA3), MOV instructions which
use a memory offset directly encoded in the instruction. Also, add a DEBUG
statement to identify an unsupported MMIO opcode being used.

Fixes: c45f678a1ea2080344e125dc55b14e4b9f98483d
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
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: Min Xu <min.m.xu@intel.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 111 ++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
index b716541ad170..41b0c8cc5312 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
@@ -680,6 +680,7 @@ MmioExit (
   UINTN   Bytes;
   UINT64  *Register;
   UINT8   OpCode, SignByte;
+  UINTN   Address;
 
   Bytes = 0;
 
@@ -729,6 +730,57 @@ MmioExit (
     }
     break;
 
+  //
+  // MMIO write (MOV moffsetX, aX)
+  //
+  case 0xA2:
+    Bytes = 1;
+    //
+    // fall through
+    //
+  case 0xA3:
+    Bytes = ((Bytes != 0) ? Bytes :
+             (InstructionData->DataSize == Size16Bits) ? 2 :
+             (InstructionData->DataSize == Size32Bits) ? 4 :
+             (InstructionData->DataSize == Size64Bits) ? 8 :
+             0);
+
+    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
+    InstructionData->End += InstructionData->ImmediateSize;
+
+    //
+    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
+    // Use a STATIC_ASSERT to be certain the code is being built as X64.
+    //
+    STATIC_ASSERT (
+      sizeof (UINTN) == sizeof (UINT64),
+      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
+      );
+
+    Address = 0;
+    CopyMem (
+      &Address,
+      InstructionData->Immediate,
+      InstructionData->ImmediateSize
+      );
+
+    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
+    if (Status != 0) {
+      return Status;
+    }
+
+    ExitInfo1 = Address;
+    ExitInfo2 = Bytes;
+    CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
+
+    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
+    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
+    if (Status != 0) {
+      return Status;
+    }
+    break;
+
   //
   // MMIO write (MOV reg/memX, immX)
   //
@@ -811,6 +863,64 @@ MmioExit (
     CopyMem (Register, Ghcb->SharedBuffer, Bytes);
     break;
 
+  //
+  // MMIO read (MOV aX, moffsetX)
+  //
+  case 0xA0:
+    Bytes = 1;
+    //
+    // fall through
+    //
+  case 0xA1:
+    Bytes = ((Bytes != 0) ? Bytes :
+             (InstructionData->DataSize == Size16Bits) ? 2 :
+             (InstructionData->DataSize == Size32Bits) ? 4 :
+             (InstructionData->DataSize == Size64Bits) ? 8 :
+             0);
+
+    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
+    InstructionData->End += InstructionData->ImmediateSize;
+
+    //
+    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
+    // Use a STATIC_ASSERT to be certain the code is being built as X64.
+    //
+    STATIC_ASSERT (
+      sizeof (UINTN) == sizeof (UINT64),
+      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
+      );
+
+    Address = 0;
+    CopyMem (
+      &Address,
+      InstructionData->Immediate,
+      InstructionData->ImmediateSize
+      );
+
+    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
+    if (Status != 0) {
+      return Status;
+    }
+
+    ExitInfo1 = Address;
+    ExitInfo2 = Bytes;
+
+    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
+    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
+    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
+    if (Status != 0) {
+      return Status;
+    }
+
+    if (Bytes == 4) {
+      //
+      // Zero-extend for 32-bit operation
+      //
+      Regs->Rax = 0;
+    }
+    CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
+    break;
+
   //
   // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
   //
@@ -888,6 +998,7 @@ MmioExit (
     break;
 
   default:
+    DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
     Status = GP_EXCEPTION;
     ASSERT (FALSE);
   }
-- 
2.31.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#74610): https://edk2.groups.io/g/devel/message/74610
Mute This Topic: https://groups.io/mt/82461188/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH v3 2/5] OvmfPkg/VmgExitLib: Add support for new MMIO MOV opcodes
Posted by Lendacky, Thomas 4 years, 9 months ago
On 4/29/21 12:12 PM, Tom Lendacky wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3345
> 
> Enabling TPM support results in guest termination of an SEV-ES guest
> because it uses MMIO opcodes that are not currently supported.
> 
> Add support for the new MMIO opcodes (0xA0 - 0xA3), MOV instructions which
> use a memory offset directly encoded in the instruction. Also, add a DEBUG
> statement to identify an unsupported MMIO opcode being used.
> 
> Fixes: c45f678a1ea2080344e125dc55b14e4b9f98483d
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> 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: Min Xu <min.m.xu@intel.com>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>

Sorry, Laszlo, I forgot to include your Acked-by: on this patch.

Tom

> ---
>  OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 111 ++++++++++++++++++++
>  1 file changed, 111 insertions(+)
> 
> diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
> index b716541ad170..41b0c8cc5312 100644
> --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
> +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
> @@ -680,6 +680,7 @@ MmioExit (
>    UINTN   Bytes;
>    UINT64  *Register;
>    UINT8   OpCode, SignByte;
> +  UINTN   Address;
>  
>    Bytes = 0;
>  
> @@ -729,6 +730,57 @@ MmioExit (
>      }
>      break;
>  
> +  //
> +  // MMIO write (MOV moffsetX, aX)
> +  //
> +  case 0xA2:
> +    Bytes = 1;
> +    //
> +    // fall through
> +    //
> +  case 0xA3:
> +    Bytes = ((Bytes != 0) ? Bytes :
> +             (InstructionData->DataSize == Size16Bits) ? 2 :
> +             (InstructionData->DataSize == Size32Bits) ? 4 :
> +             (InstructionData->DataSize == Size64Bits) ? 8 :
> +             0);
> +
> +    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
> +    InstructionData->End += InstructionData->ImmediateSize;
> +
> +    //
> +    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
> +    // Use a STATIC_ASSERT to be certain the code is being built as X64.
> +    //
> +    STATIC_ASSERT (
> +      sizeof (UINTN) == sizeof (UINT64),
> +      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
> +      );
> +
> +    Address = 0;
> +    CopyMem (
> +      &Address,
> +      InstructionData->Immediate,
> +      InstructionData->ImmediateSize
> +      );
> +
> +    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
> +    if (Status != 0) {
> +      return Status;
> +    }
> +
> +    ExitInfo1 = Address;
> +    ExitInfo2 = Bytes;
> +    CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
> +
> +    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
> +    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
> +    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
> +    if (Status != 0) {
> +      return Status;
> +    }
> +    break;
> +
>    //
>    // MMIO write (MOV reg/memX, immX)
>    //
> @@ -811,6 +863,64 @@ MmioExit (
>      CopyMem (Register, Ghcb->SharedBuffer, Bytes);
>      break;
>  
> +  //
> +  // MMIO read (MOV aX, moffsetX)
> +  //
> +  case 0xA0:
> +    Bytes = 1;
> +    //
> +    // fall through
> +    //
> +  case 0xA1:
> +    Bytes = ((Bytes != 0) ? Bytes :
> +             (InstructionData->DataSize == Size16Bits) ? 2 :
> +             (InstructionData->DataSize == Size32Bits) ? 4 :
> +             (InstructionData->DataSize == Size64Bits) ? 8 :
> +             0);
> +
> +    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
> +    InstructionData->End += InstructionData->ImmediateSize;
> +
> +    //
> +    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
> +    // Use a STATIC_ASSERT to be certain the code is being built as X64.
> +    //
> +    STATIC_ASSERT (
> +      sizeof (UINTN) == sizeof (UINT64),
> +      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
> +      );
> +
> +    Address = 0;
> +    CopyMem (
> +      &Address,
> +      InstructionData->Immediate,
> +      InstructionData->ImmediateSize
> +      );
> +
> +    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
> +    if (Status != 0) {
> +      return Status;
> +    }
> +
> +    ExitInfo1 = Address;
> +    ExitInfo2 = Bytes;
> +
> +    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
> +    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
> +    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
> +    if (Status != 0) {
> +      return Status;
> +    }
> +
> +    if (Bytes == 4) {
> +      //
> +      // Zero-extend for 32-bit operation
> +      //
> +      Regs->Rax = 0;
> +    }
> +    CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
> +    break;
> +
>    //
>    // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
>    //
> @@ -888,6 +998,7 @@ MmioExit (
>      break;
>  
>    default:
> +    DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
>      Status = GP_EXCEPTION;
>      ASSERT (FALSE);
>    }
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#74614): https://edk2.groups.io/g/devel/message/74614
Mute This Topic: https://groups.io/mt/82461188/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH v3 2/5] OvmfPkg/VmgExitLib: Add support for new MMIO MOV opcodes
Posted by Laszlo Ersek 4 years, 9 months ago
On 04/29/21 19:19, Lendacky, Thomas wrote:
> On 4/29/21 12:12 PM, Tom Lendacky wrote:
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3345
>>
>> Enabling TPM support results in guest termination of an SEV-ES guest
>> because it uses MMIO opcodes that are not currently supported.
>>
>> Add support for the new MMIO opcodes (0xA0 - 0xA3), MOV instructions which
>> use a memory offset directly encoded in the instruction. Also, add a DEBUG
>> statement to identify an unsupported MMIO opcode being used.
>>
>> Fixes: c45f678a1ea2080344e125dc55b14e4b9f98483d
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
>> 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: Min Xu <min.m.xu@intel.com>
>> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Sorry, Laszlo, I forgot to include your Acked-by: on this patch.

np

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

Thanks
Laszlo

> 
> Tom
> 
>> ---
>>  OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 111 ++++++++++++++++++++
>>  1 file changed, 111 insertions(+)
>>
>> diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> index b716541ad170..41b0c8cc5312 100644
>> --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
>> @@ -680,6 +680,7 @@ MmioExit (
>>    UINTN   Bytes;
>>    UINT64  *Register;
>>    UINT8   OpCode, SignByte;
>> +  UINTN   Address;
>>  
>>    Bytes = 0;
>>  
>> @@ -729,6 +730,57 @@ MmioExit (
>>      }
>>      break;
>>  
>> +  //
>> +  // MMIO write (MOV moffsetX, aX)
>> +  //
>> +  case 0xA2:
>> +    Bytes = 1;
>> +    //
>> +    // fall through
>> +    //
>> +  case 0xA3:
>> +    Bytes = ((Bytes != 0) ? Bytes :
>> +             (InstructionData->DataSize == Size16Bits) ? 2 :
>> +             (InstructionData->DataSize == Size32Bits) ? 4 :
>> +             (InstructionData->DataSize == Size64Bits) ? 8 :
>> +             0);
>> +
>> +    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
>> +    InstructionData->End += InstructionData->ImmediateSize;
>> +
>> +    //
>> +    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
>> +    // Use a STATIC_ASSERT to be certain the code is being built as X64.
>> +    //
>> +    STATIC_ASSERT (
>> +      sizeof (UINTN) == sizeof (UINT64),
>> +      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
>> +      );
>> +
>> +    Address = 0;
>> +    CopyMem (
>> +      &Address,
>> +      InstructionData->Immediate,
>> +      InstructionData->ImmediateSize
>> +      );
>> +
>> +    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
>> +    if (Status != 0) {
>> +      return Status;
>> +    }
>> +
>> +    ExitInfo1 = Address;
>> +    ExitInfo2 = Bytes;
>> +    CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
>> +
>> +    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
>> +    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
>> +    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
>> +    if (Status != 0) {
>> +      return Status;
>> +    }
>> +    break;
>> +
>>    //
>>    // MMIO write (MOV reg/memX, immX)
>>    //
>> @@ -811,6 +863,64 @@ MmioExit (
>>      CopyMem (Register, Ghcb->SharedBuffer, Bytes);
>>      break;
>>  
>> +  //
>> +  // MMIO read (MOV aX, moffsetX)
>> +  //
>> +  case 0xA0:
>> +    Bytes = 1;
>> +    //
>> +    // fall through
>> +    //
>> +  case 0xA1:
>> +    Bytes = ((Bytes != 0) ? Bytes :
>> +             (InstructionData->DataSize == Size16Bits) ? 2 :
>> +             (InstructionData->DataSize == Size32Bits) ? 4 :
>> +             (InstructionData->DataSize == Size64Bits) ? 8 :
>> +             0);
>> +
>> +    InstructionData->ImmediateSize = (UINTN) (1 << InstructionData->AddrSize);
>> +    InstructionData->End += InstructionData->ImmediateSize;
>> +
>> +    //
>> +    // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
>> +    // Use a STATIC_ASSERT to be certain the code is being built as X64.
>> +    //
>> +    STATIC_ASSERT (
>> +      sizeof (UINTN) == sizeof (UINT64),
>> +      "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
>> +      );
>> +
>> +    Address = 0;
>> +    CopyMem (
>> +      &Address,
>> +      InstructionData->Immediate,
>> +      InstructionData->ImmediateSize
>> +      );
>> +
>> +    Status = ValidateMmioMemory (Ghcb, Address, Bytes);
>> +    if (Status != 0) {
>> +      return Status;
>> +    }
>> +
>> +    ExitInfo1 = Address;
>> +    ExitInfo2 = Bytes;
>> +
>> +    Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
>> +    VmgSetOffsetValid (Ghcb, GhcbSwScratch);
>> +    Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
>> +    if (Status != 0) {
>> +      return Status;
>> +    }
>> +
>> +    if (Bytes == 4) {
>> +      //
>> +      // Zero-extend for 32-bit operation
>> +      //
>> +      Regs->Rax = 0;
>> +    }
>> +    CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
>> +    break;
>> +
>>    //
>>    // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
>>    //
>> @@ -888,6 +998,7 @@ MmioExit (
>>      break;
>>  
>>    default:
>> +    DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
>>      Status = GP_EXCEPTION;
>>      ASSERT (FALSE);
>>    }
>>
> 
> 
> 
> 
> 



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#74662): https://edk2.groups.io/g/devel/message/74662
Mute This Topic: https://groups.io/mt/82461188/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-