mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-04 13:23:26 +01:00
240 lines
6.1 KiB
C
240 lines
6.1 KiB
C
|
/** @file
|
||
|
CcExitLib Support Library.
|
||
|
|
||
|
Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
|
||
|
Copyright (C) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include <Base.h>
|
||
|
#include <Uefi.h>
|
||
|
#include <Library/BaseMemoryLib.h>
|
||
|
#include <Library/CcExitLib.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
|
||
|
CcExitVmgExit (
|
||
|
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;
|
||
|
|
||
|
CcExitVmgSetOffsetValid (Ghcb, GhcbSwExitCode);
|
||
|
CcExitVmgSetOffsetValid (Ghcb, GhcbSwExitInfo1);
|
||
|
CcExitVmgSetOffsetValid (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 CcExitVmgDone ()
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
CcExitVmgInit (
|
||
|
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
|
||
|
CcExitVmgDone (
|
||
|
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
|
||
|
CcExitVmgSetOffsetValid (
|
||
|
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
|
||
|
CcExitVmgIsOffsetValid (
|
||
|
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);
|
||
|
}
|