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