mirror of https://github.com/acidanthera/audk.git
OvmfPkg/VmgExitLib: Support string IO for IOIO_PROT NAE events
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>
This commit is contained in:
parent
fb040cced3
commit
0020157a98
|
@ -397,6 +397,26 @@ IoioExitInfo (
|
|||
ExitInfo = 0;
|
||||
|
||||
switch (*(InstructionData->OpCodes)) {
|
||||
//
|
||||
// INS opcodes
|
||||
//
|
||||
case 0x6C:
|
||||
case 0x6D:
|
||||
ExitInfo |= IOIO_TYPE_INS;
|
||||
ExitInfo |= IOIO_SEG_ES;
|
||||
ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
|
||||
break;
|
||||
|
||||
//
|
||||
// OUTS opcodes
|
||||
//
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
ExitInfo |= IOIO_TYPE_OUTS;
|
||||
ExitInfo |= IOIO_SEG_DS;
|
||||
ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
|
||||
break;
|
||||
|
||||
//
|
||||
// IN immediate opcodes
|
||||
//
|
||||
|
@ -445,6 +465,8 @@ IoioExitInfo (
|
|||
//
|
||||
// Single-byte opcodes
|
||||
//
|
||||
case 0x6C:
|
||||
case 0x6E:
|
||||
case 0xE4:
|
||||
case 0xE6:
|
||||
case 0xEC:
|
||||
|
@ -506,30 +528,70 @@ IoioExit (
|
|||
IN SEV_ES_INSTRUCTION_DATA *InstructionData
|
||||
)
|
||||
{
|
||||
UINT64 ExitInfo1, Status;
|
||||
UINT64 ExitInfo1, ExitInfo2, Status;
|
||||
BOOLEAN IsString;
|
||||
|
||||
ExitInfo1 = IoioExitInfo (Regs, InstructionData);
|
||||
if (ExitInfo1 == 0) {
|
||||
return UnsupportedExit (Ghcb, Regs, InstructionData);
|
||||
}
|
||||
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
|
||||
Ghcb->SaveArea.Rax = 0;
|
||||
} else {
|
||||
CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
|
||||
}
|
||||
GhcbSetRegValid (Ghcb, GhcbRax);
|
||||
IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
|
||||
if (IsString) {
|
||||
UINTN IoBytes, VmgExitBytes;
|
||||
UINTN GhcbCount, OpCount;
|
||||
|
||||
Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
|
||||
if (Status != 0) {
|
||||
return Status;
|
||||
}
|
||||
Status = 0;
|
||||
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
|
||||
if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
|
||||
return UnsupportedExit (Ghcb, Regs, InstructionData);
|
||||
IoBytes = IOIO_DATA_BYTES (ExitInfo1);
|
||||
GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
|
||||
|
||||
OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
|
||||
while (OpCount != 0) {
|
||||
ExitInfo2 = MIN (OpCount, GhcbCount);
|
||||
VmgExitBytes = ExitInfo2 * IoBytes;
|
||||
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
|
||||
CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);
|
||||
Regs->Rsi += VmgExitBytes;
|
||||
}
|
||||
|
||||
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
|
||||
Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
|
||||
if (Status != 0) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
|
||||
CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
|
||||
Regs->Rdi += VmgExitBytes;
|
||||
}
|
||||
|
||||
if ((ExitInfo1 & IOIO_REP) != 0) {
|
||||
Regs->Rcx -= ExitInfo2;
|
||||
}
|
||||
|
||||
OpCount -= ExitInfo2;
|
||||
}
|
||||
} else {
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
|
||||
Ghcb->SaveArea.Rax = 0;
|
||||
} else {
|
||||
CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
|
||||
}
|
||||
GhcbSetRegValid (Ghcb, GhcbRax);
|
||||
|
||||
Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
|
||||
if (Status != 0) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
|
||||
if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
|
||||
return UnsupportedExit (Ghcb, Regs, InstructionData);
|
||||
}
|
||||
CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
|
||||
}
|
||||
CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue