]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 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 UINTN ProcessorNumber;
385 UINTN StackStart;
386
387 MpInitLibWhoAmI (&ProcessorNumber);
388 CpuMpData = GetCpuMpData ();
389 MwaitSupport = IsMwaitSupport ();
390 if (CpuMpData->UseSevEsAPMethod) {
391 //
392 // 64-bit AMD processors with SEV-ES
393 //
394 StackStart = CpuMpData->SevEsAPResetStackStart;
395 mReservedApLoop.AmdSevEntry (
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 //
407 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
408 //
409 StackStart = mReservedTopOfApStack;
410 mReservedApLoop.GenericEntry (
411 MwaitSupport,
412 CpuMpData->ApTargetCState,
413 StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
414 (UINTN)&mNumberToFinish,
415 mApPageTable
416 );
417 }
418
419 //
420 // It should never reach here
421 //
422 ASSERT (FALSE);
423 }
424
425 /**
426 Callback function for ExitBootServices.
427
428 @param[in] Event Event whose notification function is being invoked.
429 @param[in] Context The pointer to the notification function's context,
430 which is implementation-dependent.
431
432 **/
433 VOID
434 EFIAPI
435 MpInitChangeApLoopCallback (
436 IN EFI_EVENT Event,
437 IN VOID *Context
438 )
439 {
440 CPU_MP_DATA *CpuMpData;
441
442 CpuMpData = GetCpuMpData ();
443 CpuMpData->PmCodeSegment = GetProtectedModeCS ();
444 CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
445 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
446 mNumberToFinish = CpuMpData->CpuCount - 1;
447 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
448 while (mNumberToFinish > 0) {
449 CpuPause ();
450 }
451
452 if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN)-1)) {
453 //
454 // There are APs present. Re-use reserved memory area below 1MB from
455 // WakeupBuffer as the area to be used for transitioning to 16-bit mode
456 // in support of booting of the AP by an OS.
457 //
458 CopyMem (
459 (VOID *)CpuMpData->WakeupBuffer,
460 (VOID *)(CpuMpData->AddressMap.RendezvousFunnelAddress +
461 CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),
462 CpuMpData->AddressMap.SwitchToRealPM16ModeSize
463 );
464 }
465
466 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
467 }
468
469 /**
470 Initialize global data for MP support.
471
472 @param[in] CpuMpData The pointer to CPU MP Data structure.
473 **/
474 VOID
475 InitMpGlobalData (
476 IN CPU_MP_DATA *CpuMpData
477 )
478 {
479 EFI_STATUS Status;
480 EFI_PHYSICAL_ADDRESS Address;
481 UINTN Index;
482 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
483 UINTN StackBase;
484 CPU_INFO_IN_HOB *CpuInfoInHob;
485 MP_ASSEMBLY_ADDRESS_MAP *AddressMap;
486 UINT8 *ApLoopFunc;
487 UINTN ApLoopFuncSize;
488 UINTN StackPages;
489 UINTN FuncPages;
490
491 SaveCpuMpData (CpuMpData);
492
493 if (CpuMpData->CpuCount == 1) {
494 //
495 // If only BSP exists, return
496 //
497 return;
498 }
499
500 if (PcdGetBool (PcdCpuStackGuard)) {
501 //
502 // One extra page at the bottom of the stack is needed for Guard page.
503 //
504 if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {
505 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
506 ASSERT (FALSE);
507 }
508
509 //
510 // DXE will reuse stack allocated for APs at PEI phase if it's available.
511 // Let's check it here.
512 //
513 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
514 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
515 // set here.
516 //
517 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
518 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {
519 if ((CpuInfoInHob != NULL) && (CpuInfoInHob[Index].ApTopOfStack != 0)) {
520 StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;
521 } else {
522 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;
523 }
524
525 Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);
526 ASSERT_EFI_ERROR (Status);
527
528 Status = gDS->SetMemorySpaceAttributes (
529 StackBase,
530 EFI_PAGES_TO_SIZE (1),
531 MemDesc.Attributes | EFI_MEMORY_RP
532 );
533 ASSERT_EFI_ERROR (Status);
534
535 DEBUG ((
536 DEBUG_INFO,
537 "Stack Guard set at %lx [cpu%lu]!\n",
538 (UINT64)StackBase,
539 (UINT64)Index
540 ));
541 }
542 }
543
544 AddressMap = &CpuMpData->AddressMap;
545 if (CpuMpData->UseSevEsAPMethod) {
546 //
547 // 64-bit AMD processors with SEV-ES
548 //
549 Address = BASE_4GB - 1;
550 ApLoopFunc = AddressMap->RelocateApLoopFuncAddressAmdSev;
551 ApLoopFuncSize = AddressMap->RelocateApLoopFuncSizeAmdSev;
552 } else {
553 //
554 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
555 //
556 Address = MAX_ADDRESS;
557 ApLoopFunc = AddressMap->RelocateApLoopFuncAddressGeneric;
558 ApLoopFuncSize = AddressMap->RelocateApLoopFuncSizeGeneric;
559 }
560
561 //
562 // Avoid APs access invalid buffer data which allocated by BootServices,
563 // so we will allocate reserved data for AP loop code. We also need to
564 // allocate this buffer below 4GB due to APs may be transferred to 32bit
565 // protected mode on long mode DXE.
566 // Allocating it in advance since memory services are not available in
567 // Exit Boot Services callback function.
568 //
569 // +------------+ (TopOfApStack)
570 // | Stack * N |
571 // +------------+ (stack base, 4k aligned)
572 // | Padding |
573 // +------------+
574 // | Ap Loop |
575 // +------------+ ((low address, 4k-aligned)
576 //
577
578 StackPages = EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * AP_SAFE_STACK_SIZE);
579 FuncPages = EFI_SIZE_TO_PAGES (ApLoopFuncSize);
580
581 Status = gBS->AllocatePages (
582 AllocateMaxAddress,
583 EfiReservedMemoryType,
584 StackPages + FuncPages,
585 &Address
586 );
587 ASSERT_EFI_ERROR (Status);
588
589 //
590 // Make sure that the buffer memory is executable if NX protection is enabled
591 // for EfiReservedMemoryType.
592 //
593 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
594 // service.
595 //
596 Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);
597 if (!EFI_ERROR (Status)) {
598 gDS->SetMemorySpaceAttributes (
599 Address,
600 EFI_PAGES_TO_SIZE (FuncPages),
601 MemDesc.Attributes & (~EFI_MEMORY_XP)
602 );
603 }
604
605 mReservedTopOfApStack = (UINTN)Address + EFI_PAGES_TO_SIZE (StackPages+FuncPages);
606 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
607 mReservedApLoop.Data = (VOID *)(UINTN)Address;
608 ASSERT (mReservedApLoop.Data != NULL);
609 CopyMem (mReservedApLoop.Data, ApLoopFunc, ApLoopFuncSize);
610 if (!CpuMpData->UseSevEsAPMethod) {
611 //
612 // processors without SEV-ES
613 //
614 mApPageTable = CreatePageTable (
615 (UINTN)Address,
616 EFI_PAGES_TO_SIZE (StackPages+FuncPages)
617 );
618 }
619
620 Status = gBS->CreateEvent (
621 EVT_TIMER | EVT_NOTIFY_SIGNAL,
622 TPL_NOTIFY,
623 CheckApsStatus,
624 NULL,
625 &mCheckAllApsEvent
626 );
627 ASSERT_EFI_ERROR (Status);
628
629 //
630 // Set timer to check all APs status.
631 //
632 Status = gBS->SetTimer (
633 mCheckAllApsEvent,
634 TimerPeriodic,
635 EFI_TIMER_PERIOD_MICROSECONDS (
636 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)
637 )
638 );
639 ASSERT_EFI_ERROR (Status);
640
641 Status = gBS->CreateEvent (
642 EVT_SIGNAL_EXIT_BOOT_SERVICES,
643 TPL_CALLBACK,
644 MpInitChangeApLoopCallback,
645 NULL,
646 &mMpInitExitBootServicesEvent
647 );
648 ASSERT_EFI_ERROR (Status);
649
650 Status = gBS->CreateEventEx (
651 EVT_NOTIFY_SIGNAL,
652 TPL_CALLBACK,
653 MpInitChangeApLoopCallback,
654 NULL,
655 &gEfiEventLegacyBootGuid,
656 &mLegacyBootEvent
657 );
658 ASSERT_EFI_ERROR (Status);
659 }
660
661 /**
662 This service executes a caller provided function on all enabled APs.
663
664 @param[in] Procedure A pointer to the function to be run on
665 enabled APs of the system. See type
666 EFI_AP_PROCEDURE.
667 @param[in] SingleThread If TRUE, then all the enabled APs execute
668 the function specified by Procedure one by
669 one, in ascending order of processor handle
670 number. If FALSE, then all the enabled APs
671 execute the function specified by Procedure
672 simultaneously.
673 @param[in] WaitEvent The event created by the caller with CreateEvent()
674 service. If it is NULL, then execute in
675 blocking mode. BSP waits until all APs finish
676 or TimeoutInMicroSeconds expires. If it's
677 not NULL, then execute in non-blocking mode.
678 BSP requests the function specified by
679 Procedure to be started on all the enabled
680 APs, and go on executing immediately. If
681 all return from Procedure, or TimeoutInMicroSeconds
682 expires, this event is signaled. The BSP
683 can use the CheckEvent() or WaitForEvent()
684 services to check the state of event. Type
685 EFI_EVENT is defined in CreateEvent() in
686 the Unified Extensible Firmware Interface
687 Specification.
688 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
689 APs to return from Procedure, either for
690 blocking or non-blocking mode. Zero means
691 infinity. If the timeout expires before
692 all APs return from Procedure, then Procedure
693 on the failed APs is terminated. All enabled
694 APs are available for next function assigned
695 by MpInitLibStartupAllAPs() or
696 MPInitLibStartupThisAP().
697 If the timeout expires in blocking mode,
698 BSP returns EFI_TIMEOUT. If the timeout
699 expires in non-blocking mode, WaitEvent
700 is signaled with SignalEvent().
701 @param[in] ProcedureArgument The parameter passed into Procedure for
702 all APs.
703 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
704 if all APs finish successfully, then its
705 content is set to NULL. If not all APs
706 finish before timeout expires, then its
707 content is set to address of the buffer
708 holding handle numbers of the failed APs.
709 The buffer is allocated by MP Initialization
710 library, and it's the caller's responsibility to
711 free the buffer with FreePool() service.
712 In blocking mode, it is ready for consumption
713 when the call returns. In non-blocking mode,
714 it is ready when WaitEvent is signaled. The
715 list of failed CPU is terminated by
716 END_OF_CPU_LIST.
717
718 @retval EFI_SUCCESS In blocking mode, all APs have finished before
719 the timeout expired.
720 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
721 to all enabled APs.
722 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
723 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
724 signaled.
725 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
726 supported.
727 @retval EFI_DEVICE_ERROR Caller processor is AP.
728 @retval EFI_NOT_STARTED No enabled APs exist in the system.
729 @retval EFI_NOT_READY Any enabled APs are busy.
730 @retval EFI_NOT_READY MP Initialize Library is not initialized.
731 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
732 all enabled APs have finished.
733 @retval EFI_INVALID_PARAMETER Procedure is NULL.
734
735 **/
736 EFI_STATUS
737 EFIAPI
738 MpInitLibStartupAllAPs (
739 IN EFI_AP_PROCEDURE Procedure,
740 IN BOOLEAN SingleThread,
741 IN EFI_EVENT WaitEvent OPTIONAL,
742 IN UINTN TimeoutInMicroseconds,
743 IN VOID *ProcedureArgument OPTIONAL,
744 OUT UINTN **FailedCpuList OPTIONAL
745 )
746 {
747 EFI_STATUS Status;
748
749 //
750 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
751 //
752 mStopCheckAllApsStatus = TRUE;
753
754 Status = StartupAllCPUsWorker (
755 Procedure,
756 SingleThread,
757 TRUE,
758 WaitEvent,
759 TimeoutInMicroseconds,
760 ProcedureArgument,
761 FailedCpuList
762 );
763
764 //
765 // Start checkAllApsStatus
766 //
767 mStopCheckAllApsStatus = FALSE;
768
769 return Status;
770 }
771
772 /**
773 This service lets the caller get one enabled AP to execute a caller-provided
774 function.
775
776 @param[in] Procedure A pointer to the function to be run on the
777 designated AP of the system. See type
778 EFI_AP_PROCEDURE.
779 @param[in] ProcessorNumber The handle number of the AP. The range is
780 from 0 to the total number of logical
781 processors minus 1. The total number of
782 logical processors can be retrieved by
783 MpInitLibGetNumberOfProcessors().
784 @param[in] WaitEvent The event created by the caller with CreateEvent()
785 service. If it is NULL, then execute in
786 blocking mode. BSP waits until this AP finish
787 or TimeoutInMicroSeconds expires. If it's
788 not NULL, then execute in non-blocking mode.
789 BSP requests the function specified by
790 Procedure to be started on this AP,
791 and go on executing immediately. If this AP
792 return from Procedure or TimeoutInMicroSeconds
793 expires, this event is signaled. The BSP
794 can use the CheckEvent() or WaitForEvent()
795 services to check the state of event. Type
796 EFI_EVENT is defined in CreateEvent() in
797 the Unified Extensible Firmware Interface
798 Specification.
799 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
800 this AP to finish this Procedure, either for
801 blocking or non-blocking mode. Zero means
802 infinity. If the timeout expires before
803 this AP returns from Procedure, then Procedure
804 on the AP is terminated. The
805 AP is available for next function assigned
806 by MpInitLibStartupAllAPs() or
807 MpInitLibStartupThisAP().
808 If the timeout expires in blocking mode,
809 BSP returns EFI_TIMEOUT. If the timeout
810 expires in non-blocking mode, WaitEvent
811 is signaled with SignalEvent().
812 @param[in] ProcedureArgument The parameter passed into Procedure on the
813 specified AP.
814 @param[out] Finished If NULL, this parameter is ignored. In
815 blocking mode, this parameter is ignored.
816 In non-blocking mode, if AP returns from
817 Procedure before the timeout expires, its
818 content is set to TRUE. Otherwise, the
819 value is set to FALSE. The caller can
820 determine if the AP returned from Procedure
821 by evaluating this value.
822
823 @retval EFI_SUCCESS In blocking mode, specified AP finished before
824 the timeout expires.
825 @retval EFI_SUCCESS In non-blocking mode, the function has been
826 dispatched to specified AP.
827 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
828 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
829 signaled.
830 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
831 supported.
832 @retval EFI_DEVICE_ERROR The calling processor is an AP.
833 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
834 the specified AP has finished.
835 @retval EFI_NOT_READY The specified AP is busy.
836 @retval EFI_NOT_READY MP Initialize Library is not initialized.
837 @retval EFI_NOT_FOUND The processor with the handle specified by
838 ProcessorNumber does not exist.
839 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
840 @retval EFI_INVALID_PARAMETER Procedure is NULL.
841
842 **/
843 EFI_STATUS
844 EFIAPI
845 MpInitLibStartupThisAP (
846 IN EFI_AP_PROCEDURE Procedure,
847 IN UINTN ProcessorNumber,
848 IN EFI_EVENT WaitEvent OPTIONAL,
849 IN UINTN TimeoutInMicroseconds,
850 IN VOID *ProcedureArgument OPTIONAL,
851 OUT BOOLEAN *Finished OPTIONAL
852 )
853 {
854 EFI_STATUS Status;
855
856 //
857 // temporarily stop checkAllApsStatus for avoid resource dead-lock.
858 //
859 mStopCheckAllApsStatus = TRUE;
860
861 Status = StartupThisAPWorker (
862 Procedure,
863 ProcessorNumber,
864 WaitEvent,
865 TimeoutInMicroseconds,
866 ProcedureArgument,
867 Finished
868 );
869
870 mStopCheckAllApsStatus = FALSE;
871
872 return Status;
873 }
874
875 /**
876 This service switches the requested AP to be the BSP from that point onward.
877 This service changes the BSP for all purposes. This call can only be performed
878 by the current BSP.
879
880 @param[in] ProcessorNumber The handle number of AP that is to become the new
881 BSP. The range is from 0 to the total number of
882 logical processors minus 1. The total number of
883 logical processors can be retrieved by
884 MpInitLibGetNumberOfProcessors().
885 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
886 enabled AP. Otherwise, it will be disabled.
887
888 @retval EFI_SUCCESS BSP successfully switched.
889 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
890 this service returning.
891 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
892 @retval EFI_DEVICE_ERROR The calling processor is an AP.
893 @retval EFI_NOT_FOUND The processor with the handle specified by
894 ProcessorNumber does not exist.
895 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
896 a disabled AP.
897 @retval EFI_NOT_READY The specified AP is busy.
898 @retval EFI_NOT_READY MP Initialize Library is not initialized.
899
900 **/
901 EFI_STATUS
902 EFIAPI
903 MpInitLibSwitchBSP (
904 IN UINTN ProcessorNumber,
905 IN BOOLEAN EnableOldBSP
906 )
907 {
908 EFI_STATUS Status;
909 EFI_TIMER_ARCH_PROTOCOL *Timer;
910 UINT64 TimerPeriod;
911
912 TimerPeriod = 0;
913 //
914 // Locate Timer Arch Protocol
915 //
916 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&Timer);
917 if (EFI_ERROR (Status)) {
918 Timer = NULL;
919 }
920
921 if (Timer != NULL) {
922 //
923 // Save current rate of DXE Timer
924 //
925 Timer->GetTimerPeriod (Timer, &TimerPeriod);
926 //
927 // Disable DXE Timer and drain pending interrupts
928 //
929 Timer->SetTimerPeriod (Timer, 0);
930 }
931
932 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
933
934 if (Timer != NULL) {
935 //
936 // Enable and restore rate of DXE Timer
937 //
938 Timer->SetTimerPeriod (Timer, TimerPeriod);
939 }
940
941 return Status;
942 }
943
944 /**
945 This service lets the caller enable or disable an AP from this point onward.
946 This service may only be called from the BSP.
947
948 @param[in] ProcessorNumber The handle number of AP.
949 The range is from 0 to the total number of
950 logical processors minus 1. The total number of
951 logical processors can be retrieved by
952 MpInitLibGetNumberOfProcessors().
953 @param[in] EnableAP Specifies the new state for the processor for
954 enabled, FALSE for disabled.
955 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
956 the new health status of the AP. This flag
957 corresponds to StatusFlag defined in
958 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
959 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
960 bits are ignored. If it is NULL, this parameter
961 is ignored.
962
963 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
964 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
965 prior to this service returning.
966 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
967 @retval EFI_DEVICE_ERROR The calling processor is an AP.
968 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
969 does not exist.
970 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
971 @retval EFI_NOT_READY MP Initialize Library is not initialized.
972
973 **/
974 EFI_STATUS
975 EFIAPI
976 MpInitLibEnableDisableAP (
977 IN UINTN ProcessorNumber,
978 IN BOOLEAN EnableAP,
979 IN UINT32 *HealthFlag OPTIONAL
980 )
981 {
982 EFI_STATUS Status;
983 BOOLEAN TempStopCheckState;
984
985 TempStopCheckState = FALSE;
986 //
987 // temporarily stop checkAllAPsStatus for initialize parameters.
988 //
989 if (!mStopCheckAllApsStatus) {
990 mStopCheckAllApsStatus = TRUE;
991 TempStopCheckState = TRUE;
992 }
993
994 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
995
996 if (TempStopCheckState) {
997 mStopCheckAllApsStatus = FALSE;
998 }
999
1000 return Status;
1001 }
1002
1003 /**
1004 This funtion will try to invoke platform specific microcode shadow logic to
1005 relocate microcode update patches into memory.
1006
1007 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1008
1009 @retval EFI_SUCCESS Shadow microcode success.
1010 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
1011 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
1012 PPI/Protocol.
1013 **/
1014 EFI_STATUS
1015 PlatformShadowMicrocode (
1016 IN OUT CPU_MP_DATA *CpuMpData
1017 )
1018 {
1019 //
1020 // There is no DXE version of platform shadow microcode protocol so far.
1021 // A platform which only uses DxeMpInitLib instance could only supports
1022 // the PCD based microcode shadowing.
1023 //
1024 return EFI_UNSUPPORTED;
1025 }