Avoid use of Local APIC Base Address MSR (MSR_IA32_APIC_BASE_ADDRESS) if there is only 1 CPU present. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney <michael.d.kinney@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17218 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			381 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Multi-Processor support functions implementation.
 | 
						|
 | 
						|
  Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "DebugAgent.h"
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile  mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE};
 | 
						|
 | 
						|
GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile  mDebugCpuData = {0};
 | 
						|
 | 
						|
/**
 | 
						|
  Acquire a spin lock when Multi-processor supported.
 | 
						|
 | 
						|
  It will block in the function if cannot get the access control.
 | 
						|
  If Multi-processor is not supported, return directly.
 | 
						|
 | 
						|
  @param[in, out] MpSpinLock      A pointer to the spin lock.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
AcquireMpSpinLock (
 | 
						|
  IN OUT SPIN_LOCK           *MpSpinLock
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!MultiProcessorDebugSupport()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  while (TRUE) {
 | 
						|
    if (AcquireSpinLockOrFail (MpSpinLock)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    CpuPause ();
 | 
						|
    continue;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Release a spin lock when Multi-processor supported.
 | 
						|
 | 
						|
  @param[in, out] MpSpinLock      A pointer to the spin lock.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ReleaseMpSpinLock (
 | 
						|
  IN OUT SPIN_LOCK           *MpSpinLock
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!MultiProcessorDebugSupport()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  ReleaseSpinLock (MpSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Break the other processor by send IPI.
 | 
						|
 | 
						|
  @param[in] CurrentProcessorIndex  Current processor index value.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
HaltOtherProcessors (
 | 
						|
  IN UINT32             CurrentProcessorIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);
 | 
						|
  if (!IsBsp (CurrentProcessorIndex)) {
 | 
						|
    SetIpiSentByApFlag (TRUE);;
 | 
						|
  }
 | 
						|
 | 
						|
  mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the debug viewpoint to the current breaking CPU.
 | 
						|
  //
 | 
						|
  SetDebugViewPoint (CurrentProcessorIndex);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send fixed IPI to other processors.
 | 
						|
  //
 | 
						|
  SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the current processor's index.
 | 
						|
 | 
						|
  @return Processor index value.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
GetProcessorIndex (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                Index;
 | 
						|
  UINT16                LocalApicID;
 | 
						|
 | 
						|
  LocalApicID = (UINT16) GetApicId ();
 | 
						|
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
 | 
						|
  for (Index = 0; Index < mDebugCpuData.CpuCount; Index ++) {
 | 
						|
    if (mDebugCpuData.ApicID[Index] == LocalApicID) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index == mDebugCpuData.CpuCount) {
 | 
						|
    mDebugCpuData.ApicID[Index] = LocalApicID;
 | 
						|
    mDebugCpuData.CpuCount ++ ;
 | 
						|
  }
 | 
						|
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
 | 
						|
  return Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if the specified processor is BSP or not.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex Processor index value.
 | 
						|
 | 
						|
  @retval TRUE    It is BSP.
 | 
						|
  @retval FALSE   It isn't BSP.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsBsp (
 | 
						|
  IN UINT32  ProcessorIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // If there are less than 2 CPUs detected, then the currently executing CPU
 | 
						|
  // must be the BSP.  This avoids an access to an MSR that may not be supported 
 | 
						|
  // on single core CPUs.
 | 
						|
  //
 | 
						|
  if (mDebugCpuData.CpuCount < 2) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (AsmMsrBitFieldRead64 (MSR_IA32_APIC_BASE_ADDRESS, 8, 8) == 1) {
 | 
						|
    if (mDebugMpContext.BspIndex != ProcessorIndex) {
 | 
						|
      AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
      mDebugMpContext.BspIndex = ProcessorIndex;
 | 
						|
      ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
  } else {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set processor stop flag bitmask in MP context.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex Processor index value.
 | 
						|
  @param[in] StopFlag       TRUE means set stop flag.
 | 
						|
                            FALSE means clean break flag.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetCpuStopFlagByIndex (
 | 
						|
  IN UINT32             ProcessorIndex,
 | 
						|
  IN BOOLEAN            StopFlag
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                 Value;
 | 
						|
  UINTN                 Index;
 | 
						|
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
 | 
						|
  Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
 | 
						|
  Index = ProcessorIndex % 8;
 | 
						|
  if (StopFlag) {
 | 
						|
    Value = BitFieldWrite8 (Value, Index, Index, 1);
 | 
						|
  } else {
 | 
						|
    Value = BitFieldWrite8 (Value, Index, Index, 0);
 | 
						|
  }
 | 
						|
  mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
 | 
						|
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set processor break flag bitmask in MP context.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex Processor index value.
 | 
						|
  @param[in] BreakFlag      TRUE means set break flag.
 | 
						|
                            FALSE means clean break flag.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetCpuBreakFlagByIndex (
 | 
						|
  IN UINT32             ProcessorIndex,
 | 
						|
  IN BOOLEAN            BreakFlag
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                 Value;
 | 
						|
  UINTN                 Index;
 | 
						|
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
 | 
						|
  Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
 | 
						|
  Index = ProcessorIndex % 8;
 | 
						|
  if (BreakFlag) {
 | 
						|
    Value = BitFieldWrite8 (Value, Index, Index, 1);
 | 
						|
  } else {
 | 
						|
    Value = BitFieldWrite8 (Value, Index, Index, 0);
 | 
						|
  }
 | 
						|
  mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
 | 
						|
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if processor is stopped already.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex   Processor index value.
 | 
						|
 | 
						|
  @retval TRUE        Processor is stopped already.
 | 
						|
  @retval TRUE        Processor isn't stopped.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsCpuStopped (
 | 
						|
  IN UINT32              ProcessorIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                 CpuMask;
 | 
						|
 | 
						|
  CpuMask = (UINT8) (1 << (ProcessorIndex % 8));
 | 
						|
 | 
						|
  if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
 | 
						|
    return TRUE;
 | 
						|
  } else {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the run command flag.
 | 
						|
 | 
						|
  @param[in] RunningFlag   TRUE means run command flag is set.
 | 
						|
                           FALSE means run command flag is cleared.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetCpuRunningFlag (
 | 
						|
  IN BOOLEAN            RunningFlag
 | 
						|
  )
 | 
						|
{
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
  mDebugMpContext.RunCommandSet = RunningFlag;
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the current view point to be debugged.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex   Processor index value.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetDebugViewPoint (
 | 
						|
  IN UINT32             ProcessorIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
  mDebugMpContext.ViewPointIndex = ProcessorIndex;
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the IPI send by BPS/AP flag.
 | 
						|
 | 
						|
  @param[in] IpiSentByApFlag   TRUE means this IPI is sent by AP.
 | 
						|
                               FALSE means this IPI is sent by BSP.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetIpiSentByApFlag (
 | 
						|
  IN BOOLEAN            IpiSentByApFlag
 | 
						|
  )
 | 
						|
{
 | 
						|
  AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
  mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
 | 
						|
  ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check the next pending breaking CPU.
 | 
						|
 | 
						|
  @retval others      There is at least one processor broken, the minimum
 | 
						|
                      index number of Processor returned.
 | 
						|
  @retval -1          No any processor broken.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
FindNextPendingBreakCpu (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32               Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
 | 
						|
    if (mDebugMpContext.CpuBreakMask[Index] != 0) {
 | 
						|
      return  (UINT32) LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (UINT32)-1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if all processors are in running status.
 | 
						|
 | 
						|
  @retval TRUE        All processors run.
 | 
						|
  @retval FALSE       At least one processor does not run.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsAllCpuRunning (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN              Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
 | 
						|
    if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if the current processor is the first breaking processor.
 | 
						|
 | 
						|
  If yes, halt other processors.
 | 
						|
 | 
						|
  @param[in] ProcessorIndex   Processor index value.
 | 
						|
 | 
						|
  @return TRUE       This processor is the first breaking processor.
 | 
						|
  @return FALSE      This processor is not the first breaking processor.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsFirstBreakProcessor (
 | 
						|
  IN UINT32              ProcessorIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (MultiProcessorDebugSupport()) {
 | 
						|
    if (mDebugMpContext.BreakAtCpuIndex != (UINT32) -1) {
 | 
						|
      //
 | 
						|
      // The current processor is not the first breaking one.
 | 
						|
      //
 | 
						|
      SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
 | 
						|
      return FALSE;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // If no any processor breaks, try to halt other processors
 | 
						|
      //
 | 
						|
      HaltOtherProcessors (ProcessorIndex);
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 |