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