123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /** @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);
- }
|