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