]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
StandaloneMmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / DxeMpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 MP initialize support functions for DXE phase.\r
3\r
7367cc6c 4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
3e8ad6bd
JF
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "MpLib.h"\r
96378861
JF
16\r
17#include <Library/UefiLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
43c9fdcc 19#include <Library/DebugAgentLib.h>\r
15720a6c 20#include <Library/DxeServicesTableLib.h>\r
96378861 21\r
b6e45716
JF
22#include <Protocol/Timer.h>\r
23\r
96378861 24#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))\r
bf2786dc 25#define AP_SAFE_STACK_SIZE 128\r
96378861 26\r
93ca4c0f 27CPU_MP_DATA *mCpuMpData = NULL;\r
96378861 28EFI_EVENT mCheckAllApsEvent = NULL;\r
4d3314f6 29EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
8677a56a 30EFI_EVENT mLegacyBootEvent = NULL;\r
96378861 31volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
5183fb37 32VOID *mReservedApLoopFunc = NULL;\r
bf2786dc 33UINTN mReservedTopOfApStack;\r
9f91cb01 34volatile UINT32 mNumberToFinish = 0;\r
93ca4c0f 35\r
43c9fdcc
JF
36/**\r
37 Enable Debug Agent to support source debugging on AP function.\r
38\r
39**/\r
40VOID\r
41EnableDebugAgent (\r
42 VOID\r
43 )\r
44{\r
45 //\r
46 // Initialize Debug Agent to support source level debug in DXE phase\r
47 //\r
48 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);\r
49}\r
50\r
93ca4c0f
JF
51/**\r
52 Get the pointer to CPU MP Data structure.\r
53\r
54 @return The pointer to CPU MP Data structure.\r
55**/\r
56CPU_MP_DATA *\r
57GetCpuMpData (\r
58 VOID\r
59 )\r
60{\r
61 ASSERT (mCpuMpData != NULL);\r
62 return mCpuMpData;\r
63}\r
64\r
65/**\r
66 Save the pointer to CPU MP Data structure.\r
67\r
68 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.\r
69**/\r
70VOID\r
71SaveCpuMpData (\r
72 IN CPU_MP_DATA *CpuMpData\r
73 )\r
74{\r
75 mCpuMpData = CpuMpData;\r
76}\r
77\r
96378861 78/**\r
e4ff6349 79 Get available system memory below 0x88000 by specified size.\r
ed66e0e3 80\r
a6b3d753 81 @param[in] WakeupBufferSize Wakeup buffer size required\r
3ed4e502 82\r
a6b3d753
SZ
83 @retval other Return wakeup buffer address below 1MB.\r
84 @retval -1 Cannot find free memory below 1MB.\r
ed66e0e3 85**/\r
a6b3d753
SZ
86UINTN\r
87GetWakeupBuffer (\r
88 IN UINTN WakeupBufferSize\r
ed66e0e3
JF
89 )\r
90{\r
a6b3d753
SZ
91 EFI_STATUS Status;\r
92 EFI_PHYSICAL_ADDRESS StartAddress;\r
93\r
e4ff6349
ED
94 //\r
95 // Try to allocate buffer below 1M for waking vector.\r
96 // LegacyBios driver only reports warning when page allocation in range\r
97 // [0x60000, 0x88000) fails.\r
98 // This library is consumed by CpuDxe driver to produce CPU Arch protocol.\r
99 // LagacyBios driver depends on CPU Arch protocol which guarantees below\r
100 // allocation runs earlier than LegacyBios driver.\r
101 //\r
102 StartAddress = 0x88000;\r
a6b3d753
SZ
103 Status = gBS->AllocatePages (\r
104 AllocateMaxAddress,\r
105 EfiBootServicesData,\r
106 EFI_SIZE_TO_PAGES (WakeupBufferSize),\r
107 &StartAddress\r
108 );\r
109 ASSERT_EFI_ERROR (Status);\r
e4ff6349 110 if (EFI_ERROR (Status)) {\r
a6b3d753 111 StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\r
3ed4e502 112 }\r
e4ff6349
ED
113\r
114 DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
115 (UINTN) StartAddress, WakeupBufferSize));\r
116\r
a6b3d753 117 return (UINTN) StartAddress;\r
ed66e0e3
JF
118}\r
119\r
f32bfe6d
JW
120/**\r
121 Get available EfiBootServicesCode memory below 4GB by specified size.\r
122\r
123 This buffer is required to safely transfer AP from real address mode to\r
124 protected mode or long mode, due to the fact that the buffer returned by\r
125 GetWakeupBuffer() may be marked as non-executable.\r
126\r
127 @param[in] BufferSize Wakeup transition buffer size.\r
128\r
129 @retval other Return wakeup transition buffer address below 4GB.\r
130 @retval 0 Cannot find free memory below 4GB.\r
131**/\r
132UINTN\r
133GetModeTransitionBuffer (\r
134 IN UINTN BufferSize\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 EFI_PHYSICAL_ADDRESS StartAddress;\r
139\r
140 StartAddress = BASE_4GB - 1;\r
141 Status = gBS->AllocatePages (\r
142 AllocateMaxAddress,\r
143 EfiBootServicesCode,\r
144 EFI_SIZE_TO_PAGES (BufferSize),\r
145 &StartAddress\r
146 );\r
147 if (EFI_ERROR (Status)) {\r
148 StartAddress = 0;\r
149 }\r
150\r
151 return (UINTN)StartAddress;\r
152}\r
153\r
96378861
JF
154/**\r
155 Checks APs status and updates APs status if needed.\r
156\r
157**/\r
158VOID\r
159CheckAndUpdateApsStatus (\r
160 VOID\r
161 )\r
162{\r
08085f08
JF
163 UINTN ProcessorNumber;\r
164 EFI_STATUS Status;\r
165 CPU_MP_DATA *CpuMpData;\r
166\r
167 CpuMpData = GetCpuMpData ();\r
168\r
169 //\r
170 // First, check whether pending StartupAllAPs() exists.\r
171 //\r
172 if (CpuMpData->WaitEvent != NULL) {\r
173\r
174 Status = CheckAllAPs ();\r
175 //\r
176 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.\r
177 //\r
178 if (Status != EFI_NOT_READY) {\r
179 Status = gBS->SignalEvent (CpuMpData->WaitEvent);\r
180 CpuMpData->WaitEvent = NULL;\r
181 }\r
182 }\r
183\r
184 //\r
185 // Second, check whether pending StartupThisAPs() callings exist.\r
186 //\r
187 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
188\r
189 if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {\r
190 continue;\r
191 }\r
192\r
193 Status = CheckThisAP (ProcessorNumber);\r
194\r
195 if (Status != EFI_NOT_READY) {\r
196 gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);\r
197 CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
198 }\r
199 }\r
96378861
JF
200}\r
201\r
202/**\r
203 Checks APs' status periodically.\r
204\r
438f1766 205 This function is triggered by timer periodically to check the\r
96378861
JF
206 state of APs for StartupAllAPs() and StartupThisAP() executed\r
207 in non-blocking mode.\r
208\r
209 @param[in] Event Event triggered.\r
210 @param[in] Context Parameter passed with the event.\r
211\r
212**/\r
213VOID\r
214EFIAPI\r
215CheckApsStatus (\r
216 IN EFI_EVENT Event,\r
217 IN VOID *Context\r
218 )\r
219{\r
220 //\r
221 // If CheckApsStatus() is not stopped, otherwise return immediately.\r
222 //\r
223 if (!mStopCheckAllApsStatus) {\r
224 CheckAndUpdateApsStatus ();\r
225 }\r
226}\r
ed66e0e3 227\r
4d3314f6
JF
228/**\r
229 Get Protected mode code segment from current GDT table.\r
230\r
b31c1ad1 231 @return Protected mode code segment value.\r
4d3314f6
JF
232**/\r
233UINT16\r
234GetProtectedModeCS (\r
235 VOID\r
236 )\r
237{\r
238 IA32_DESCRIPTOR GdtrDesc;\r
239 IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
240 UINTN GdtEntryCount;\r
241 UINT16 Index;\r
242\r
4d3314f6
JF
243 AsmReadGdtr (&GdtrDesc);\r
244 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
245 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
246 for (Index = 0; Index < GdtEntryCount; Index++) {\r
247 if (GdtEntry->Bits.L == 0) {\r
248 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {\r
249 break;\r
250 }\r
251 }\r
252 GdtEntry++;\r
253 }\r
37fba7c2 254 ASSERT (Index != GdtEntryCount);\r
4d3314f6
JF
255 return Index * 8;\r
256}\r
257\r
258/**\r
259 Do sync on APs.\r
260\r
261 @param[in, out] Buffer Pointer to private data buffer.\r
262**/\r
263VOID\r
264EFIAPI\r
265RelocateApLoop (\r
266 IN OUT VOID *Buffer\r
267 )\r
268{\r
269 CPU_MP_DATA *CpuMpData;\r
270 BOOLEAN MwaitSupport;\r
271 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
bf2786dc 272 UINTN ProcessorNumber;\r
4d3314f6 273\r
7367cc6c 274 MpInitLibWhoAmI (&ProcessorNumber);\r
4d3314f6
JF
275 CpuMpData = GetCpuMpData ();\r
276 MwaitSupport = IsMwaitSupport ();\r
081f6416 277 AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
bf2786dc
JF
278 AsmRelocateApLoopFunc (\r
279 MwaitSupport,\r
280 CpuMpData->ApTargetCState,\r
281 CpuMpData->PmCodeSegment,\r
9f91cb01
JF
282 mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
283 (UINTN) &mNumberToFinish\r
bf2786dc 284 );\r
4d3314f6
JF
285 //\r
286 // It should never reach here\r
287 //\r
288 ASSERT (FALSE);\r
289}\r
290\r
291/**\r
292 Callback function for ExitBootServices.\r
293\r
294 @param[in] Event Event whose notification function is being invoked.\r
295 @param[in] Context The pointer to the notification function's context,\r
296 which is implementation-dependent.\r
297\r
298**/\r
299VOID\r
300EFIAPI\r
86af2eb8 301MpInitChangeApLoopCallback (\r
4d3314f6
JF
302 IN EFI_EVENT Event,\r
303 IN VOID *Context\r
304 )\r
305{\r
306 CPU_MP_DATA *CpuMpData;\r
5183fb37 307\r
4d3314f6
JF
308 CpuMpData = GetCpuMpData ();\r
309 CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
310 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
9f91cb01 311 mNumberToFinish = CpuMpData->CpuCount - 1;\r
cf4e79e4 312 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
9f91cb01
JF
313 while (mNumberToFinish > 0) {\r
314 CpuPause ();\r
315 }\r
86af2eb8 316 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
4d3314f6
JF
317}\r
318\r
93ca4c0f
JF
319/**\r
320 Initialize global data for MP support.\r
321\r
322 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
323**/\r
324VOID\r
325InitMpGlobalData (\r
326 IN CPU_MP_DATA *CpuMpData\r
327 )\r
328{\r
15720a6c
JW
329 EFI_STATUS Status;\r
330 EFI_PHYSICAL_ADDRESS Address;\r
331 UINTN ApSafeBufferSize;\r
332 UINTN Index;\r
333 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
334 UINTN StackBase;\r
52315261 335 CPU_INFO_IN_HOB *CpuInfoInHob;\r
96378861 336\r
93ca4c0f
JF
337 SaveCpuMpData (CpuMpData);\r
338\r
14e8137c
JF
339 if (CpuMpData->CpuCount == 1) {\r
340 //\r
341 // If only BSP exists, return\r
342 //\r
343 return;\r
344 }\r
345\r
15720a6c
JW
346 if (PcdGetBool (PcdCpuStackGuard)) {\r
347 //\r
348 // One extra page at the bottom of the stack is needed for Guard page.\r
349 //\r
350 if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {\r
351 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
352 ASSERT (FALSE);\r
353 }\r
354\r
52315261
JW
355 //\r
356 // DXE will reuse stack allocated for APs at PEI phase if it's available.\r
357 // Let's check it here.\r
358 //\r
359 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of\r
360 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be\r
361 // set here.\r
362 //\r
363 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
15720a6c 364 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
52315261 365 if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) {\r
20737c2f 366 StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
52315261
JW
367 } else {\r
368 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
369 }\r
15720a6c
JW
370\r
371 Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);\r
372 ASSERT_EFI_ERROR (Status);\r
373\r
374 Status = gDS->SetMemorySpaceAttributes (\r
375 StackBase,\r
376 EFI_PAGES_TO_SIZE (1),\r
377 MemDesc.Attributes | EFI_MEMORY_RP\r
378 );\r
379 ASSERT_EFI_ERROR (Status);\r
52315261
JW
380\r
381 DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",\r
382 (UINT64)StackBase, (UINT64)Index));\r
15720a6c
JW
383 }\r
384 }\r
385\r
5183fb37 386 //\r
ffd6b0b1
JF
387 // Avoid APs access invalid buffer data which allocated by BootServices,\r
388 // so we will allocate reserved data for AP loop code. We also need to\r
389 // allocate this buffer below 4GB due to APs may be transferred to 32bit\r
390 // protected mode on long mode DXE.\r
5183fb37
JF
391 // Allocating it in advance since memory services are not available in\r
392 // Exit Boot Services callback function.\r
393 //\r
bc2288f5
JW
394 ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (\r
395 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
396 ));\r
ffd6b0b1
JF
397 Address = BASE_4GB - 1;\r
398 Status = gBS->AllocatePages (\r
399 AllocateMaxAddress,\r
400 EfiReservedMemoryType,\r
bf2786dc 401 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
ffd6b0b1
JF
402 &Address\r
403 );\r
404 ASSERT_EFI_ERROR (Status);\r
bc2288f5 405\r
ffd6b0b1 406 mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
5183fb37 407 ASSERT (mReservedApLoopFunc != NULL);\r
bc2288f5
JW
408\r
409 //\r
410 // Make sure that the buffer memory is executable if NX protection is enabled\r
411 // for EfiReservedMemoryType.\r
7367cc6c 412 //\r
bc2288f5
JW
413 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD\r
414 // service.\r
415 //\r
416 Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);\r
417 if (!EFI_ERROR (Status)) {\r
418 gDS->SetMemorySpaceAttributes (\r
419 Address,\r
420 ApSafeBufferSize,\r
421 MemDesc.Attributes & (~EFI_MEMORY_XP)\r
422 );\r
423 }\r
424\r
425 ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (\r
426 CpuMpData->CpuCount * AP_SAFE_STACK_SIZE\r
427 ));\r
428 Address = BASE_4GB - 1;\r
429 Status = gBS->AllocatePages (\r
430 AllocateMaxAddress,\r
431 EfiReservedMemoryType,\r
432 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
433 &Address\r
434 );\r
435 ASSERT_EFI_ERROR (Status);\r
436\r
437 mReservedTopOfApStack = (UINTN) Address + ApSafeBufferSize;\r
bf2786dc 438 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
ffd6b0b1
JF
439 CopyMem (\r
440 mReservedApLoopFunc,\r
441 CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
442 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
443 );\r
5183fb37 444\r
96378861
JF
445 Status = gBS->CreateEvent (\r
446 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
447 TPL_NOTIFY,\r
448 CheckApsStatus,\r
449 NULL,\r
450 &mCheckAllApsEvent\r
451 );\r
452 ASSERT_EFI_ERROR (Status);\r
453\r
454 //\r
455 // Set timer to check all APs status.\r
456 //\r
457 Status = gBS->SetTimer (\r
458 mCheckAllApsEvent,\r
459 TimerPeriodic,\r
460 AP_CHECK_INTERVAL\r
461 );\r
462 ASSERT_EFI_ERROR (Status);\r
8677a56a 463\r
4d3314f6
JF
464 Status = gBS->CreateEvent (\r
465 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
466 TPL_CALLBACK,\r
86af2eb8 467 MpInitChangeApLoopCallback,\r
4d3314f6
JF
468 NULL,\r
469 &mMpInitExitBootServicesEvent\r
470 );\r
471 ASSERT_EFI_ERROR (Status);\r
8677a56a
JF
472\r
473 Status = gBS->CreateEventEx (\r
474 EVT_NOTIFY_SIGNAL,\r
475 TPL_CALLBACK,\r
476 MpInitChangeApLoopCallback,\r
477 NULL,\r
478 &gEfiEventLegacyBootGuid,\r
479 &mLegacyBootEvent\r
480 );\r
481 ASSERT_EFI_ERROR (Status);\r
93ca4c0f 482}\r
3e8ad6bd
JF
483\r
484/**\r
485 This service executes a caller provided function on all enabled APs.\r
486\r
487 @param[in] Procedure A pointer to the function to be run on\r
488 enabled APs of the system. See type\r
489 EFI_AP_PROCEDURE.\r
490 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
491 the function specified by Procedure one by\r
492 one, in ascending order of processor handle\r
493 number. If FALSE, then all the enabled APs\r
494 execute the function specified by Procedure\r
495 simultaneously.\r
496 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
497 service. If it is NULL, then execute in\r
498 blocking mode. BSP waits until all APs finish\r
499 or TimeoutInMicroSeconds expires. If it's\r
500 not NULL, then execute in non-blocking mode.\r
501 BSP requests the function specified by\r
502 Procedure to be started on all the enabled\r
503 APs, and go on executing immediately. If\r
504 all return from Procedure, or TimeoutInMicroSeconds\r
505 expires, this event is signaled. The BSP\r
506 can use the CheckEvent() or WaitForEvent()\r
507 services to check the state of event. Type\r
508 EFI_EVENT is defined in CreateEvent() in\r
509 the Unified Extensible Firmware Interface\r
510 Specification.\r
367284e7 511 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
512 APs to return from Procedure, either for\r
513 blocking or non-blocking mode. Zero means\r
514 infinity. If the timeout expires before\r
515 all APs return from Procedure, then Procedure\r
516 on the failed APs is terminated. All enabled\r
517 APs are available for next function assigned\r
518 by MpInitLibStartupAllAPs() or\r
519 MPInitLibStartupThisAP().\r
520 If the timeout expires in blocking mode,\r
521 BSP returns EFI_TIMEOUT. If the timeout\r
522 expires in non-blocking mode, WaitEvent\r
523 is signaled with SignalEvent().\r
524 @param[in] ProcedureArgument The parameter passed into Procedure for\r
525 all APs.\r
526 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
527 if all APs finish successfully, then its\r
528 content is set to NULL. If not all APs\r
529 finish before timeout expires, then its\r
530 content is set to address of the buffer\r
531 holding handle numbers of the failed APs.\r
532 The buffer is allocated by MP Initialization\r
533 library, and it's the caller's responsibility to\r
534 free the buffer with FreePool() service.\r
535 In blocking mode, it is ready for consumption\r
536 when the call returns. In non-blocking mode,\r
537 it is ready when WaitEvent is signaled. The\r
538 list of failed CPU is terminated by\r
539 END_OF_CPU_LIST.\r
540\r
541 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
542 the timeout expired.\r
543 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
544 to all enabled APs.\r
545 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
546 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
547 signaled.\r
548 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
549 supported.\r
550 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
551 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
552 @retval EFI_NOT_READY Any enabled APs are busy.\r
553 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
554 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
555 all enabled APs have finished.\r
556 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
557\r
558**/\r
559EFI_STATUS\r
560EFIAPI\r
561MpInitLibStartupAllAPs (\r
562 IN EFI_AP_PROCEDURE Procedure,\r
563 IN BOOLEAN SingleThread,\r
564 IN EFI_EVENT WaitEvent OPTIONAL,\r
565 IN UINTN TimeoutInMicroseconds,\r
566 IN VOID *ProcedureArgument OPTIONAL,\r
567 OUT UINTN **FailedCpuList OPTIONAL\r
568 )\r
569{\r
86efe976
JF
570 EFI_STATUS Status;\r
571\r
572 //\r
573 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
574 //\r
575 mStopCheckAllApsStatus = TRUE;\r
576\r
577 Status = StartupAllAPsWorker (\r
578 Procedure,\r
579 SingleThread,\r
580 WaitEvent,\r
581 TimeoutInMicroseconds,\r
582 ProcedureArgument,\r
583 FailedCpuList\r
584 );\r
585\r
586 //\r
587 // Start checkAllApsStatus\r
588 //\r
589 mStopCheckAllApsStatus = FALSE;\r
590\r
591 return Status;\r
3e8ad6bd
JF
592}\r
593\r
594/**\r
595 This service lets the caller get one enabled AP to execute a caller-provided\r
596 function.\r
597\r
598 @param[in] Procedure A pointer to the function to be run on the\r
599 designated AP of the system. See type\r
600 EFI_AP_PROCEDURE.\r
601 @param[in] ProcessorNumber The handle number of the AP. The range is\r
602 from 0 to the total number of logical\r
603 processors minus 1. The total number of\r
604 logical processors can be retrieved by\r
605 MpInitLibGetNumberOfProcessors().\r
606 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
607 service. If it is NULL, then execute in\r
608 blocking mode. BSP waits until this AP finish\r
609 or TimeoutInMicroSeconds expires. If it's\r
610 not NULL, then execute in non-blocking mode.\r
611 BSP requests the function specified by\r
612 Procedure to be started on this AP,\r
613 and go on executing immediately. If this AP\r
614 return from Procedure or TimeoutInMicroSeconds\r
615 expires, this event is signaled. The BSP\r
616 can use the CheckEvent() or WaitForEvent()\r
617 services to check the state of event. Type\r
618 EFI_EVENT is defined in CreateEvent() in\r
619 the Unified Extensible Firmware Interface\r
620 Specification.\r
367284e7 621 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
622 this AP to finish this Procedure, either for\r
623 blocking or non-blocking mode. Zero means\r
624 infinity. If the timeout expires before\r
625 this AP returns from Procedure, then Procedure\r
626 on the AP is terminated. The\r
627 AP is available for next function assigned\r
628 by MpInitLibStartupAllAPs() or\r
629 MpInitLibStartupThisAP().\r
630 If the timeout expires in blocking mode,\r
631 BSP returns EFI_TIMEOUT. If the timeout\r
632 expires in non-blocking mode, WaitEvent\r
633 is signaled with SignalEvent().\r
634 @param[in] ProcedureArgument The parameter passed into Procedure on the\r
635 specified AP.\r
636 @param[out] Finished If NULL, this parameter is ignored. In\r
637 blocking mode, this parameter is ignored.\r
638 In non-blocking mode, if AP returns from\r
639 Procedure before the timeout expires, its\r
640 content is set to TRUE. Otherwise, the\r
641 value is set to FALSE. The caller can\r
642 determine if the AP returned from Procedure\r
643 by evaluating this value.\r
644\r
645 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
646 the timeout expires.\r
647 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
648 dispatched to specified AP.\r
649 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
650 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
651 signaled.\r
652 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
653 supported.\r
654 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
655 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
656 the specified AP has finished.\r
657 @retval EFI_NOT_READY The specified AP is busy.\r
658 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
659 @retval EFI_NOT_FOUND The processor with the handle specified by\r
660 ProcessorNumber does not exist.\r
661 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
662 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
663\r
664**/\r
665EFI_STATUS\r
666EFIAPI\r
667MpInitLibStartupThisAP (\r
668 IN EFI_AP_PROCEDURE Procedure,\r
669 IN UINTN ProcessorNumber,\r
670 IN EFI_EVENT WaitEvent OPTIONAL,\r
671 IN UINTN TimeoutInMicroseconds,\r
672 IN VOID *ProcedureArgument OPTIONAL,\r
673 OUT BOOLEAN *Finished OPTIONAL\r
674 )\r
675{\r
20ae5774
JF
676 EFI_STATUS Status;\r
677\r
678 //\r
679 // temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
680 //\r
681 mStopCheckAllApsStatus = TRUE;\r
682\r
683 Status = StartupThisAPWorker (\r
684 Procedure,\r
685 ProcessorNumber,\r
686 WaitEvent,\r
687 TimeoutInMicroseconds,\r
688 ProcedureArgument,\r
689 Finished\r
690 );\r
691\r
692 mStopCheckAllApsStatus = FALSE;\r
693\r
694 return Status;\r
3e8ad6bd
JF
695}\r
696\r
697/**\r
698 This service switches the requested AP to be the BSP from that point onward.\r
699 This service changes the BSP for all purposes. This call can only be performed\r
700 by the current BSP.\r
701\r
702 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
703 BSP. The range is from 0 to the total number of\r
704 logical processors minus 1. The total number of\r
705 logical processors can be retrieved by\r
706 MpInitLibGetNumberOfProcessors().\r
707 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
708 enabled AP. Otherwise, it will be disabled.\r
709\r
710 @retval EFI_SUCCESS BSP successfully switched.\r
711 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
712 this service returning.\r
713 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
714 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
715 @retval EFI_NOT_FOUND The processor with the handle specified by\r
716 ProcessorNumber does not exist.\r
717 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
718 a disabled AP.\r
719 @retval EFI_NOT_READY The specified AP is busy.\r
720 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
721\r
722**/\r
723EFI_STATUS\r
724EFIAPI\r
725MpInitLibSwitchBSP (\r
726 IN UINTN ProcessorNumber,\r
727 IN BOOLEAN EnableOldBSP\r
728 )\r
729{\r
b6e45716
JF
730 EFI_STATUS Status;\r
731 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
732 UINT64 TimerPeriod;\r
41be0da5 733\r
8ad05bd2 734 TimerPeriod = 0;\r
b6e45716
JF
735 //\r
736 // Locate Timer Arch Protocol\r
737 //\r
738 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);\r
739 if (EFI_ERROR (Status)) {\r
740 Timer = NULL;\r
741 }\r
742\r
743 if (Timer != NULL) {\r
744 //\r
745 // Save current rate of DXE Timer\r
746 //\r
747 Timer->GetTimerPeriod (Timer, &TimerPeriod);\r
748 //\r
749 // Disable DXE Timer and drain pending interrupts\r
750 //\r
751 Timer->SetTimerPeriod (Timer, 0);\r
752 }\r
41be0da5
JF
753\r
754 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
755\r
b6e45716
JF
756 if (Timer != NULL) {\r
757 //\r
758 // Enable and restore rate of DXE Timer\r
759 //\r
760 Timer->SetTimerPeriod (Timer, TimerPeriod);\r
761 }\r
762\r
41be0da5 763 return Status;\r
3e8ad6bd
JF
764}\r
765\r
766/**\r
767 This service lets the caller enable or disable an AP from this point onward.\r
768 This service may only be called from the BSP.\r
769\r
770 @param[in] ProcessorNumber The handle number of AP.\r
771 The range is from 0 to the total number of\r
772 logical processors minus 1. The total number of\r
773 logical processors can be retrieved by\r
774 MpInitLibGetNumberOfProcessors().\r
775 @param[in] EnableAP Specifies the new state for the processor for\r
776 enabled, FALSE for disabled.\r
777 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
778 the new health status of the AP. This flag\r
779 corresponds to StatusFlag defined in\r
780 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
781 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
782 bits are ignored. If it is NULL, this parameter\r
783 is ignored.\r
784\r
785 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
786 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
787 prior to this service returning.\r
788 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
789 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
790 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
791 does not exist.\r
792 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
793 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
794\r
795**/\r
796EFI_STATUS\r
797EFIAPI\r
798MpInitLibEnableDisableAP (\r
799 IN UINTN ProcessorNumber,\r
800 IN BOOLEAN EnableAP,\r
801 IN UINT32 *HealthFlag OPTIONAL\r
802 )\r
803{\r
e37109bc
JF
804 EFI_STATUS Status;\r
805 BOOLEAN TempStopCheckState;\r
806\r
807 TempStopCheckState = FALSE;\r
808 //\r
809 // temporarily stop checkAllAPsStatus for initialize parameters.\r
810 //\r
811 if (!mStopCheckAllApsStatus) {\r
812 mStopCheckAllApsStatus = TRUE;\r
813 TempStopCheckState = TRUE;\r
814 }\r
815\r
816 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
817\r
818 if (TempStopCheckState) {\r
819 mStopCheckAllApsStatus = FALSE;\r
820 }\r
821\r
822 return Status;\r
3e8ad6bd 823}\r