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
17GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile  mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE};
18
19GLOBAL_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**/
30VOID
31AcquireMpSpinLock (
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**/
54VOID
55ReleaseMpSpinLock (
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**/
72VOID
73HaltOtherProcessors (
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**/
102UINT32
103GetProcessorIndex (
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**/
139BOOLEAN
140IsBsp (
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**/
173VOID
174SetCpuStopFlagByIndex (
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**/
204VOID
205SetCpuBreakFlagByIndex (
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**/
236BOOLEAN
237IsCpuStopped (
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**/
259VOID
260SetCpuRunningFlag (
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**/
275VOID
276SetDebugViewPoint (
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**/
292VOID
293SetIpiSentByApFlag (
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**/
310UINT32
311FindNextPendingBreakCpu (
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**/
332BOOLEAN
333IsAllCpuRunning (
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**/
358BOOLEAN
359IsFirstBreakProcessor (
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