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