mirror of https://github.com/acidanthera/audk.git
236 lines
6.1 KiB
C
236 lines
6.1 KiB
C
/** @file
|
|
VMGEXIT Support Library.
|
|
|
|
Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Uefi.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/VmgExitLib.h>
|
|
#include <Register/Amd/Msr.h>
|
|
|
|
/**
|
|
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;
|
|
|
|
VmgSetOffsetValid (Ghcb, GhcbSwExitCode);
|
|
VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1);
|
|
VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2);
|
|
|
|
//
|
|
// 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
|
|
@param[in, out] InterruptState A pointer to hold the current interrupt
|
|
state, used for restoring in VmgDone ()
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
VmgInit (
|
|
IN OUT GHCB *Ghcb,
|
|
IN OUT BOOLEAN *InterruptState
|
|
)
|
|
{
|
|
//
|
|
// Be sure that an interrupt can't cause a #VC while the GHCB is
|
|
// being used.
|
|
//
|
|
*InterruptState = GetInterruptState ();
|
|
if (*InterruptState) {
|
|
DisableInterrupts ();
|
|
}
|
|
|
|
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
|
|
@param[in] InterruptState An indicator to conditionally (re)enable
|
|
interrupts
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
VmgDone (
|
|
IN OUT GHCB *Ghcb,
|
|
IN BOOLEAN InterruptState
|
|
)
|
|
{
|
|
if (InterruptState) {
|
|
EnableInterrupts ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
Marks a field at the specified offset as valid in the GHCB.
|
|
|
|
The ValidBitmap area represents the areas of the GHCB that have been marked
|
|
valid. Set the bit in ValidBitmap for the input offset.
|
|
|
|
@param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block
|
|
@param[in] Offset Qword offset in the GHCB to mark valid
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
VmgSetOffsetValid (
|
|
IN OUT GHCB *Ghcb,
|
|
IN GHCB_REGISTER Offset
|
|
)
|
|
{
|
|
UINT32 OffsetIndex;
|
|
UINT32 OffsetBit;
|
|
|
|
OffsetIndex = Offset / 8;
|
|
OffsetBit = Offset % 8;
|
|
|
|
Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit);
|
|
}
|
|
|
|
/**
|
|
Checks if a specified offset is valid in the GHCB.
|
|
|
|
The ValidBitmap area represents the areas of the GHCB that have been marked
|
|
valid. Return whether the bit in the ValidBitmap is set for the input offset.
|
|
|
|
@param[in] Ghcb A pointer to the GHCB
|
|
@param[in] Offset Qword offset in the GHCB to mark valid
|
|
|
|
@retval TRUE Offset is marked valid in the GHCB
|
|
@retval FALSE Offset is not marked valid in the GHCB
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
VmgIsOffsetValid (
|
|
IN GHCB *Ghcb,
|
|
IN GHCB_REGISTER Offset
|
|
)
|
|
{
|
|
UINT32 OffsetIndex;
|
|
UINT32 OffsetBit;
|
|
|
|
OffsetIndex = Offset / 8;
|
|
OffsetBit = Offset % 8;
|
|
|
|
return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0);
|
|
}
|