1 /** @file
2   MP initialize support functions for PEI 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 #include <Library/PeiServicesLib.h>
11 #include <Guid/S3SmmInitDone.h>
12 #include <Ppi/ShadowMicrocode.h>
13 
14 /**
15   S3 SMM Init Done notification function.
16 
17   @param  PeiServices      Indirect reference to the PEI Services Table.
18   @param  NotifyDesc       Address of the notification descriptor data structure.
19   @param  InvokePpi        Address of the PPI that was invoked.
20 
21   @retval EFI_SUCCESS      The function completes successfully.
22 
23 **/
24 EFI_STATUS
25 EFIAPI
26 NotifyOnS3SmmInitDonePpi (
27   IN  EFI_PEI_SERVICES                              **PeiServices,
28   IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,
29   IN  VOID                                          *InvokePpi
30   );
31 
32 
33 //
34 // Global function
35 //
36 EFI_PEI_NOTIFY_DESCRIPTOR        mS3SmmInitDoneNotifyDesc = {
37   EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
38   &gEdkiiS3SmmInitDoneGuid,
39   NotifyOnS3SmmInitDonePpi
40 };
41 
42 /**
43   S3 SMM Init Done notification function.
44 
45   @param  PeiServices      Indirect reference to the PEI Services Table.
46   @param  NotifyDesc       Address of the notification descriptor data structure.
47   @param  InvokePpi        Address of the PPI that was invoked.
48 
49   @retval EFI_SUCCESS      The function completes successfully.
50 
51 **/
52 EFI_STATUS
53 EFIAPI
NotifyOnS3SmmInitDonePpi(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDesc,IN VOID * InvokePpi)54 NotifyOnS3SmmInitDonePpi (
55   IN  EFI_PEI_SERVICES                              **PeiServices,
56   IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,
57   IN  VOID                                          *InvokePpi
58   )
59 {
60   CPU_MP_DATA     *CpuMpData;
61 
62   CpuMpData = GetCpuMpData ();
63 
64   //
65   // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
66   // So in this notify function, code need to check the current loop
67   // mode, if it is not HLT mode, code need to change loop mode back
68   // to the original mode.
69   //
70   if (CpuMpData->ApLoopMode != ApInHltLoop) {
71     CpuMpData->WakeUpByInitSipiSipi = TRUE;
72   }
73 
74   return EFI_SUCCESS;
75 }
76 
77 
78 /**
79   Enable Debug Agent to support source debugging on AP function.
80 
81 **/
82 VOID
EnableDebugAgent(VOID)83 EnableDebugAgent (
84   VOID
85   )
86 {
87 }
88 
89 /**
90   Get pointer to CPU MP Data structure.
91   For BSP, the pointer is retrieved from HOB.
92   For AP, the structure is just after IDT.
93 
94   @return  The pointer to CPU MP Data structure.
95 **/
96 CPU_MP_DATA *
GetCpuMpData(VOID)97 GetCpuMpData (
98   VOID
99   )
100 {
101   CPU_MP_DATA                  *CpuMpData;
102   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
103   IA32_DESCRIPTOR              Idtr;
104 
105   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
106   if (ApicBaseMsr.Bits.BSP == 1) {
107     CpuMpData = GetCpuMpDataFromGuidedHob ();
108     ASSERT (CpuMpData != NULL);
109   } else {
110     AsmReadIdtr (&Idtr);
111     CpuMpData = (CPU_MP_DATA *) (Idtr.Base + Idtr.Limit + 1);
112   }
113   return CpuMpData;
114 }
115 
116 /**
117   Save the pointer to CPU MP Data structure.
118 
119   @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
120 **/
121 VOID
SaveCpuMpData(IN CPU_MP_DATA * CpuMpData)122 SaveCpuMpData (
123   IN CPU_MP_DATA   *CpuMpData
124   )
125 {
126   UINT64           Data64;
127   //
128   // Build location of CPU MP DATA buffer in HOB
129   //
130   Data64 = (UINT64) (UINTN) CpuMpData;
131   BuildGuidDataHob (
132     &mCpuInitMpLibHobGuid,
133     (VOID *) &Data64,
134     sizeof (UINT64)
135     );
136 }
137 
138 /**
139   Check if AP wakeup buffer is overlapped with existing allocated buffer.
140 
141   @param[in]  WakeupBufferStart     AP wakeup buffer start address.
142   @param[in]  WakeupBufferEnd       AP wakeup buffer end address.
143 
144   @retval  TRUE       There is overlap.
145   @retval  FALSE      There is no overlap.
146 **/
147 BOOLEAN
CheckOverlapWithAllocatedBuffer(IN UINT64 WakeupBufferStart,IN UINT64 WakeupBufferEnd)148 CheckOverlapWithAllocatedBuffer (
149   IN UINT64               WakeupBufferStart,
150   IN UINT64               WakeupBufferEnd
151   )
152 {
153   EFI_PEI_HOB_POINTERS      Hob;
154   EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
155   BOOLEAN                   Overlapped;
156   UINT64                    MemoryStart;
157   UINT64                    MemoryEnd;
158 
159   Overlapped = FALSE;
160   //
161   // Get the HOB list for processing
162   //
163   Hob.Raw = GetHobList ();
164   //
165   // Collect memory ranges
166   //
167   while (!END_OF_HOB_LIST (Hob)) {
168     if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
169       MemoryHob   = Hob.MemoryAllocation;
170       MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
171       MemoryEnd   = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
172       if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
173         Overlapped = TRUE;
174         break;
175       }
176     }
177     Hob.Raw = GET_NEXT_HOB (Hob);
178   }
179   return Overlapped;
180 }
181 
182 /**
183   Get available system memory below 1MB by specified size.
184 
185   @param[in] WakeupBufferSize   Wakeup buffer size required
186 
187   @retval other   Return wakeup buffer address below 1MB.
188   @retval -1      Cannot find free memory below 1MB.
189 **/
190 UINTN
GetWakeupBuffer(IN UINTN WakeupBufferSize)191 GetWakeupBuffer (
192   IN UINTN                WakeupBufferSize
193   )
194 {
195   EFI_PEI_HOB_POINTERS    Hob;
196   UINT64                  WakeupBufferStart;
197   UINT64                  WakeupBufferEnd;
198 
199   WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
200 
201   //
202   // Get the HOB list for processing
203   //
204   Hob.Raw = GetHobList ();
205 
206   //
207   // Collect memory ranges
208   //
209   while (!END_OF_HOB_LIST (Hob)) {
210     if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
211       if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
212           (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
213           ((Hob.ResourceDescriptor->ResourceAttribute &
214             (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
215              EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
216              EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
217              )) == 0)
218            ) {
219         //
220         // Need memory under 1MB to be collected here
221         //
222         WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
223         if (WakeupBufferEnd > BASE_1MB) {
224           //
225           // Wakeup buffer should be under 1MB
226           //
227           WakeupBufferEnd = BASE_1MB;
228         }
229         while (WakeupBufferEnd > WakeupBufferSize) {
230           //
231           // Wakeup buffer should be aligned on 4KB
232           //
233           WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
234           if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
235             break;
236           }
237           if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
238             //
239             // If this range is overlapped with existing allocated buffer, skip it
240             // and find the next range
241             //
242             WakeupBufferEnd -= WakeupBufferSize;
243             continue;
244           }
245           DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
246                                WakeupBufferStart, WakeupBufferSize));
247           return (UINTN)WakeupBufferStart;
248         }
249       }
250     }
251     //
252     // Find the next HOB
253     //
254     Hob.Raw = GET_NEXT_HOB (Hob);
255   }
256 
257   return (UINTN) -1;
258 }
259 
260 /**
261   Get available EfiBootServicesCode memory below 4GB by specified size.
262 
263   This buffer is required to safely transfer AP from real address mode to
264   protected mode or long mode, due to the fact that the buffer returned by
265   GetWakeupBuffer() may be marked as non-executable.
266 
267   @param[in] BufferSize   Wakeup transition buffer size.
268 
269   @retval other   Return wakeup transition buffer address below 4GB.
270   @retval 0       Cannot find free memory below 4GB.
271 **/
272 UINTN
GetModeTransitionBuffer(IN UINTN BufferSize)273 GetModeTransitionBuffer (
274   IN UINTN                BufferSize
275   )
276 {
277   //
278   // PEI phase doesn't need to do such transition. So simply return 0.
279   //
280   return 0;
281 }
282 
283 /**
284   Return the address of the SEV-ES AP jump table.
285 
286   This buffer is required in order for an SEV-ES guest to transition from
287   UEFI into an OS.
288 
289   @return         Return SEV-ES AP jump table buffer
290 **/
291 UINTN
GetSevEsAPMemory(VOID)292 GetSevEsAPMemory (
293   VOID
294   )
295 {
296   //
297   // PEI phase doesn't need to do such transition. So simply return 0.
298   //
299   return 0;
300 }
301 
302 /**
303   Checks APs status and updates APs status if needed.
304 
305 **/
306 VOID
CheckAndUpdateApsStatus(VOID)307 CheckAndUpdateApsStatus (
308   VOID
309   )
310 {
311 }
312 
313 /**
314   Build the microcode patch HOB that contains the base address and size of the
315   microcode patch stored in the memory.
316 
317   @param[in]  CpuMpData    Pointer to the CPU_MP_DATA structure.
318 
319 **/
320 VOID
BuildMicrocodeCacheHob(IN CPU_MP_DATA * CpuMpData)321 BuildMicrocodeCacheHob (
322   IN CPU_MP_DATA    *CpuMpData
323   )
324 {
325   EDKII_MICROCODE_PATCH_HOB    *MicrocodeHob;
326   UINTN                        HobDataLength;
327   UINT32                       Index;
328 
329   HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
330                   sizeof (UINT64) * CpuMpData->CpuCount;
331 
332   MicrocodeHob  = AllocatePool (HobDataLength);
333   if (MicrocodeHob == NULL) {
334     ASSERT (FALSE);
335     return;
336   }
337 
338   //
339   // Store the information of the memory region that holds the microcode patches.
340   //
341   MicrocodeHob->MicrocodePatchAddress    = CpuMpData->MicrocodePatchAddress;
342   MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
343 
344   //
345   // Store the detected microcode patch for each processor as well.
346   //
347   MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
348   for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
349     if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
350       MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
351         CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
352     } else {
353       MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
354     }
355   }
356 
357   BuildGuidDataHob (
358     &gEdkiiMicrocodePatchHobGuid,
359     MicrocodeHob,
360     HobDataLength
361     );
362 
363   return;
364 }
365 
366 /**
367   Initialize global data for MP support.
368 
369   @param[in] CpuMpData  The pointer to CPU MP Data structure.
370 **/
371 VOID
InitMpGlobalData(IN CPU_MP_DATA * CpuMpData)372 InitMpGlobalData (
373   IN CPU_MP_DATA               *CpuMpData
374   )
375 {
376   EFI_STATUS  Status;
377 
378   BuildMicrocodeCacheHob (CpuMpData);
379   SaveCpuMpData (CpuMpData);
380 
381   ///
382   /// Install Notify
383   ///
384   Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
385   ASSERT_EFI_ERROR (Status);
386 }
387 
388 /**
389   This service executes a caller provided function on all enabled APs.
390 
391   @param[in]  Procedure               A pointer to the function to be run on
392                                       enabled APs of the system. See type
393                                       EFI_AP_PROCEDURE.
394   @param[in]  SingleThread            If TRUE, then all the enabled APs execute
395                                       the function specified by Procedure one by
396                                       one, in ascending order of processor handle
397                                       number.  If FALSE, then all the enabled APs
398                                       execute the function specified by Procedure
399                                       simultaneously.
400   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
401                                       service.  If it is NULL, then execute in
402                                       blocking mode. BSP waits until all APs finish
403                                       or TimeoutInMicroSeconds expires.  If it's
404                                       not NULL, then execute in non-blocking mode.
405                                       BSP requests the function specified by
406                                       Procedure to be started on all the enabled
407                                       APs, and go on executing immediately. If
408                                       all return from Procedure, or TimeoutInMicroSeconds
409                                       expires, this event is signaled. The BSP
410                                       can use the CheckEvent() or WaitForEvent()
411                                       services to check the state of event.  Type
412                                       EFI_EVENT is defined in CreateEvent() in
413                                       the Unified Extensible Firmware Interface
414                                       Specification.
415   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
416                                       APs to return from Procedure, either for
417                                       blocking or non-blocking mode. Zero means
418                                       infinity.  If the timeout expires before
419                                       all APs return from Procedure, then Procedure
420                                       on the failed APs is terminated. All enabled
421                                       APs are available for next function assigned
422                                       by MpInitLibStartupAllAPs() or
423                                       MPInitLibStartupThisAP().
424                                       If the timeout expires in blocking mode,
425                                       BSP returns EFI_TIMEOUT.  If the timeout
426                                       expires in non-blocking mode, WaitEvent
427                                       is signaled with SignalEvent().
428   @param[in]  ProcedureArgument       The parameter passed into Procedure for
429                                       all APs.
430   @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
431                                       if all APs finish successfully, then its
432                                       content is set to NULL. If not all APs
433                                       finish before timeout expires, then its
434                                       content is set to address of the buffer
435                                       holding handle numbers of the failed APs.
436                                       The buffer is allocated by MP Initialization
437                                       library, and it's the caller's responsibility to
438                                       free the buffer with FreePool() service.
439                                       In blocking mode, it is ready for consumption
440                                       when the call returns. In non-blocking mode,
441                                       it is ready when WaitEvent is signaled.  The
442                                       list of failed CPU is terminated by
443                                       END_OF_CPU_LIST.
444 
445   @retval EFI_SUCCESS             In blocking mode, all APs have finished before
446                                   the timeout expired.
447   @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
448                                   to all enabled APs.
449   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
450                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
451                                   signaled.
452   @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
453                                   supported.
454   @retval EFI_DEVICE_ERROR        Caller processor is AP.
455   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
456   @retval EFI_NOT_READY           Any enabled APs are busy.
457   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
458   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
459                                   all enabled APs have finished.
460   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
461 
462 **/
463 EFI_STATUS
464 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)465 MpInitLibStartupAllAPs (
466   IN  EFI_AP_PROCEDURE          Procedure,
467   IN  BOOLEAN                   SingleThread,
468   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
469   IN  UINTN                     TimeoutInMicroseconds,
470   IN  VOID                      *ProcedureArgument      OPTIONAL,
471   OUT UINTN                     **FailedCpuList         OPTIONAL
472   )
473 {
474   if (WaitEvent != NULL) {
475     return EFI_UNSUPPORTED;
476   }
477 
478   return StartupAllCPUsWorker (
479            Procedure,
480            SingleThread,
481            TRUE,
482            NULL,
483            TimeoutInMicroseconds,
484            ProcedureArgument,
485            FailedCpuList
486            );
487 }
488 
489 /**
490   This service lets the caller get one enabled AP to execute a caller-provided
491   function.
492 
493   @param[in]  Procedure               A pointer to the function to be run on the
494                                       designated AP of the system. See type
495                                       EFI_AP_PROCEDURE.
496   @param[in]  ProcessorNumber         The handle number of the AP. The range is
497                                       from 0 to the total number of logical
498                                       processors minus 1. The total number of
499                                       logical processors can be retrieved by
500                                       MpInitLibGetNumberOfProcessors().
501   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
502                                       service.  If it is NULL, then execute in
503                                       blocking mode. BSP waits until this AP finish
504                                       or TimeoutInMicroSeconds expires.  If it's
505                                       not NULL, then execute in non-blocking mode.
506                                       BSP requests the function specified by
507                                       Procedure to be started on this AP,
508                                       and go on executing immediately. If this AP
509                                       return from Procedure or TimeoutInMicroSeconds
510                                       expires, this event is signaled. The BSP
511                                       can use the CheckEvent() or WaitForEvent()
512                                       services to check the state of event.  Type
513                                       EFI_EVENT is defined in CreateEvent() in
514                                       the Unified Extensible Firmware Interface
515                                       Specification.
516   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
517                                       this AP to finish this Procedure, either for
518                                       blocking or non-blocking mode. Zero means
519                                       infinity.  If the timeout expires before
520                                       this AP returns from Procedure, then Procedure
521                                       on the AP is terminated. The
522                                       AP is available for next function assigned
523                                       by MpInitLibStartupAllAPs() or
524                                       MpInitLibStartupThisAP().
525                                       If the timeout expires in blocking mode,
526                                       BSP returns EFI_TIMEOUT.  If the timeout
527                                       expires in non-blocking mode, WaitEvent
528                                       is signaled with SignalEvent().
529   @param[in]  ProcedureArgument       The parameter passed into Procedure on the
530                                       specified AP.
531   @param[out] Finished                If NULL, this parameter is ignored.  In
532                                       blocking mode, this parameter is ignored.
533                                       In non-blocking mode, if AP returns from
534                                       Procedure before the timeout expires, its
535                                       content is set to TRUE. Otherwise, the
536                                       value is set to FALSE. The caller can
537                                       determine if the AP returned from Procedure
538                                       by evaluating this value.
539 
540   @retval EFI_SUCCESS             In blocking mode, specified AP finished before
541                                   the timeout expires.
542   @retval EFI_SUCCESS             In non-blocking mode, the function has been
543                                   dispatched to specified AP.
544   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
545                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
546                                   signaled.
547   @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
548                                   supported.
549   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
550   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
551                                   the specified AP has finished.
552   @retval EFI_NOT_READY           The specified AP is busy.
553   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
554   @retval EFI_NOT_FOUND           The processor with the handle specified by
555                                   ProcessorNumber does not exist.
556   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
557   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
558 
559 **/
560 EFI_STATUS
561 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)562 MpInitLibStartupThisAP (
563   IN  EFI_AP_PROCEDURE          Procedure,
564   IN  UINTN                     ProcessorNumber,
565   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
566   IN  UINTN                     TimeoutInMicroseconds,
567   IN  VOID                      *ProcedureArgument      OPTIONAL,
568   OUT BOOLEAN                   *Finished               OPTIONAL
569   )
570 {
571   if (WaitEvent != NULL) {
572     return EFI_UNSUPPORTED;
573   }
574 
575   return StartupThisAPWorker (
576            Procedure,
577            ProcessorNumber,
578            NULL,
579            TimeoutInMicroseconds,
580            ProcedureArgument,
581            Finished
582            );
583 }
584 
585 /**
586   This service switches the requested AP to be the BSP from that point onward.
587   This service changes the BSP for all purposes. This call can only be performed
588   by the current BSP.
589 
590   @param[in] ProcessorNumber   The handle number of AP that is to become the new
591                                BSP. The range is from 0 to the total number of
592                                logical processors minus 1. The total number of
593                                logical processors can be retrieved by
594                                MpInitLibGetNumberOfProcessors().
595   @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
596                                enabled AP. Otherwise, it will be disabled.
597 
598   @retval EFI_SUCCESS             BSP successfully switched.
599   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
600                                   this service returning.
601   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
602   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
603   @retval EFI_NOT_FOUND           The processor with the handle specified by
604                                   ProcessorNumber does not exist.
605   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
606                                   a disabled AP.
607   @retval EFI_NOT_READY           The specified AP is busy.
608   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
609 
610 **/
611 EFI_STATUS
612 EFIAPI
MpInitLibSwitchBSP(IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)613 MpInitLibSwitchBSP (
614   IN UINTN                     ProcessorNumber,
615   IN  BOOLEAN                  EnableOldBSP
616   )
617 {
618   return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
619 }
620 
621 /**
622   This service lets the caller enable or disable an AP from this point onward.
623   This service may only be called from the BSP.
624 
625   @param[in] ProcessorNumber   The handle number of AP.
626                                The range is from 0 to the total number of
627                                logical processors minus 1. The total number of
628                                logical processors can be retrieved by
629                                MpInitLibGetNumberOfProcessors().
630   @param[in] EnableAP          Specifies the new state for the processor for
631                                enabled, FALSE for disabled.
632   @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
633                                the new health status of the AP. This flag
634                                corresponds to StatusFlag defined in
635                                EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
636                                the PROCESSOR_HEALTH_STATUS_BIT is used. All other
637                                bits are ignored.  If it is NULL, this parameter
638                                is ignored.
639 
640   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
641   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
642                                   prior to this service returning.
643   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
644   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
645   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
646                                   does not exist.
647   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
648   @retval EFI_NOT_READY           MP Initialize Library is not initialized.
649 
650 **/
651 EFI_STATUS
652 EFIAPI
MpInitLibEnableDisableAP(IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)653 MpInitLibEnableDisableAP (
654   IN  UINTN                     ProcessorNumber,
655   IN  BOOLEAN                   EnableAP,
656   IN  UINT32                    *HealthFlag OPTIONAL
657   )
658 {
659   return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
660 }
661 
662 /**
663   This funtion will try to invoke platform specific microcode shadow logic to
664   relocate microcode update patches into memory.
665 
666   @param[in, out] CpuMpData  The pointer to CPU MP Data structure.
667 
668   @retval EFI_SUCCESS              Shadow microcode success.
669   @retval EFI_OUT_OF_RESOURCES     No enough resource to complete the operation.
670   @retval EFI_UNSUPPORTED          Can't find platform specific microcode shadow
671                                    PPI/Protocol.
672 **/
673 EFI_STATUS
PlatformShadowMicrocode(IN OUT CPU_MP_DATA * CpuMpData)674 PlatformShadowMicrocode (
675   IN OUT CPU_MP_DATA             *CpuMpData
676   )
677 {
678   EFI_STATUS                         Status;
679   EDKII_PEI_SHADOW_MICROCODE_PPI     *ShadowMicrocodePpi;
680   UINTN                              CpuCount;
681   EDKII_PEI_MICROCODE_CPU_ID         *MicrocodeCpuId;
682   UINTN                              Index;
683   UINTN                              BufferSize;
684   VOID                               *Buffer;
685 
686   Status = PeiServicesLocatePpi (
687              &gEdkiiPeiShadowMicrocodePpiGuid,
688              0,
689              NULL,
690              (VOID **) &ShadowMicrocodePpi
691              );
692   if (EFI_ERROR (Status)) {
693     return EFI_UNSUPPORTED;
694   }
695 
696   CpuCount = CpuMpData->CpuCount;
697   MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *) AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
698   if (MicrocodeCpuId == NULL) {
699     return EFI_OUT_OF_RESOURCES;
700   }
701 
702   for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
703     MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
704     MicrocodeCpuId[Index].PlatformId         = CpuMpData->CpuData[Index].PlatformId;
705   }
706 
707   Status = ShadowMicrocodePpi->ShadowMicrocode (
708              ShadowMicrocodePpi,
709              CpuCount,
710              MicrocodeCpuId,
711              &BufferSize,
712              &Buffer
713              );
714   FreePool (MicrocodeCpuId);
715   if (EFI_ERROR (Status)) {
716     return EFI_NOT_FOUND;
717   }
718 
719   CpuMpData->MicrocodePatchAddress    = (UINTN) Buffer;
720   CpuMpData->MicrocodePatchRegionSize = BufferSize;
721 
722   DEBUG ((
723     DEBUG_INFO,
724     "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
725     __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
726     ));
727 
728   return EFI_SUCCESS;
729 }
730