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