summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
new file mode 100644
index 00000000..30ee5205
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
@@ -0,0 +1,377 @@
+/** @file
+ Multi-Processor support functions implementation.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 (!DebugAgentIsBsp (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
+DebugAgentIsBsp (
+ IN UINT32 ProcessorIndex
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER MsrApicBase;
+
+ //
+ // 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;
+ }
+
+ MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (MsrApicBase.Bits.BSP == 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;
+}
+