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