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
EnableDebugAgent(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 *
GetCpuMpData(VOID)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
SaveCpuMpData(IN CPU_MP_DATA * CpuMpData)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
GetWakeupBuffer(IN UINTN WakeupBufferSize)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
GetModeTransitionBuffer(IN UINTN BufferSize)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
GetSevEsAPMemory(VOID)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
CheckAndUpdateApsStatus(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
CheckApsStatus(IN EFI_EVENT Event,IN VOID * Context)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
GetProtectedMode16CS(VOID)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
GetProtectedModeCS(VOID)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
RelocateApLoop(IN OUT VOID * Buffer)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
MpInitChangeApLoopCallback(IN EFI_EVENT Event,IN VOID * Context)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
InitMpGlobalData(IN CPU_MP_DATA * CpuMpData)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
MpInitLibStartupAllAPs(IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)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
MpInitLibStartupThisAP(IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)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
MpInitLibSwitchBSP(IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)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
MpInitLibEnableDisableAP(IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)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
PlatformShadowMicrocode(IN OUT CPU_MP_DATA * CpuMpData)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 }
956