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
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 //
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
SetCpuStopFlagByIndex(IN UINT32 ProcessorIndex,IN BOOLEAN StopFlag)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
SetCpuBreakFlagByIndex(IN UINT32 ProcessorIndex,IN BOOLEAN BreakFlag)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
IsCpuStopped(IN UINT32 ProcessorIndex)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
SetCpuRunningFlag(IN BOOLEAN RunningFlag)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
SetDebugViewPoint(IN UINT32 ProcessorIndex)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
SetIpiSentByApFlag(IN BOOLEAN IpiSentByApFlag)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
FindNextPendingBreakCpu(VOID)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
IsAllCpuRunning(VOID)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
IsFirstBreakProcessor(IN UINT32 ProcessorIndex)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