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 17GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE}; 18 19GLOBAL_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**/ 30VOID 31AcquireMpSpinLock ( 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**/ 54VOID 55ReleaseMpSpinLock ( 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**/ 72VOID 73HaltOtherProcessors ( 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**/ 102UINT32 103GetProcessorIndex ( 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**/ 139BOOLEAN 140IsBsp ( 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**/ 173VOID 174SetCpuStopFlagByIndex ( 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**/ 204VOID 205SetCpuBreakFlagByIndex ( 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**/ 236BOOLEAN 237IsCpuStopped ( 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**/ 259VOID 260SetCpuRunningFlag ( 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**/ 275VOID 276SetDebugViewPoint ( 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**/ 292VOID 293SetIpiSentByApFlag ( 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**/ 310UINT32 311FindNextPendingBreakCpu ( 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**/ 332BOOLEAN 333IsAllCpuRunning ( 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**/ 358BOOLEAN 359IsFirstBreakProcessor ( 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