Home | History | Annotate | Download | only in DebugAgentCommon
      1 /** @file
      2   Multi-Processor support functions implementation.
      3 
      4   Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DebugAgent.h"
     16 
     17 GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile  mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE};
     18 
     19 GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile  mDebugCpuData = {0};
     20 
     21 /**
     22   Acquire a spin lock when Multi-processor supported.
     23 
     24   It will block in the function if cannot get the access control.
     25   If Multi-processor is not supported, return directly.
     26 
     27   @param[in, out] MpSpinLock      A pointer to the spin lock.
     28 
     29 **/
     30 VOID
     31 AcquireMpSpinLock (
     32   IN OUT SPIN_LOCK           *MpSpinLock
     33   )
     34 {
     35   if (!MultiProcessorDebugSupport()) {
     36     return;
     37   }
     38 
     39   while (TRUE) {
     40     if (AcquireSpinLockOrFail (MpSpinLock)) {
     41       break;
     42     }
     43     CpuPause ();
     44     continue;
     45   }
     46 }
     47 
     48 /**
     49   Release a spin lock when Multi-processor supported.
     50 
     51   @param[in, out] MpSpinLock      A pointer to the spin lock.
     52 
     53 **/
     54 VOID
     55 ReleaseMpSpinLock (
     56   IN OUT SPIN_LOCK           *MpSpinLock
     57   )
     58 {
     59   if (!MultiProcessorDebugSupport()) {
     60     return;
     61   }
     62 
     63   ReleaseSpinLock (MpSpinLock);
     64 }
     65 
     66 /**
     67   Break the other processor by send IPI.
     68 
     69   @param[in] CurrentProcessorIndex  Current processor index value.
     70 
     71 **/
     72 VOID
     73 HaltOtherProcessors (
     74   IN UINT32             CurrentProcessorIndex
     75   )
     76 {
     77   DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);
     78   if (!IsBsp (CurrentProcessorIndex)) {
     79     SetIpiSentByApFlag (TRUE);;
     80   }
     81 
     82   mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;
     83 
     84   //
     85   // Set the debug viewpoint to the current breaking CPU.
     86   //
     87   SetDebugViewPoint (CurrentProcessorIndex);
     88 
     89   //
     90   // Send fixed IPI to other processors.
     91   //
     92   SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);
     93 
     94 }
     95 
     96 /**
     97   Get the current processor's index.
     98 
     99   @return Processor index value.
    100 
    101 **/
    102 UINT32
    103 GetProcessorIndex (
    104   VOID
    105   )
    106 {
    107   UINT32                Index;
    108   UINT16                LocalApicID;
    109 
    110   LocalApicID = (UINT16) GetApicId ();
    111 
    112   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    113 
    114   for (Index = 0; Index < mDebugCpuData.CpuCount; Index ++) {
    115     if (mDebugCpuData.ApicID[Index] == LocalApicID) {
    116       break;
    117     }
    118   }
    119 
    120   if (Index == mDebugCpuData.CpuCount) {
    121     mDebugCpuData.ApicID[Index] = LocalApicID;
    122     mDebugCpuData.CpuCount ++ ;
    123   }
    124 
    125   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    126 
    127   return Index;
    128 }
    129 
    130 /**
    131   Check if the specified processor is BSP or not.
    132 
    133   @param[in] ProcessorIndex Processor index value.
    134 
    135   @retval TRUE    It is BSP.
    136   @retval FALSE   It isn't BSP.
    137 
    138 **/
    139 BOOLEAN
    140 IsBsp (
    141   IN UINT32  ProcessorIndex
    142   )
    143 {
    144   MSR_IA32_APIC_BASE_REGISTER  MsrApicBase;
    145 
    146   //
    147   // If there are less than 2 CPUs detected, then the currently executing CPU
    148   // must be the BSP.  This avoids an access to an MSR that may not be supported
    149   // on single core CPUs.
    150   //
    151   if (mDebugCpuData.CpuCount < 2) {
    152     return TRUE;
    153   }
    154 
    155   MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
    156   if (MsrApicBase.Bits.BSP == 1) {
    157     if (mDebugMpContext.BspIndex != ProcessorIndex) {
    158       AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    159       mDebugMpContext.BspIndex = ProcessorIndex;
    160       ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    161     }
    162     return TRUE;
    163   } else {
    164     return FALSE;
    165   }
    166 }
    167 
    168 /**
    169   Set processor stop flag bitmask in MP context.
    170 
    171   @param[in] ProcessorIndex Processor index value.
    172   @param[in] StopFlag       TRUE means set stop flag.
    173                             FALSE means clean break flag.
    174 
    175 **/
    176 VOID
    177 SetCpuStopFlagByIndex (
    178   IN UINT32             ProcessorIndex,
    179   IN BOOLEAN            StopFlag
    180   )
    181 {
    182   UINT8                 Value;
    183   UINTN                 Index;
    184 
    185   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    186 
    187   Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
    188   Index = ProcessorIndex % 8;
    189   if (StopFlag) {
    190     Value = BitFieldWrite8 (Value, Index, Index, 1);
    191   } else {
    192     Value = BitFieldWrite8 (Value, Index, Index, 0);
    193   }
    194   mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
    195 
    196   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    197 }
    198 
    199 /**
    200   Set processor break flag bitmask in MP context.
    201 
    202   @param[in] ProcessorIndex Processor index value.
    203   @param[in] BreakFlag      TRUE means set break flag.
    204                             FALSE means clean break flag.
    205 
    206 **/
    207 VOID
    208 SetCpuBreakFlagByIndex (
    209   IN UINT32             ProcessorIndex,
    210   IN BOOLEAN            BreakFlag
    211   )
    212 {
    213   UINT8                 Value;
    214   UINTN                 Index;
    215 
    216   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    217 
    218   Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
    219   Index = ProcessorIndex % 8;
    220   if (BreakFlag) {
    221     Value = BitFieldWrite8 (Value, Index, Index, 1);
    222   } else {
    223     Value = BitFieldWrite8 (Value, Index, Index, 0);
    224   }
    225   mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
    226 
    227   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    228 }
    229 
    230 /**
    231   Check if processor is stopped already.
    232 
    233   @param[in] ProcessorIndex   Processor index value.
    234 
    235   @retval TRUE        Processor is stopped already.
    236   @retval TRUE        Processor isn't stopped.
    237 
    238 **/
    239 BOOLEAN
    240 IsCpuStopped (
    241   IN UINT32              ProcessorIndex
    242   )
    243 {
    244   UINT8                 CpuMask;
    245 
    246   CpuMask = (UINT8) (1 << (ProcessorIndex % 8));
    247 
    248   if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
    249     return TRUE;
    250   } else {
    251     return FALSE;
    252   }
    253 }
    254 
    255 /**
    256   Set the run command flag.
    257 
    258   @param[in] RunningFlag   TRUE means run command flag is set.
    259                            FALSE means run command flag is cleared.
    260 
    261 **/
    262 VOID
    263 SetCpuRunningFlag (
    264   IN BOOLEAN            RunningFlag
    265   )
    266 {
    267   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    268   mDebugMpContext.RunCommandSet = RunningFlag;
    269   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    270 }
    271 
    272 /**
    273   Set the current view point to be debugged.
    274 
    275   @param[in] ProcessorIndex   Processor index value.
    276 
    277 **/
    278 VOID
    279 SetDebugViewPoint (
    280   IN UINT32             ProcessorIndex
    281   )
    282 {
    283   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    284   mDebugMpContext.ViewPointIndex = ProcessorIndex;
    285   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    286 }
    287 
    288 /**
    289   Set the IPI send by BPS/AP flag.
    290 
    291   @param[in] IpiSentByApFlag   TRUE means this IPI is sent by AP.
    292                                FALSE means this IPI is sent by BSP.
    293 
    294 **/
    295 VOID
    296 SetIpiSentByApFlag (
    297   IN BOOLEAN            IpiSentByApFlag
    298   )
    299 {
    300   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    301   mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
    302   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    303 }
    304 
    305 /**
    306   Check the next pending breaking CPU.
    307 
    308   @retval others      There is at least one processor broken, the minimum
    309                       index number of Processor returned.
    310   @retval -1          No any processor broken.
    311 
    312 **/
    313 UINT32
    314 FindNextPendingBreakCpu (
    315   VOID
    316   )
    317 {
    318   UINT32               Index;
    319 
    320   for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
    321     if (mDebugMpContext.CpuBreakMask[Index] != 0) {
    322       return  (UINT32) LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
    323     }
    324   }
    325   return (UINT32)-1;
    326 }
    327 
    328 /**
    329   Check if all processors are in running status.
    330 
    331   @retval TRUE        All processors run.
    332   @retval FALSE       At least one processor does not run.
    333 
    334 **/
    335 BOOLEAN
    336 IsAllCpuRunning (
    337   VOID
    338   )
    339 {
    340   UINTN              Index;
    341 
    342   for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
    343     if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
    344       return FALSE;
    345     }
    346   }
    347   return TRUE;
    348 }
    349 
    350 /**
    351   Check if the current processor is the first breaking processor.
    352 
    353   If yes, halt other processors.
    354 
    355   @param[in] ProcessorIndex   Processor index value.
    356 
    357   @return TRUE       This processor is the first breaking processor.
    358   @return FALSE      This processor is not the first breaking processor.
    359 
    360 **/
    361 BOOLEAN
    362 IsFirstBreakProcessor (
    363   IN UINT32              ProcessorIndex
    364   )
    365 {
    366   if (MultiProcessorDebugSupport()) {
    367     if (mDebugMpContext.BreakAtCpuIndex != (UINT32) -1) {
    368       //
    369       // The current processor is not the first breaking one.
    370       //
    371       SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
    372       return FALSE;
    373     } else {
    374       //
    375       // If no any processor breaks, try to halt other processors
    376       //
    377       HaltOtherProcessors (ProcessorIndex);
    378       return TRUE;
    379     }
    380   }
    381   return TRUE;
    382 }
    383 
    384