Home | History | Annotate | Download | only in DebugAgentCommon
      1 /** @file
      2   Multi-Processor support functions implementation.
      3 
      4   Copyright (c) 2010 - 2015, 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   //
    145   // If there are less than 2 CPUs detected, then the currently executing CPU
    146   // must be the BSP.  This avoids an access to an MSR that may not be supported
    147   // on single core CPUs.
    148   //
    149   if (mDebugCpuData.CpuCount < 2) {
    150     return TRUE;
    151   }
    152 
    153   if (AsmMsrBitFieldRead64 (MSR_IA32_APIC_BASE_ADDRESS, 8, 8) == 1) {
    154     if (mDebugMpContext.BspIndex != ProcessorIndex) {
    155       AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    156       mDebugMpContext.BspIndex = ProcessorIndex;
    157       ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    158     }
    159     return TRUE;
    160   } else {
    161     return FALSE;
    162   }
    163 }
    164 
    165 /**
    166   Set processor stop flag bitmask in MP context.
    167 
    168   @param[in] ProcessorIndex Processor index value.
    169   @param[in] StopFlag       TRUE means set stop flag.
    170                             FALSE means clean break flag.
    171 
    172 **/
    173 VOID
    174 SetCpuStopFlagByIndex (
    175   IN UINT32             ProcessorIndex,
    176   IN BOOLEAN            StopFlag
    177   )
    178 {
    179   UINT8                 Value;
    180   UINTN                 Index;
    181 
    182   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    183 
    184   Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
    185   Index = ProcessorIndex % 8;
    186   if (StopFlag) {
    187     Value = BitFieldWrite8 (Value, Index, Index, 1);
    188   } else {
    189     Value = BitFieldWrite8 (Value, Index, Index, 0);
    190   }
    191   mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
    192 
    193   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    194 }
    195 
    196 /**
    197   Set processor break flag bitmask in MP context.
    198 
    199   @param[in] ProcessorIndex Processor index value.
    200   @param[in] BreakFlag      TRUE means set break flag.
    201                             FALSE means clean break flag.
    202 
    203 **/
    204 VOID
    205 SetCpuBreakFlagByIndex (
    206   IN UINT32             ProcessorIndex,
    207   IN BOOLEAN            BreakFlag
    208   )
    209 {
    210   UINT8                 Value;
    211   UINTN                 Index;
    212 
    213   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    214 
    215   Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
    216   Index = ProcessorIndex % 8;
    217   if (BreakFlag) {
    218     Value = BitFieldWrite8 (Value, Index, Index, 1);
    219   } else {
    220     Value = BitFieldWrite8 (Value, Index, Index, 0);
    221   }
    222   mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
    223 
    224   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    225 }
    226 
    227 /**
    228   Check if processor is stopped already.
    229 
    230   @param[in] ProcessorIndex   Processor index value.
    231 
    232   @retval TRUE        Processor is stopped already.
    233   @retval TRUE        Processor isn't stopped.
    234 
    235 **/
    236 BOOLEAN
    237 IsCpuStopped (
    238   IN UINT32              ProcessorIndex
    239   )
    240 {
    241   UINT8                 CpuMask;
    242 
    243   CpuMask = (UINT8) (1 << (ProcessorIndex % 8));
    244 
    245   if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
    246     return TRUE;
    247   } else {
    248     return FALSE;
    249   }
    250 }
    251 
    252 /**
    253   Set the run command flag.
    254 
    255   @param[in] RunningFlag   TRUE means run command flag is set.
    256                            FALSE means run command flag is cleared.
    257 
    258 **/
    259 VOID
    260 SetCpuRunningFlag (
    261   IN BOOLEAN            RunningFlag
    262   )
    263 {
    264   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    265   mDebugMpContext.RunCommandSet = RunningFlag;
    266   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    267 }
    268 
    269 /**
    270   Set the current view point to be debugged.
    271 
    272   @param[in] ProcessorIndex   Processor index value.
    273 
    274 **/
    275 VOID
    276 SetDebugViewPoint (
    277   IN UINT32             ProcessorIndex
    278   )
    279 {
    280   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    281   mDebugMpContext.ViewPointIndex = ProcessorIndex;
    282   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    283 }
    284 
    285 /**
    286   Set the IPI send by BPS/AP flag.
    287 
    288   @param[in] IpiSentByApFlag   TRUE means this IPI is sent by AP.
    289                                FALSE means this IPI is sent by BSP.
    290 
    291 **/
    292 VOID
    293 SetIpiSentByApFlag (
    294   IN BOOLEAN            IpiSentByApFlag
    295   )
    296 {
    297   AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    298   mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
    299   ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
    300 }
    301 
    302 /**
    303   Check the next pending breaking CPU.
    304 
    305   @retval others      There is at least one processor broken, the minimum
    306                       index number of Processor returned.
    307   @retval -1          No any processor broken.
    308 
    309 **/
    310 UINT32
    311 FindNextPendingBreakCpu (
    312   VOID
    313   )
    314 {
    315   UINT32               Index;
    316 
    317   for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
    318     if (mDebugMpContext.CpuBreakMask[Index] != 0) {
    319       return  (UINT32) LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
    320     }
    321   }
    322   return (UINT32)-1;
    323 }
    324 
    325 /**
    326   Check if all processors are in running status.
    327 
    328   @retval TRUE        All processors run.
    329   @retval FALSE       At least one processor does not run.
    330 
    331 **/
    332 BOOLEAN
    333 IsAllCpuRunning (
    334   VOID
    335   )
    336 {
    337   UINTN              Index;
    338 
    339   for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
    340     if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
    341       return FALSE;
    342     }
    343   }
    344   return TRUE;
    345 }
    346 
    347 /**
    348   Check if the current processor is the first breaking processor.
    349 
    350   If yes, halt other processors.
    351 
    352   @param[in] ProcessorIndex   Processor index value.
    353 
    354   @return TRUE       This processor is the first breaking processor.
    355   @return FALSE      This processor is not the first breaking processor.
    356 
    357 **/
    358 BOOLEAN
    359 IsFirstBreakProcessor (
    360   IN UINT32              ProcessorIndex
    361   )
    362 {
    363   if (MultiProcessorDebugSupport()) {
    364     if (mDebugMpContext.BreakAtCpuIndex != (UINT32) -1) {
    365       //
    366       // The current processor is not the first breaking one.
    367       //
    368       SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
    369       return FALSE;
    370     } else {
    371       //
    372       // If no any processor breaks, try to halt other processors
    373       //
    374       HaltOtherProcessors (ProcessorIndex);
    375       return TRUE;
    376     }
    377   }
    378   return TRUE;
    379 }
    380 
    381