]>
Commit | Line | Data |
---|---|---|
18b144ea | 1 | /** @file\r |
2 | Multi-Processor support functions implementation.\r | |
3 | \r | |
a2acb04c | 4 | Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r |
85f7e110 | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
18b144ea | 6 | \r |
7 | **/\r | |
8 | \r | |
9 | #include "DebugAgent.h"\r | |
10 | \r | |
c1e126b1 | 11 | GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = { 0, 0, 0, { 0 }, { 0 }, 0, 0, 0, 0, FALSE, FALSE };\r |
18b144ea | 12 | \r |
c1e126b1 | 13 | GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile mDebugCpuData = { 0 };\r |
18b144ea | 14 | \r |
15 | /**\r | |
b422b62c | 16 | Acquire a spin lock when Multi-processor supported.\r |
18b144ea | 17 | \r |
18 | It will block in the function if cannot get the access control.\r | |
b422b62c | 19 | If Multi-processor is not supported, return directly.\r |
20 | \r | |
21 | @param[in, out] MpSpinLock A pointer to the spin lock.\r | |
18b144ea | 22 | \r |
23 | **/\r | |
24 | VOID\r | |
b422b62c | 25 | AcquireMpSpinLock (\r |
c1e126b1 | 26 | IN OUT SPIN_LOCK *MpSpinLock\r |
18b144ea | 27 | )\r |
28 | {\r | |
c1e126b1 | 29 | if (!MultiProcessorDebugSupport ()) {\r |
18b144ea | 30 | return;\r |
31 | }\r | |
32 | \r | |
33 | while (TRUE) {\r | |
b422b62c | 34 | if (AcquireSpinLockOrFail (MpSpinLock)) {\r |
18b144ea | 35 | break;\r |
36 | }\r | |
c1e126b1 | 37 | \r |
18b144ea | 38 | CpuPause ();\r |
39 | continue;\r | |
40 | }\r | |
41 | }\r | |
42 | \r | |
43 | /**\r | |
b422b62c | 44 | Release a spin lock when Multi-processor supported.\r |
18b144ea | 45 | \r |
b422b62c | 46 | @param[in, out] MpSpinLock A pointer to the spin lock.\r |
18b144ea | 47 | \r |
48 | **/\r | |
49 | VOID\r | |
b422b62c | 50 | ReleaseMpSpinLock (\r |
c1e126b1 | 51 | IN OUT SPIN_LOCK *MpSpinLock\r |
18b144ea | 52 | )\r |
53 | {\r | |
c1e126b1 | 54 | if (!MultiProcessorDebugSupport ()) {\r |
b422b62c | 55 | return;\r |
18b144ea | 56 | }\r |
18b144ea | 57 | \r |
b422b62c | 58 | ReleaseSpinLock (MpSpinLock);\r |
18b144ea | 59 | }\r |
60 | \r | |
61 | /**\r | |
62 | Break the other processor by send IPI.\r | |
63 | \r | |
64 | @param[in] CurrentProcessorIndex Current processor index value.\r | |
65 | \r | |
66 | **/\r | |
67 | VOID\r | |
68 | HaltOtherProcessors (\r | |
c1e126b1 | 69 | IN UINT32 CurrentProcessorIndex\r |
18b144ea | 70 | )\r |
71 | {\r | |
93c0bdec | 72 | DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);\r |
a2acb04c | 73 | if (!DebugAgentIsBsp (CurrentProcessorIndex)) {\r |
c1e126b1 | 74 | SetIpiSentByApFlag (TRUE);\r |
18b144ea | 75 | }\r |
76 | \r | |
77 | mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;\r | |
78 | \r | |
28c6c878 | 79 | //\r |
80 | // Set the debug viewpoint to the current breaking CPU.\r | |
81 | //\r | |
82 | SetDebugViewPoint (CurrentProcessorIndex);\r | |
83 | \r | |
18b144ea | 84 | //\r |
85 | // Send fixed IPI to other processors.\r | |
86 | //\r | |
87 | SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);\r | |
18b144ea | 88 | }\r |
89 | \r | |
90 | /**\r | |
91 | Get the current processor's index.\r | |
92 | \r | |
93 | @return Processor index value.\r | |
94 | \r | |
95 | **/\r | |
96 | UINT32\r | |
97 | GetProcessorIndex (\r | |
98 | VOID\r | |
99 | )\r | |
100 | {\r | |
c1e126b1 MK |
101 | UINT32 Index;\r |
102 | UINT16 LocalApicID;\r | |
18b144ea | 103 | \r |
c1e126b1 | 104 | LocalApicID = (UINT16)GetApicId ();\r |
18b144ea | 105 | \r |
b422b62c | 106 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 107 | \r |
c1e126b1 | 108 | for (Index = 0; Index < mDebugCpuData.CpuCount; Index++) {\r |
18b144ea | 109 | if (mDebugCpuData.ApicID[Index] == LocalApicID) {\r |
110 | break;\r | |
111 | }\r | |
112 | }\r | |
113 | \r | |
114 | if (Index == mDebugCpuData.CpuCount) {\r | |
115 | mDebugCpuData.ApicID[Index] = LocalApicID;\r | |
c1e126b1 | 116 | mDebugCpuData.CpuCount++;\r |
18b144ea | 117 | }\r |
118 | \r | |
b422b62c | 119 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 120 | \r |
121 | return Index;\r | |
122 | }\r | |
123 | \r | |
124 | /**\r | |
125 | Check if the specified processor is BSP or not.\r | |
126 | \r | |
127 | @param[in] ProcessorIndex Processor index value.\r | |
128 | \r | |
129 | @retval TRUE It is BSP.\r | |
130 | @retval FALSE It isn't BSP.\r | |
131 | \r | |
132 | **/\r | |
133 | BOOLEAN\r | |
a2acb04c | 134 | DebugAgentIsBsp (\r |
d5203c10 | 135 | IN UINT32 ProcessorIndex\r |
18b144ea | 136 | )\r |
137 | {\r | |
a742e186 | 138 | MSR_IA32_APIC_BASE_REGISTER MsrApicBase;\r |
77695f4d | 139 | \r |
d5203c10 MK |
140 | //\r |
141 | // If there are less than 2 CPUs detected, then the currently executing CPU\r | |
77695f4d | 142 | // must be the BSP. This avoids an access to an MSR that may not be supported\r |
d5203c10 MK |
143 | // on single core CPUs.\r |
144 | //\r | |
145 | if (mDebugCpuData.CpuCount < 2) {\r | |
146 | return TRUE;\r | |
147 | }\r | |
148 | \r | |
a742e186 JF |
149 | MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r |
150 | if (MsrApicBase.Bits.BSP == 1) {\r | |
18b144ea | 151 | if (mDebugMpContext.BspIndex != ProcessorIndex) {\r |
b422b62c | 152 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 153 | mDebugMpContext.BspIndex = ProcessorIndex;\r |
b422b62c | 154 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 155 | }\r |
c1e126b1 | 156 | \r |
18b144ea | 157 | return TRUE;\r |
158 | } else {\r | |
159 | return FALSE;\r | |
160 | }\r | |
161 | }\r | |
162 | \r | |
163 | /**\r | |
164 | Set processor stop flag bitmask in MP context.\r | |
165 | \r | |
166 | @param[in] ProcessorIndex Processor index value.\r | |
167 | @param[in] StopFlag TRUE means set stop flag.\r | |
168 | FALSE means clean break flag.\r | |
169 | \r | |
170 | **/\r | |
171 | VOID\r | |
172 | SetCpuStopFlagByIndex (\r | |
c1e126b1 MK |
173 | IN UINT32 ProcessorIndex,\r |
174 | IN BOOLEAN StopFlag\r | |
18b144ea | 175 | )\r |
176 | {\r | |
c1e126b1 MK |
177 | UINT8 Value;\r |
178 | UINTN Index;\r | |
18b144ea | 179 | \r |
b422b62c | 180 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 181 | \r |
182 | Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];\r | |
183 | Index = ProcessorIndex % 8;\r | |
184 | if (StopFlag) {\r | |
185 | Value = BitFieldWrite8 (Value, Index, Index, 1);\r | |
186 | } else {\r | |
187 | Value = BitFieldWrite8 (Value, Index, Index, 0);\r | |
188 | }\r | |
c1e126b1 | 189 | \r |
18b144ea | 190 | mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;\r |
191 | \r | |
b422b62c | 192 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 193 | }\r |
194 | \r | |
195 | /**\r | |
196 | Set processor break flag bitmask in MP context.\r | |
197 | \r | |
198 | @param[in] ProcessorIndex Processor index value.\r | |
199 | @param[in] BreakFlag TRUE means set break flag.\r | |
200 | FALSE means clean break flag.\r | |
201 | \r | |
202 | **/\r | |
203 | VOID\r | |
204 | SetCpuBreakFlagByIndex (\r | |
c1e126b1 MK |
205 | IN UINT32 ProcessorIndex,\r |
206 | IN BOOLEAN BreakFlag\r | |
18b144ea | 207 | )\r |
208 | {\r | |
c1e126b1 MK |
209 | UINT8 Value;\r |
210 | UINTN Index;\r | |
18b144ea | 211 | \r |
b422b62c | 212 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 213 | \r |
214 | Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];\r | |
215 | Index = ProcessorIndex % 8;\r | |
216 | if (BreakFlag) {\r | |
217 | Value = BitFieldWrite8 (Value, Index, Index, 1);\r | |
218 | } else {\r | |
219 | Value = BitFieldWrite8 (Value, Index, Index, 0);\r | |
220 | }\r | |
c1e126b1 | 221 | \r |
18b144ea | 222 | mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;\r |
223 | \r | |
b422b62c | 224 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 225 | }\r |
226 | \r | |
227 | /**\r | |
228 | Check if processor is stopped already.\r | |
229 | \r | |
230 | @param[in] ProcessorIndex Processor index value.\r | |
231 | \r | |
232 | @retval TRUE Processor is stopped already.\r | |
233 | @retval TRUE Processor isn't stopped.\r | |
234 | \r | |
235 | **/\r | |
236 | BOOLEAN\r | |
237 | IsCpuStopped (\r | |
c1e126b1 | 238 | IN UINT32 ProcessorIndex\r |
18b144ea | 239 | )\r |
240 | {\r | |
c1e126b1 | 241 | UINT8 CpuMask;\r |
18b144ea | 242 | \r |
c1e126b1 | 243 | CpuMask = (UINT8)(1 << (ProcessorIndex % 8));\r |
18b144ea | 244 | \r |
245 | if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {\r | |
246 | return TRUE;\r | |
247 | } else {\r | |
248 | return FALSE;\r | |
249 | }\r | |
250 | }\r | |
251 | \r | |
252 | /**\r | |
253 | Set the run command flag.\r | |
254 | \r | |
255 | @param[in] RunningFlag TRUE means run command flag is set.\r | |
256 | FALSE means run command flag is cleared.\r | |
257 | \r | |
258 | **/\r | |
259 | VOID\r | |
260 | SetCpuRunningFlag (\r | |
c1e126b1 | 261 | IN BOOLEAN RunningFlag\r |
18b144ea | 262 | )\r |
263 | {\r | |
b422b62c | 264 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 265 | mDebugMpContext.RunCommandSet = RunningFlag;\r |
b422b62c | 266 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 267 | }\r |
268 | \r | |
269 | /**\r | |
270 | Set the current view point to be debugged.\r | |
271 | \r | |
272 | @param[in] ProcessorIndex Processor index value.\r | |
273 | \r | |
274 | **/\r | |
275 | VOID\r | |
276 | SetDebugViewPoint (\r | |
c1e126b1 | 277 | IN UINT32 ProcessorIndex\r |
18b144ea | 278 | )\r |
279 | {\r | |
b422b62c | 280 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 281 | mDebugMpContext.ViewPointIndex = ProcessorIndex;\r |
b422b62c | 282 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 283 | }\r |
284 | \r | |
285 | /**\r | |
93c0bdec | 286 | Set the IPI send by BPS/AP flag.\r |
18b144ea | 287 | \r |
288 | @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.\r | |
289 | FALSE means this IPI is sent by BSP.\r | |
290 | \r | |
291 | **/\r | |
292 | VOID\r | |
293 | SetIpiSentByApFlag (\r | |
c1e126b1 | 294 | IN BOOLEAN IpiSentByApFlag\r |
18b144ea | 295 | )\r |
296 | {\r | |
b422b62c | 297 | AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 298 | mDebugMpContext.IpiSentByAp = IpiSentByApFlag;\r |
b422b62c | 299 | ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);\r |
18b144ea | 300 | }\r |
301 | \r | |
302 | /**\r | |
93c0bdec | 303 | Check the next pending breaking CPU.\r |
18b144ea | 304 | \r |
305 | @retval others There is at least one processor broken, the minimum\r | |
306 | index number of Processor returned.\r | |
307 | @retval -1 No any processor broken.\r | |
308 | \r | |
309 | **/\r | |
310 | UINT32\r | |
93c0bdec | 311 | FindNextPendingBreakCpu (\r |
18b144ea | 312 | VOID\r |
313 | )\r | |
314 | {\r | |
c1e126b1 | 315 | UINT32 Index;\r |
4fe43eb3 | 316 | \r |
c1e126b1 | 317 | for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) {\r |
18b144ea | 318 | if (mDebugMpContext.CpuBreakMask[Index] != 0) {\r |
c1e126b1 | 319 | return (UINT32)LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;\r |
18b144ea | 320 | }\r |
321 | }\r | |
c1e126b1 | 322 | \r |
18b144ea | 323 | return (UINT32)-1;\r |
324 | }\r | |
4fe43eb3 | 325 | \r |
18b144ea | 326 | /**\r |
327 | Check if all processors are in running status.\r | |
328 | \r | |
329 | @retval TRUE All processors run.\r | |
330 | @retval FALSE At least one processor does not run.\r | |
331 | \r | |
332 | **/\r | |
333 | BOOLEAN\r | |
334 | IsAllCpuRunning (\r | |
335 | VOID\r | |
336 | )\r | |
337 | {\r | |
c1e126b1 | 338 | UINTN Index;\r |
4fe43eb3 | 339 | \r |
c1e126b1 | 340 | for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index++) {\r |
18b144ea | 341 | if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {\r |
342 | return FALSE;\r | |
343 | }\r | |
344 | }\r | |
c1e126b1 | 345 | \r |
18b144ea | 346 | return TRUE;\r |
347 | }\r | |
348 | \r | |
93c0bdec | 349 | /**\r |
350 | Check if the current processor is the first breaking processor.\r | |
351 | \r | |
4fe43eb3 JF |
352 | If yes, halt other processors.\r |
353 | \r | |
93c0bdec | 354 | @param[in] ProcessorIndex Processor index value.\r |
4fe43eb3 | 355 | \r |
93c0bdec | 356 | @return TRUE This processor is the first breaking processor.\r |
357 | @return FALSE This processor is not the first breaking processor.\r | |
4fe43eb3 | 358 | \r |
93c0bdec | 359 | **/\r |
360 | BOOLEAN\r | |
361 | IsFirstBreakProcessor (\r | |
c1e126b1 | 362 | IN UINT32 ProcessorIndex\r |
93c0bdec | 363 | )\r |
364 | {\r | |
c1e126b1 MK |
365 | if (MultiProcessorDebugSupport ()) {\r |
366 | if (mDebugMpContext.BreakAtCpuIndex != (UINT32)-1) {\r | |
93c0bdec | 367 | //\r |
368 | // The current processor is not the first breaking one.\r | |
369 | //\r | |
370 | SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);\r | |
371 | return FALSE;\r | |
372 | } else {\r | |
373 | //\r | |
374 | // If no any processor breaks, try to halt other processors\r | |
375 | //\r | |
376 | HaltOtherProcessors (ProcessorIndex);\r | |
377 | return TRUE;\r | |
378 | }\r | |
379 | }\r | |
c1e126b1 | 380 | \r |
93c0bdec | 381 | return TRUE;\r |
4fe43eb3 | 382 | }\r |