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