/** @file
VMGEXIT Support Library.
Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
/**
Check for VMGEXIT error
Check if the hypervisor has returned an error after completion of the VMGEXIT
by examining the SwExitInfo1 field of the GHCB.
@param[in] Ghcb A pointer to the GHCB
@retval 0 VMGEXIT succeeded.
@return Exception number to be propagated, VMGEXIT processing
did not succeed.
**/
STATIC
UINT64
VmgExitErrorCheck (
IN GHCB *Ghcb
)
{
GHCB_EVENT_INJECTION Event;
GHCB_EXIT_INFO ExitInfo;
UINT64 Status;
ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
ASSERT ((ExitInfo.Elements.Lower32Bits == 0) ||
(ExitInfo.Elements.Lower32Bits == 1));
Status = 0;
if (ExitInfo.Elements.Lower32Bits == 0) {
return Status;
}
if (ExitInfo.Elements.Lower32Bits == 1) {
ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0);
//
// Check that the return event is valid
//
Event.Uint64 = Ghcb->SaveArea.SwExitInfo2;
if (Event.Elements.Valid &&
Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION) {
switch (Event.Elements.Vector) {
case GP_EXCEPTION:
case UD_EXCEPTION:
//
// Use returned event as return code
//
Status = Event.Uint64;
}
}
}
if (Status == 0) {
GHCB_EVENT_INJECTION GpEvent;
GpEvent.Uint64 = 0;
GpEvent.Elements.Vector = GP_EXCEPTION;
GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
GpEvent.Elements.Valid = 1;
Status = GpEvent.Uint64;
}
return Status;
}
/**
Perform VMGEXIT.
Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and
then handles the return actions.
@param[in, out] Ghcb A pointer to the GHCB
@param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode
field of the GHCB.
@param[in] ExitInfo1 VMGEXIT information to be assigned to the
SwExitInfo1 field of the GHCB.
@param[in] ExitInfo2 VMGEXIT information to be assigned to the
SwExitInfo2 field of the GHCB.
@retval 0 VMGEXIT succeeded.
@return Exception number to be propagated, VMGEXIT
processing did not succeed.
**/
UINT64
EFIAPI
VmgExit (
IN OUT GHCB *Ghcb,
IN UINT64 ExitCode,
IN UINT64 ExitInfo1,
IN UINT64 ExitInfo2
)
{
Ghcb->SaveArea.SwExitCode = ExitCode;
Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
//
// Guest memory is used for the guest-hypervisor communication, so fence
// the invocation of the VMGEXIT instruction to ensure GHCB accesses are
// synchronized properly.
//
MemoryFence ();
AsmVmgExit ();
MemoryFence ();
return VmgExitErrorCheck (Ghcb);
}
/**
Perform pre-VMGEXIT initialization/preparation.
Performs the necessary steps in preparation for invoking VMGEXIT. Must be
called before setting any fields within the GHCB.
@param[in, out] Ghcb A pointer to the GHCB
**/
VOID
EFIAPI
VmgInit (
IN OUT GHCB *Ghcb
)
{
SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
}
/**
Perform post-VMGEXIT cleanup.
Performs the necessary steps to cleanup after invoking VMGEXIT. Must be
called after obtaining needed fields within the GHCB.
@param[in, out] Ghcb A pointer to the GHCB
**/
VOID
EFIAPI
VmgDone (
IN OUT GHCB *Ghcb
)
{
}