BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4123 APIs which are defined in CcExitLib.h are added with the CcExit prefix. This is to make the APIs' name more meaningful. This change impacts OvmfPkg/UefiCpuPkg. Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Signed-off-by: Min Xu <min.m.xu@intel.com>
		
			
				
	
	
		
			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);
 | 
						|
}
 |