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