]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg/MpInitLib: Fix MemTest86 failure.
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / DxeMpLib.c
... / ...
CommitLineData
1/** @file\r
2 MP initialize support functions for DXE phase.\r
3\r
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
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
16\r
17#include <Library/UefiLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/DebugAgentLib.h>\r
20#include <Library/DxeServicesTableLib.h>\r
21\r
22#include <Protocol/Timer.h>\r
23\r
24#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))\r
25#define AP_SAFE_STACK_SIZE 128\r
26\r
27CPU_MP_DATA *mCpuMpData = NULL;\r
28EFI_EVENT mCheckAllApsEvent = NULL;\r
29EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
30EFI_EVENT mLegacyBootEvent = NULL;\r
31volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
32VOID *mReservedApLoopFunc = NULL;\r
33UINTN mReservedTopOfApStack;\r
34volatile UINT32 mNumberToFinish = 0;\r
35\r
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
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
78/**\r
79 Get available system memory below 0x88000 by specified size.\r
80\r
81 @param[in] WakeupBufferSize Wakeup buffer size required\r
82\r
83 @retval other Return wakeup buffer address below 1MB.\r
84 @retval -1 Cannot find free memory below 1MB.\r
85**/\r
86UINTN\r
87GetWakeupBuffer (\r
88 IN UINTN WakeupBufferSize\r
89 )\r
90{\r
91 EFI_STATUS Status;\r
92 EFI_PHYSICAL_ADDRESS StartAddress;\r
93\r
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
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
110 if (EFI_ERROR (Status)) {\r
111 StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\r
112 }\r
113\r
114 DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
115 (UINTN) StartAddress, WakeupBufferSize));\r
116\r
117 return (UINTN) StartAddress;\r
118}\r
119\r
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
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
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
200}\r
201\r
202/**\r
203 Checks APs' status periodically.\r
204\r
205 This function is triggered by timer periodically to check the\r
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
227\r
228/**\r
229 Get Protected mode code segment from current GDT table.\r
230\r
231 @return Protected mode code segment value.\r
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
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
254 ASSERT (Index != GdtEntryCount);\r
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
272 UINTN ProcessorNumber;\r
273\r
274 MpInitLibWhoAmI (&ProcessorNumber);\r
275 CpuMpData = GetCpuMpData ();\r
276 MwaitSupport = IsMwaitSupport ();\r
277 AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
278 AsmRelocateApLoopFunc (\r
279 MwaitSupport,\r
280 CpuMpData->ApTargetCState,\r
281 CpuMpData->PmCodeSegment,\r
282 mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
283 (UINTN) &mNumberToFinish\r
284 );\r
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
301MpInitChangeApLoopCallback (\r
302 IN EFI_EVENT Event,\r
303 IN VOID *Context\r
304 )\r
305{\r
306 CPU_MP_DATA *CpuMpData;\r
307\r
308 CpuMpData = GetCpuMpData ();\r
309 CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
310 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
311 mNumberToFinish = CpuMpData->CpuCount - 1;\r
312 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
313 while (mNumberToFinish > 0) {\r
314 CpuPause ();\r
315 }\r
316 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
317}\r
318\r
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
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
335 CPU_INFO_IN_HOB *CpuInfoInHob;\r
336\r
337 SaveCpuMpData (CpuMpData);\r
338\r
339 if (CpuMpData->CpuCount == 1) {\r
340 //\r
341 // If only BSP exists, return\r
342 //\r
343 return;\r
344 }\r
345\r
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
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
364 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
365 if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) {\r
366 StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
367 } else {\r
368 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
369 }\r
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
380\r
381 DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",\r
382 (UINT64)StackBase, (UINT64)Index));\r
383 }\r
384 }\r
385\r
386 //\r
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
391 // Allocating it in advance since memory services are not available in\r
392 // Exit Boot Services callback function.\r
393 //\r
394 ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (\r
395 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
396 ));\r
397 Address = BASE_4GB - 1;\r
398 Status = gBS->AllocatePages (\r
399 AllocateMaxAddress,\r
400 EfiReservedMemoryType,\r
401 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
402 &Address\r
403 );\r
404 ASSERT_EFI_ERROR (Status);\r
405\r
406 mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
407 ASSERT (mReservedApLoopFunc != NULL);\r
408\r
409 //\r
410 // Make sure that the buffer memory is executable if NX protection is enabled\r
411 // for EfiReservedMemoryType.\r
412 //\r
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
438 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
439 CopyMem (\r
440 mReservedApLoopFunc,\r
441 CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
442 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
443 );\r
444\r
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
463\r
464 Status = gBS->CreateEvent (\r
465 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
466 TPL_CALLBACK,\r
467 MpInitChangeApLoopCallback,\r
468 NULL,\r
469 &mMpInitExitBootServicesEvent\r
470 );\r
471 ASSERT_EFI_ERROR (Status);\r
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
482}\r
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
511 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
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
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
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
621 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
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
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
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
730 EFI_STATUS Status;\r
731 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
732 UINT64 TimerPeriod;\r
733\r
734 TimerPeriod = 0;\r
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
753\r
754 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
755\r
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
763 return Status;\r
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
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
823}\r