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
AcquireMpSpinLock(IN OUT SPIN_LOCK * MpSpinLock)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
ReleaseMpSpinLock(IN OUT SPIN_LOCK * MpSpinLock)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
HaltOtherProcessors(IN UINT32 CurrentProcessorIndex)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
GetProcessorIndex(VOID)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
IsBsp(IN UINT32 ProcessorIndex)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
SetCpuStopFlagByIndex(IN UINT32 ProcessorIndex,IN BOOLEAN StopFlag)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
SetCpuBreakFlagByIndex(IN UINT32 ProcessorIndex,IN BOOLEAN BreakFlag)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
IsCpuStopped(IN UINT32 ProcessorIndex)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
SetCpuRunningFlag(IN BOOLEAN RunningFlag)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
SetDebugViewPoint(IN UINT32 ProcessorIndex)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
SetIpiSentByApFlag(IN BOOLEAN IpiSentByApFlag)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
FindNextPendingBreakCpu(VOID)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
IsAllCpuRunning(VOID)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
IsFirstBreakProcessor(IN UINT32 ProcessorIndex)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