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