1 /** @file
2   CPU DXE Module to produce CPU MP Protocol.
3 
4   Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "CpuDxe.h"
10 #include "CpuMp.h"
11 
12 EFI_HANDLE     mMpServiceHandle       = NULL;
13 UINTN          mNumberOfProcessors    = 1;
14 
15 EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
16   GetNumberOfProcessors,
17   GetProcessorInfo,
18   StartupAllAPs,
19   StartupThisAP,
20   SwitchBSP,
21   EnableDisableAP,
22   WhoAmI
23 };
24 
25 /**
26   This service retrieves the number of logical processor in the platform
27   and the number of those logical processors that are enabled on this boot.
28   This service may only be called from the BSP.
29 
30   This function is used to retrieve the following information:
31     - The number of logical processors that are present in the system.
32     - The number of enabled logical processors in the system at the instant
33       this call is made.
34 
35   Because MP Service Protocol provides services to enable and disable processors
36   dynamically, the number of enabled logical processors may vary during the
37   course of a boot session.
38 
39   If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
40   If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
41   EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
42   is returned in NumberOfProcessors, the number of currently enabled processor
43   is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
44 
45   @param[in]  This                        A pointer to the EFI_MP_SERVICES_PROTOCOL
46                                           instance.
47   @param[out] NumberOfProcessors          Pointer to the total number of logical
48                                           processors in the system, including the BSP
49                                           and disabled APs.
50   @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
51                                           processors that exist in system, including
52                                           the BSP.
53 
54   @retval EFI_SUCCESS             The number of logical processors and enabled
55                                   logical processors was retrieved.
56   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
57   @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
58   @retval EFI_INVALID_PARAMETER   NumberOfEnabledProcessors is NULL.
59 
60 **/
61 EFI_STATUS
62 EFIAPI
GetNumberOfProcessors(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * NumberOfProcessors,OUT UINTN * NumberOfEnabledProcessors)63 GetNumberOfProcessors (
64   IN  EFI_MP_SERVICES_PROTOCOL  *This,
65   OUT UINTN                     *NumberOfProcessors,
66   OUT UINTN                     *NumberOfEnabledProcessors
67   )
68 {
69   if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
70     return EFI_INVALID_PARAMETER;
71   }
72 
73   return MpInitLibGetNumberOfProcessors (
74            NumberOfProcessors,
75            NumberOfEnabledProcessors
76            );
77 }
78 
79 /**
80   Gets detailed MP-related information on the requested processor at the
81   instant this call is made. This service may only be called from the BSP.
82 
83   This service retrieves detailed MP-related information about any processor
84   on the platform. Note the following:
85     - The processor information may change during the course of a boot session.
86     - The information presented here is entirely MP related.
87 
88   Information regarding the number of caches and their sizes, frequency of operation,
89   slot numbers is all considered platform-related information and is not provided
90   by this service.
91 
92   @param[in]  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL
93                                     instance.
94   @param[in]  ProcessorNumber       The handle number of processor.
95   @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
96                                     the requested processor is deposited.
97 
98   @retval EFI_SUCCESS             Processor information was returned.
99   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
100   @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
101   @retval EFI_NOT_FOUND           The processor with the handle specified by
102                                   ProcessorNumber does not exist in the platform.
103 
104 **/
105 EFI_STATUS
106 EFIAPI
GetProcessorInfo(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,OUT EFI_PROCESSOR_INFORMATION * ProcessorInfoBuffer)107 GetProcessorInfo (
108   IN  EFI_MP_SERVICES_PROTOCOL   *This,
109   IN  UINTN                      ProcessorNumber,
110   OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
111   )
112 {
113   return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
114 }
115 
116 /**
117   This service executes a caller provided function on all enabled APs. APs can
118   run either simultaneously or one at a time in sequence. This service supports
119   both blocking and non-blocking requests. The non-blocking requests use EFI
120   events so the BSP can detect when the APs have finished. This service may only
121   be called from the BSP.
122 
123   This function is used to dispatch all the enabled APs to the function specified
124   by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
125   immediately and Procedure is not started on any AP.
126 
127   If SingleThread is TRUE, all the enabled APs execute the function specified by
128   Procedure one by one, in ascending order of processor handle number. Otherwise,
129   all the enabled APs execute the function specified by Procedure simultaneously.
130 
131   If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
132   APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
133   mode, and the BSP returns from this service without waiting for APs. If a
134   non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
135   is signaled, then EFI_UNSUPPORTED must be returned.
136 
137   If the timeout specified by TimeoutInMicroseconds expires before all APs return
138   from Procedure, then Procedure on the failed APs is terminated. All enabled APs
139   are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
140   and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
141   content points to the list of processor handle numbers in which Procedure was
142   terminated.
143 
144   Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
145   to make sure that the nature of the code that is executed on the BSP and the
146   dispatched APs is well controlled. The MP Services Protocol does not guarantee
147   that the Procedure function is MP-safe. Hence, the tasks that can be run in
148   parallel are limited to certain independent tasks and well-controlled exclusive
149   code. EFI services and protocols may not be called by APs unless otherwise
150   specified.
151 
152   In blocking execution mode, BSP waits until all APs finish or
153   TimeoutInMicroseconds expires.
154 
155   In non-blocking execution mode, BSP is freed to return to the caller and then
156   proceed to the next task without having to wait for APs. The following
157   sequence needs to occur in a non-blocking execution mode:
158 
159     -# The caller that intends to use this MP Services Protocol in non-blocking
160        mode creates WaitEvent by calling the EFI CreateEvent() service.  The caller
161        invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
162        is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
163        the function specified by Procedure to be started on all the enabled APs,
164        and releases the BSP to continue with other tasks.
165     -# The caller can use the CheckEvent() and WaitForEvent() services to check
166        the state of the WaitEvent created in step 1.
167     -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
168        Service signals WaitEvent by calling the EFI SignalEvent() function. If
169        FailedCpuList is not NULL, its content is available when WaitEvent is
170        signaled. If all APs returned from Procedure prior to the timeout, then
171        FailedCpuList is set to NULL. If not all APs return from Procedure before
172        the timeout, then FailedCpuList is filled in with the list of the failed
173        APs. The buffer is allocated by MP Service Protocol using AllocatePool().
174        It is the caller's responsibility to free the buffer with FreePool() service.
175     -# This invocation of SignalEvent() function informs the caller that invoked
176        EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
177        the specified task or a timeout occurred. The contents of FailedCpuList
178        can be examined to determine which APs did not complete the specified task
179        prior to the timeout.
180 
181   @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
182                                       instance.
183   @param[in]  Procedure               A pointer to the function to be run on
184                                       enabled APs of the system. See type
185                                       EFI_AP_PROCEDURE.
186   @param[in]  SingleThread            If TRUE, then all the enabled APs execute
187                                       the function specified by Procedure one by
188                                       one, in ascending order of processor handle
189                                       number.  If FALSE, then all the enabled APs
190                                       execute the function specified by Procedure
191                                       simultaneously.
192   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
193                                       service.  If it is NULL, then execute in
194                                       blocking mode. BSP waits until all APs finish
195                                       or TimeoutInMicroseconds expires.  If it's
196                                       not NULL, then execute in non-blocking mode.
197                                       BSP requests the function specified by
198                                       Procedure to be started on all the enabled
199                                       APs, and go on executing immediately. If
200                                       all return from Procedure, or TimeoutInMicroseconds
201                                       expires, this event is signaled. The BSP
202                                       can use the CheckEvent() or WaitForEvent()
203                                       services to check the state of event.  Type
204                                       EFI_EVENT is defined in CreateEvent() in
205                                       the Unified Extensible Firmware Interface
206                                       Specification.
207   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
208                                       APs to return from Procedure, either for
209                                       blocking or non-blocking mode. Zero means
210                                       infinity.  If the timeout expires before
211                                       all APs return from Procedure, then Procedure
212                                       on the failed APs is terminated. All enabled
213                                       APs are available for next function assigned
214                                       by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
215                                       or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
216                                       If the timeout expires in blocking mode,
217                                       BSP returns EFI_TIMEOUT.  If the timeout
218                                       expires in non-blocking mode, WaitEvent
219                                       is signaled with SignalEvent().
220   @param[in]  ProcedureArgument       The parameter passed into Procedure for
221                                       all APs.
222   @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
223                                       if all APs finish successfully, then its
224                                       content is set to NULL. If not all APs
225                                       finish before timeout expires, then its
226                                       content is set to address of the buffer
227                                       holding handle numbers of the failed APs.
228                                       The buffer is allocated by MP Service Protocol,
229                                       and it's the caller's responsibility to
230                                       free the buffer with FreePool() service.
231                                       In blocking mode, it is ready for consumption
232                                       when the call returns. In non-blocking mode,
233                                       it is ready when WaitEvent is signaled.  The
234                                       list of failed CPU is terminated by
235                                       END_OF_CPU_LIST.
236 
237   @retval EFI_SUCCESS             In blocking mode, all APs have finished before
238                                   the timeout expired.
239   @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
240                                   to all enabled APs.
241   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
242                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
243                                   signaled.
244   @retval EFI_DEVICE_ERROR        Caller processor is AP.
245   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
246   @retval EFI_NOT_READY           Any enabled APs are busy.
247   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
248                                   all enabled APs have finished.
249   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
250 
251 **/
252 EFI_STATUS
253 EFIAPI
StartupAllAPs(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)254 StartupAllAPs (
255   IN  EFI_MP_SERVICES_PROTOCOL  *This,
256   IN  EFI_AP_PROCEDURE          Procedure,
257   IN  BOOLEAN                   SingleThread,
258   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
259   IN  UINTN                     TimeoutInMicroseconds,
260   IN  VOID                      *ProcedureArgument      OPTIONAL,
261   OUT UINTN                     **FailedCpuList         OPTIONAL
262   )
263 {
264   return MpInitLibStartupAllAPs (
265            Procedure,
266            SingleThread,
267            WaitEvent,
268            TimeoutInMicroseconds,
269            ProcedureArgument,
270            FailedCpuList
271            );
272 }
273 
274 /**
275   This service lets the caller get one enabled AP to execute a caller-provided
276   function. The caller can request the BSP to either wait for the completion
277   of the AP or just proceed with the next task by using the EFI event mechanism.
278   See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
279   execution support.  This service may only be called from the BSP.
280 
281   This function is used to dispatch one enabled AP to the function specified by
282   Procedure passing in the argument specified by ProcedureArgument.  If WaitEvent
283   is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
284   TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
285   BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
286   is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
287   then EFI_UNSUPPORTED must be returned.
288 
289   If the timeout specified by TimeoutInMicroseconds expires before the AP returns
290   from Procedure, then execution of Procedure by the AP is terminated. The AP is
291   available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
292   EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
293 
294   @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
295                                       instance.
296   @param[in]  Procedure               A pointer to the function to be run on the
297                                       designated AP of the system. See type
298                                       EFI_AP_PROCEDURE.
299   @param[in]  ProcessorNumber         The handle number of the AP. The range is
300                                       from 0 to the total number of logical
301                                       processors minus 1. The total number of
302                                       logical processors can be retrieved by
303                                       EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
304   @param[in]  WaitEvent               The event created by the caller with CreateEvent()
305                                       service.  If it is NULL, then execute in
306                                       blocking mode. BSP waits until this AP finish
307                                       or TimeoutInMicroSeconds expires.  If it's
308                                       not NULL, then execute in non-blocking mode.
309                                       BSP requests the function specified by
310                                       Procedure to be started on this AP,
311                                       and go on executing immediately. If this AP
312                                       return from Procedure or TimeoutInMicroSeconds
313                                       expires, this event is signaled. The BSP
314                                       can use the CheckEvent() or WaitForEvent()
315                                       services to check the state of event.  Type
316                                       EFI_EVENT is defined in CreateEvent() in
317                                       the Unified Extensible Firmware Interface
318                                       Specification.
319   @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
320                                       this AP to finish this Procedure, either for
321                                       blocking or non-blocking mode. Zero means
322                                       infinity.  If the timeout expires before
323                                       this AP returns from Procedure, then Procedure
324                                       on the AP is terminated. The
325                                       AP is available for next function assigned
326                                       by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
327                                       or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
328                                       If the timeout expires in blocking mode,
329                                       BSP returns EFI_TIMEOUT.  If the timeout
330                                       expires in non-blocking mode, WaitEvent
331                                       is signaled with SignalEvent().
332   @param[in]  ProcedureArgument       The parameter passed into Procedure on the
333                                       specified AP.
334   @param[out] Finished                If NULL, this parameter is ignored.  In
335                                       blocking mode, this parameter is ignored.
336                                       In non-blocking mode, if AP returns from
337                                       Procedure before the timeout expires, its
338                                       content is set to TRUE. Otherwise, the
339                                       value is set to FALSE. The caller can
340                                       determine if the AP returned from Procedure
341                                       by evaluating this value.
342 
343   @retval EFI_SUCCESS             In blocking mode, specified AP finished before
344                                   the timeout expires.
345   @retval EFI_SUCCESS             In non-blocking mode, the function has been
346                                   dispatched to specified AP.
347   @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
348                                   UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
349                                   signaled.
350   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
351   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
352                                   the specified AP has finished.
353   @retval EFI_NOT_READY           The specified AP is busy.
354   @retval EFI_NOT_FOUND           The processor with the handle specified by
355                                   ProcessorNumber does not exist.
356   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
357   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
358 
359 **/
360 EFI_STATUS
361 EFIAPI
StartupThisAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)362 StartupThisAP (
363   IN  EFI_MP_SERVICES_PROTOCOL  *This,
364   IN  EFI_AP_PROCEDURE          Procedure,
365   IN  UINTN                     ProcessorNumber,
366   IN  EFI_EVENT                 WaitEvent               OPTIONAL,
367   IN  UINTN                     TimeoutInMicroseconds,
368   IN  VOID                      *ProcedureArgument      OPTIONAL,
369   OUT BOOLEAN                   *Finished               OPTIONAL
370   )
371 {
372   return MpInitLibStartupThisAP (
373            Procedure,
374            ProcessorNumber,
375            WaitEvent,
376            TimeoutInMicroseconds,
377            ProcedureArgument,
378            Finished
379            );
380 }
381 
382 /**
383   This service switches the requested AP to be the BSP from that point onward.
384   This service changes the BSP for all purposes.   This call can only be performed
385   by the current BSP.
386 
387   This service switches the requested AP to be the BSP from that point onward.
388   This service changes the BSP for all purposes. The new BSP can take over the
389   execution of the old BSP and continue seamlessly from where the old one left
390   off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
391   is signaled.
392 
393   If the BSP cannot be switched prior to the return from this service, then
394   EFI_UNSUPPORTED must be returned.
395 
396   @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
397   @param[in] ProcessorNumber   The handle number of AP that is to become the new
398                                BSP. The range is from 0 to the total number of
399                                logical processors minus 1. The total number of
400                                logical processors can be retrieved by
401                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
402   @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
403                                enabled AP. Otherwise, it will be disabled.
404 
405   @retval EFI_SUCCESS             BSP successfully switched.
406   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
407                                   this service returning.
408   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
409   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
410   @retval EFI_NOT_FOUND           The processor with the handle specified by
411                                   ProcessorNumber does not exist.
412   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
413                                   a disabled AP.
414   @retval EFI_NOT_READY           The specified AP is busy.
415 
416 **/
417 EFI_STATUS
418 EFIAPI
SwitchBSP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)419 SwitchBSP (
420   IN EFI_MP_SERVICES_PROTOCOL  *This,
421   IN  UINTN                    ProcessorNumber,
422   IN  BOOLEAN                  EnableOldBSP
423   )
424 {
425   return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
426 }
427 
428 /**
429   This service lets the caller enable or disable an AP from this point onward.
430   This service may only be called from the BSP.
431 
432   This service allows the caller enable or disable an AP from this point onward.
433   The caller can optionally specify the health status of the AP by Health. If
434   an AP is being disabled, then the state of the disabled AP is implementation
435   dependent. If an AP is enabled, then the implementation must guarantee that a
436   complete initialization sequence is performed on the AP, so the AP is in a state
437   that is compatible with an MP operating system. This service may not be supported
438   after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
439 
440   If the enable or disable AP operation cannot be completed prior to the return
441   from this service, then EFI_UNSUPPORTED must be returned.
442 
443   @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
444   @param[in] ProcessorNumber   The handle number of AP.
445                                The range is from 0 to the total number of
446                                logical processors minus 1. The total number of
447                                logical processors can be retrieved by
448                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
449   @param[in] EnableAP          Specifies the new state for the processor for
450                                enabled, FALSE for disabled.
451   @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
452                                the new health status of the AP. This flag
453                                corresponds to StatusFlag defined in
454                                EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
455                                the PROCESSOR_HEALTH_STATUS_BIT is used. All other
456                                bits are ignored.  If it is NULL, this parameter
457                                is ignored.
458 
459   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
460   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
461                                   prior to this service returning.
462   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
463   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
464   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
465                                   does not exist.
466   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
467 
468 **/
469 EFI_STATUS
470 EFIAPI
EnableDisableAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)471 EnableDisableAP (
472   IN  EFI_MP_SERVICES_PROTOCOL  *This,
473   IN  UINTN                     ProcessorNumber,
474   IN  BOOLEAN                   EnableAP,
475   IN  UINT32                    *HealthFlag OPTIONAL
476   )
477 {
478   return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
479 }
480 
481 /**
482   This return the handle number for the calling processor.  This service may be
483   called from the BSP and APs.
484 
485   This service returns the processor handle number for the calling processor.
486   The returned value is in the range from 0 to the total number of logical
487   processors minus 1. The total number of logical processors can be retrieved
488   with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
489   called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
490   is returned. Otherwise, the current processors handle number is returned in
491   ProcessorNumber, and EFI_SUCCESS is returned.
492 
493   @param[in]  This             A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
494   @param[out] ProcessorNumber  Pointer to the handle number of AP.
495                                The range is from 0 to the total number of
496                                logical processors minus 1. The total number of
497                                logical processors can be retrieved by
498                                EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
499 
500   @retval EFI_SUCCESS             The current processor handle number was returned
501                                   in ProcessorNumber.
502   @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
503 
504 **/
505 EFI_STATUS
506 EFIAPI
WhoAmI(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * ProcessorNumber)507 WhoAmI (
508   IN EFI_MP_SERVICES_PROTOCOL  *This,
509   OUT UINTN                    *ProcessorNumber
510   )
511 {
512   return MpInitLibWhoAmI (ProcessorNumber);;
513 }
514 
515 /**
516   Collects BIST data from HOB.
517 
518   This function collects BIST data from HOB built from Sec Platform Information
519   PPI or SEC Platform Information2 PPI.
520 
521 **/
522 VOID
CollectBistDataFromHob(VOID)523 CollectBistDataFromHob (
524   VOID
525   )
526 {
527   EFI_HOB_GUID_TYPE                     *GuidHob;
528   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
529   EFI_SEC_PLATFORM_INFORMATION_RECORD   *SecPlatformInformation;
530   UINTN                                 NumberOfData;
531   EFI_SEC_PLATFORM_INFORMATION_CPU      *CpuInstance;
532   EFI_SEC_PLATFORM_INFORMATION_CPU      BspCpuInstance;
533   UINTN                                 ProcessorNumber;
534   EFI_PROCESSOR_INFORMATION             ProcessorInfo;
535   EFI_HEALTH_FLAGS                      BistData;
536   UINTN                                 CpuInstanceNumber;
537 
538   SecPlatformInformation2 = NULL;
539   SecPlatformInformation  = NULL;
540 
541   //
542   // Get gEfiSecPlatformInformation2PpiGuid Guided HOB firstly
543   //
544   GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid);
545   if (GuidHob != NULL) {
546     //
547     // Sec Platform Information2 PPI includes BSP/APs' BIST information
548     //
549     SecPlatformInformation2 = GET_GUID_HOB_DATA (GuidHob);
550     NumberOfData = SecPlatformInformation2->NumberOfCpus;
551     CpuInstance  = SecPlatformInformation2->CpuInstance;
552   } else {
553     //
554     // Otherwise, get gEfiSecPlatformInformationPpiGuid Guided HOB
555     //
556     GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);
557     if (GuidHob != NULL) {
558       SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);
559       NumberOfData = 1;
560       //
561       // SEC Platform Information only includes BSP's BIST information
562       // does not have BSP's APIC ID
563       //
564       BspCpuInstance.CpuLocation = GetApicId ();
565       BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32  = SecPlatformInformation->IA32HealthFlags.Uint32;
566       CpuInstance = &BspCpuInstance;
567     } else {
568       DEBUG ((DEBUG_INFO, "Does not find any HOB stored CPU BIST information!\n"));
569       //
570       // Does not find any HOB stored BIST information
571       //
572       return;
573     }
574   }
575 
576   for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {
577     MpInitLibGetProcessorInfo (ProcessorNumber, &ProcessorInfo, &BistData);
578     for (CpuInstanceNumber = 0; CpuInstanceNumber < NumberOfData; CpuInstanceNumber++) {
579       if (ProcessorInfo.ProcessorId == CpuInstance[CpuInstanceNumber].CpuLocation) {
580         //
581         // Update CPU health status for MP Services Protocol according to BIST data.
582         //
583         BistData = CpuInstance[CpuInstanceNumber].InfoRecord.IA32HealthFlags;
584       }
585     }
586     if (BistData.Uint32 != 0) {
587       //
588       // Report Status Code that self test is failed
589       //
590       REPORT_STATUS_CODE (
591         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
592         (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
593         );
594     }
595   }
596 }
597 
598 /**
599   Get GDT register value.
600 
601   This function is mainly for AP purpose because AP may have different GDT
602   table than BSP.
603 
604   @param[in,out] Buffer  The pointer to private data buffer.
605 
606 **/
607 VOID
608 EFIAPI
GetGdtr(IN OUT VOID * Buffer)609 GetGdtr (
610   IN OUT VOID *Buffer
611   )
612 {
613   AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);
614 }
615 
616 /**
617   Initializes CPU exceptions handlers for the sake of stack switch requirement.
618 
619   This function is a wrapper of InitializeCpuExceptionHandlersEx. It's mainly
620   for the sake of AP's init because of EFI_AP_PROCEDURE API requirement.
621 
622   @param[in,out] Buffer  The pointer to private data buffer.
623 
624 **/
625 VOID
626 EFIAPI
InitializeExceptionStackSwitchHandlers(IN OUT VOID * Buffer)627 InitializeExceptionStackSwitchHandlers (
628   IN OUT VOID *Buffer
629   )
630 {
631   CPU_EXCEPTION_INIT_DATA           *EssData;
632   IA32_DESCRIPTOR                   Idtr;
633   EFI_STATUS                        Status;
634 
635   EssData = Buffer;
636   //
637   // We don't plan to replace IDT table with a new one, but we should not assume
638   // the AP's IDT is the same as BSP's IDT either.
639   //
640   AsmReadIdtr (&Idtr);
641   EssData->Ia32.IdtTable = (VOID *)Idtr.Base;
642   EssData->Ia32.IdtTableSize = Idtr.Limit + 1;
643   Status = InitializeCpuExceptionHandlersEx (NULL, EssData);
644   ASSERT_EFI_ERROR (Status);
645 }
646 
647 /**
648   Initializes MP exceptions handlers for the sake of stack switch requirement.
649 
650   This function will allocate required resources required to setup stack switch
651   and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.
652 
653 **/
654 VOID
InitializeMpExceptionStackSwitchHandlers(VOID)655 InitializeMpExceptionStackSwitchHandlers (
656   VOID
657   )
658 {
659   UINTN                           Index;
660   UINTN                           Bsp;
661   UINTN                           ExceptionNumber;
662   UINTN                           OldGdtSize;
663   UINTN                           NewGdtSize;
664   UINTN                           NewStackSize;
665   IA32_DESCRIPTOR                 Gdtr;
666   CPU_EXCEPTION_INIT_DATA         EssData;
667   UINT8                           *GdtBuffer;
668   UINT8                           *StackTop;
669 
670   ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
671   NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;
672 
673   StackTop = AllocateRuntimeZeroPool (NewStackSize * mNumberOfProcessors);
674   ASSERT (StackTop != NULL);
675   StackTop += NewStackSize  * mNumberOfProcessors;
676 
677   //
678   // The default exception handlers must have been initialized. Let's just skip
679   // it in this method.
680   //
681   EssData.Ia32.Revision = CPU_EXCEPTION_INIT_DATA_REV;
682   EssData.Ia32.InitDefaultHandlers = FALSE;
683 
684   EssData.Ia32.StackSwitchExceptions = FixedPcdGetPtr(PcdCpuStackSwitchExceptionList);
685   EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;
686   EssData.Ia32.KnownGoodStackSize = FixedPcdGet32(PcdCpuKnownGoodStackSize);
687 
688   //
689   // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.
690   //
691   Gdtr.Base = 0;
692   Gdtr.Limit = 0;
693   MpInitLibWhoAmI (&Bsp);
694   for (Index = 0; Index < mNumberOfProcessors; ++Index) {
695     //
696     // To support stack switch, we need to re-construct GDT but not IDT.
697     //
698     if (Index == Bsp) {
699       GetGdtr (&Gdtr);
700     } else {
701       //
702       // AP might have different size of GDT from BSP.
703       //
704       MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);
705     }
706 
707     //
708     // X64 needs only one TSS of current task working for all exceptions
709     // because of its IST feature. IA32 needs one TSS for each exception
710     // in addition to current task. Since AP is not supposed to allocate
711     // memory, we have to do it in BSP. To simplify the code, we allocate
712     // memory for IA32 case to cover both IA32 and X64 exception stack
713     // switch.
714     //
715     // Layout of memory to allocate for each processor:
716     //    --------------------------------
717     //    |            Alignment         |  (just in case)
718     //    --------------------------------
719     //    |                              |
720     //    |        Original GDT          |
721     //    |                              |
722     //    --------------------------------
723     //    |    Current task descriptor   |
724     //    --------------------------------
725     //    |                              |
726     //    |  Exception task descriptors  |  X ExceptionNumber
727     //    |                              |
728     //    --------------------------------
729     //    |  Current task-state segment  |
730     //    --------------------------------
731     //    |                              |
732     //    | Exception task-state segment |  X ExceptionNumber
733     //    |                              |
734     //    --------------------------------
735     //
736     OldGdtSize = Gdtr.Limit + 1;
737     EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *
738                                         (ExceptionNumber + 1);
739     EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *
740                                     (ExceptionNumber + 1);
741     NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +
742                  OldGdtSize +
743                  EssData.Ia32.ExceptionTssDescSize +
744                  EssData.Ia32.ExceptionTssSize;
745 
746     GdtBuffer = AllocateRuntimeZeroPool (NewGdtSize);
747     ASSERT (GdtBuffer != NULL);
748 
749     //
750     // Make sure GDT table alignment
751     //
752     EssData.Ia32.GdtTable = ALIGN_POINTER(GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));
753     NewGdtSize -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);
754     EssData.Ia32.GdtTableSize = NewGdtSize;
755 
756     EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);
757     EssData.Ia32.ExceptionTss = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +
758                                  EssData.Ia32.ExceptionTssDescSize);
759 
760     EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;
761     DEBUG ((DEBUG_INFO,
762             "Exception stack top[cpu%lu]: 0x%lX\n",
763             (UINT64)(UINTN)Index,
764             (UINT64)(UINTN)StackTop));
765 
766     if (Index == Bsp) {
767       InitializeExceptionStackSwitchHandlers (&EssData);
768     } else {
769       MpInitLibStartupThisAP (
770         InitializeExceptionStackSwitchHandlers,
771         Index,
772         NULL,
773         0,
774         (VOID *)&EssData,
775         NULL
776         );
777     }
778 
779     StackTop  -= NewStackSize;
780   }
781 }
782 
783 /**
784   Initializes MP exceptions handlers for special features, such as Heap Guard
785   and Stack Guard.
786 **/
787 VOID
InitializeMpExceptionHandlers(VOID)788 InitializeMpExceptionHandlers (
789   VOID
790   )
791 {
792   //
793   // Enable non-stop mode for #PF triggered by Heap Guard or NULL Pointer
794   // Detection.
795   //
796   if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {
797     RegisterCpuInterruptHandler (EXCEPT_IA32_DEBUG, DebugExceptionHandler);
798     RegisterCpuInterruptHandler (EXCEPT_IA32_PAGE_FAULT, PageFaultExceptionHandler);
799   }
800 
801   //
802   // Setup stack switch for Stack Guard feature.
803   //
804   if (PcdGetBool (PcdCpuStackGuard)) {
805     InitializeMpExceptionStackSwitchHandlers ();
806   }
807 }
808 
809 /**
810   Initialize Multi-processor support.
811 
812 **/
813 VOID
InitializeMpSupport(VOID)814 InitializeMpSupport (
815   VOID
816   )
817 {
818   EFI_STATUS     Status;
819   UINTN          NumberOfProcessors;
820   UINTN          NumberOfEnabledProcessors;
821 
822   //
823   // Wakeup APs to do initialization
824   //
825   Status = MpInitLibInitialize ();
826   ASSERT_EFI_ERROR (Status);
827 
828   MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
829   mNumberOfProcessors = NumberOfProcessors;
830   DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
831 
832   //
833   // Initialize special exception handlers for each logic processor.
834   //
835   InitializeMpExceptionHandlers ();
836 
837   //
838   // Update CPU healthy information from Guided HOB
839   //
840   CollectBistDataFromHob ();
841 
842   Status = gBS->InstallMultipleProtocolInterfaces (
843                   &mMpServiceHandle,
844                   &gEfiMpServiceProtocolGuid,  &mMpServicesTemplate,
845                   NULL
846                   );
847   ASSERT_EFI_ERROR (Status);
848 }
849 
850