1 /** @file
2   CPU PEI Module installs CPU Multiple Processor PPI.
3 
4   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "CpuMpPei.h"
16 
17 //
18 // CPU MP PPI to be installed
19 //
20 EFI_PEI_MP_SERVICES_PPI                mMpServicesPpi = {
21   PeiGetNumberOfProcessors,
22   PeiGetProcessorInfo,
23   PeiStartupAllAPs,
24   PeiStartupThisAP,
25   PeiSwitchBSP,
26   PeiEnableDisableAP,
27   PeiWhoAmI,
28 };
29 
30 EFI_PEI_PPI_DESCRIPTOR           mPeiCpuMpPpiDesc = {
31   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
32   &gEfiPeiMpServicesPpiGuid,
33   &mMpServicesPpi
34 };
35 
36 /**
37   This service retrieves the number of logical processor in the platform
38   and the number of those logical processors that are enabled on this boot.
39   This service may only be called from the BSP.
40 
41   This function is used to retrieve the following information:
42     - The number of logical processors that are present in the system.
43     - The number of enabled logical processors in the system at the instant
44       this call is made.
45 
46   Because MP Service Ppi provides services to enable and disable processors
47   dynamically, the number of enabled logical processors may vary during the
48   course of a boot session.
49 
50   If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
51   If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
52   EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
53   is returned in NumberOfProcessors, the number of currently enabled processor
54   is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
55 
56   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
57                                   published by the PEI Foundation.
58   @param[in]  This                Pointer to this instance of the PPI.
59   @param[out] NumberOfProcessors  Pointer to the total number of logical processors in
60                                   the system, including the BSP and disabled APs.
61   @param[out] NumberOfEnabledProcessors
62                                   Number of processors in the system that are enabled.
63 
64   @retval EFI_SUCCESS             The number of logical processors and enabled
65                                   logical processors was retrieved.
66   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
67   @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
68                                   NumberOfEnabledProcessors is NULL.
69 **/
70 EFI_STATUS
71 EFIAPI
PeiGetNumberOfProcessors(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,OUT UINTN * NumberOfProcessors,OUT UINTN * NumberOfEnabledProcessors)72 PeiGetNumberOfProcessors (
73   IN  CONST EFI_PEI_SERVICES    **PeiServices,
74   IN  EFI_PEI_MP_SERVICES_PPI   *This,
75   OUT UINTN                     *NumberOfProcessors,
76   OUT UINTN                     *NumberOfEnabledProcessors
77   )
78 {
79   if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
80     return EFI_INVALID_PARAMETER;
81   }
82 
83   return MpInitLibGetNumberOfProcessors (
84            NumberOfProcessors,
85            NumberOfEnabledProcessors
86            );
87 }
88 
89 /**
90   Gets detailed MP-related information on the requested processor at the
91   instant this call is made. This service may only be called from the BSP.
92 
93   This service retrieves detailed MP-related information about any processor
94   on the platform. Note the following:
95     - The processor information may change during the course of a boot session.
96     - The information presented here is entirely MP related.
97 
98   Information regarding the number of caches and their sizes, frequency of operation,
99   slot numbers is all considered platform-related information and is not provided
100   by this service.
101 
102   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
103                                   published by the PEI Foundation.
104   @param[in]  This                Pointer to this instance of the PPI.
105   @param[in]  ProcessorNumber     Pointer to the total number of logical processors in
106                                   the system, including the BSP and disabled APs.
107   @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled.
108 
109   @retval EFI_SUCCESS             Processor information was returned.
110   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
111   @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
112   @retval EFI_NOT_FOUND           The processor with the handle specified by
113                                   ProcessorNumber does not exist in the platform.
114 **/
115 EFI_STATUS
116 EFIAPI
PeiGetProcessorInfo(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN UINTN ProcessorNumber,OUT EFI_PROCESSOR_INFORMATION * ProcessorInfoBuffer)117 PeiGetProcessorInfo (
118   IN  CONST EFI_PEI_SERVICES     **PeiServices,
119   IN  EFI_PEI_MP_SERVICES_PPI    *This,
120   IN  UINTN                      ProcessorNumber,
121   OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
122   )
123 {
124   return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
125 }
126 
127 /**
128   This service executes a caller provided function on all enabled APs. APs can
129   run either simultaneously or one at a time in sequence. This service supports
130   both blocking requests only. This service may only
131   be called from the BSP.
132 
133   This function is used to dispatch all the enabled APs to the function specified
134   by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
135   immediately and Procedure is not started on any AP.
136 
137   If SingleThread is TRUE, all the enabled APs execute the function specified by
138   Procedure one by one, in ascending order of processor handle number. Otherwise,
139   all the enabled APs execute the function specified by Procedure simultaneously.
140 
141   If the timeout specified by TimeoutInMicroSeconds expires before all APs return
142   from Procedure, then Procedure on the failed APs is terminated. All enabled APs
143   are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
144   and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
145   content points to the list of processor handle numbers in which Procedure was
146   terminated.
147 
148   Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
149   to make sure that the nature of the code that is executed on the BSP and the
150   dispatched APs is well controlled. The MP Services Ppi does not guarantee
151   that the Procedure function is MP-safe. Hence, the tasks that can be run in
152   parallel are limited to certain independent tasks and well-controlled exclusive
153   code. PEI services and Ppis may not be called by APs unless otherwise
154   specified.
155 
156   In blocking execution mode, BSP waits until all APs finish or
157   TimeoutInMicroSeconds expires.
158 
159   @param[in] PeiServices          An indirect pointer to the PEI Services Table
160                                   published by the PEI Foundation.
161   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
162   @param[in] Procedure            A pointer to the function to be run on enabled APs of
163                                   the system.
164   @param[in] SingleThread         If TRUE, then all the enabled APs execute the function
165                                   specified by Procedure one by one, in ascending order
166                                   of processor handle number. If FALSE, then all the
167                                   enabled APs execute the function specified by Procedure
168                                   simultaneously.
169   @param[in] TimeoutInMicroSeconds
170                                   Indicates the time limit in microseconds for APs to
171                                   return from Procedure, for blocking mode only. Zero
172                                   means infinity. If the timeout expires before all APs
173                                   return from Procedure, then Procedure on the failed APs
174                                   is terminated. All enabled APs are available for next
175                                   function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
176                                   or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
177                                   timeout expires in blocking mode, BSP returns
178                                   EFI_TIMEOUT.
179   @param[in] ProcedureArgument    The parameter passed into Procedure for all APs.
180 
181   @retval EFI_SUCCESS             In blocking mode, all APs have finished before the
182                                   timeout expired.
183   @retval EFI_DEVICE_ERROR        Caller processor is AP.
184   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
185   @retval EFI_NOT_READY           Any enabled APs are busy.
186   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before all
187                                   enabled APs have finished.
188   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
189 **/
190 EFI_STATUS
191 EFIAPI
PeiStartupAllAPs(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN UINTN TimeoutInMicroSeconds,IN VOID * ProcedureArgument OPTIONAL)192 PeiStartupAllAPs (
193   IN  CONST EFI_PEI_SERVICES    **PeiServices,
194   IN  EFI_PEI_MP_SERVICES_PPI   *This,
195   IN  EFI_AP_PROCEDURE          Procedure,
196   IN  BOOLEAN                   SingleThread,
197   IN  UINTN                     TimeoutInMicroSeconds,
198   IN  VOID                      *ProcedureArgument      OPTIONAL
199   )
200 {
201   return MpInitLibStartupAllAPs (
202            Procedure,
203            SingleThread,
204            NULL,
205            TimeoutInMicroSeconds,
206            ProcedureArgument,
207            NULL
208            );
209 }
210 
211 /**
212   This service lets the caller get one enabled AP to execute a caller-provided
213   function. The caller can request the BSP to wait for the completion
214   of the AP. This service may only be called from the BSP.
215 
216   This function is used to dispatch one enabled AP to the function specified by
217   Procedure passing in the argument specified by ProcedureArgument.
218   The execution is in blocking mode. The BSP waits until the AP finishes or
219   TimeoutInMicroSecondss expires.
220 
221   If the timeout specified by TimeoutInMicroseconds expires before the AP returns
222   from Procedure, then execution of Procedure by the AP is terminated. The AP is
223   available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
224   EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
225 
226   @param[in] PeiServices          An indirect pointer to the PEI Services Table
227                                   published by the PEI Foundation.
228   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
229   @param[in] Procedure            A pointer to the function to be run on enabled APs of
230                                   the system.
231   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
232                                   total number of logical processors minus 1. The total
233                                   number of logical processors can be retrieved by
234                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
235   @param[in] TimeoutInMicroseconds
236                                   Indicates the time limit in microseconds for APs to
237                                   return from Procedure, for blocking mode only. Zero
238                                   means infinity. If the timeout expires before all APs
239                                   return from Procedure, then Procedure on the failed APs
240                                   is terminated. All enabled APs are available for next
241                                   function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
242                                   or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
243                                   timeout expires in blocking mode, BSP returns
244                                   EFI_TIMEOUT.
245   @param[in] ProcedureArgument    The parameter passed into Procedure for all APs.
246 
247   @retval EFI_SUCCESS             In blocking mode, specified AP finished before the
248                                   timeout expires.
249   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
250   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before the
251                                   specified AP has finished.
252   @retval EFI_NOT_FOUND           The processor with the handle specified by
253                                   ProcessorNumber does not exist.
254   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
255   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
256 **/
257 EFI_STATUS
258 EFIAPI
PeiStartupThisAP(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL)259 PeiStartupThisAP (
260   IN  CONST EFI_PEI_SERVICES    **PeiServices,
261   IN  EFI_PEI_MP_SERVICES_PPI   *This,
262   IN  EFI_AP_PROCEDURE          Procedure,
263   IN  UINTN                     ProcessorNumber,
264   IN  UINTN                     TimeoutInMicroseconds,
265   IN  VOID                      *ProcedureArgument      OPTIONAL
266   )
267 {
268   return MpInitLibStartupThisAP (
269            Procedure,
270            ProcessorNumber,
271            NULL,
272            TimeoutInMicroseconds,
273            ProcedureArgument,
274            NULL
275            );
276 }
277 
278 /**
279   This service switches the requested AP to be the BSP from that point onward.
280   This service changes the BSP for all purposes.   This call can only be performed
281   by the current BSP.
282 
283   This service switches the requested AP to be the BSP from that point onward.
284   This service changes the BSP for all purposes. The new BSP can take over the
285   execution of the old BSP and continue seamlessly from where the old one left
286   off.
287 
288   If the BSP cannot be switched prior to the return from this service, then
289   EFI_UNSUPPORTED must be returned.
290 
291   @param[in] PeiServices          An indirect pointer to the PEI Services Table
292                                   published by the PEI Foundation.
293   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
294   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
295                                   total number of logical processors minus 1. The total
296                                   number of logical processors can be retrieved by
297                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
298   @param[in] EnableOldBSP         If TRUE, then the old BSP will be listed as an enabled
299                                   AP. Otherwise, it will be disabled.
300 
301   @retval EFI_SUCCESS             BSP successfully switched.
302   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to this
303                                   service returning.
304   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
305   @retval EFI_SUCCESS             The calling processor is an AP.
306   @retval EFI_NOT_FOUND           The processor with the handle specified by
307                                   ProcessorNumber does not exist.
308   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or a disabled
309                                   AP.
310   @retval EFI_NOT_READY           The specified AP is busy.
311 **/
312 EFI_STATUS
313 EFIAPI
PeiSwitchBSP(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)314 PeiSwitchBSP (
315   IN  CONST EFI_PEI_SERVICES   **PeiServices,
316   IN  EFI_PEI_MP_SERVICES_PPI  *This,
317   IN  UINTN                    ProcessorNumber,
318   IN  BOOLEAN                  EnableOldBSP
319   )
320 {
321   return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
322 }
323 
324 /**
325   This service lets the caller enable or disable an AP from this point onward.
326   This service may only be called from the BSP.
327 
328   This service allows the caller enable or disable an AP from this point onward.
329   The caller can optionally specify the health status of the AP by Health. If
330   an AP is being disabled, then the state of the disabled AP is implementation
331   dependent. If an AP is enabled, then the implementation must guarantee that a
332   complete initialization sequence is performed on the AP, so the AP is in a state
333   that is compatible with an MP operating system.
334 
335   If the enable or disable AP operation cannot be completed prior to the return
336   from this service, then EFI_UNSUPPORTED must be returned.
337 
338   @param[in] PeiServices          An indirect pointer to the PEI Services Table
339                                   published by the PEI Foundation.
340   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
341   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
342                                   total number of logical processors minus 1. The total
343                                   number of logical processors can be retrieved by
344                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
345   @param[in] EnableAP             Specifies the new state for the processor for enabled,
346                                   FALSE for disabled.
347   @param[in] HealthFlag           If not NULL, a pointer to a value that specifies the
348                                   new health status of the AP. This flag corresponds to
349                                   StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo().
350                                   Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other
351                                   bits are ignored. If it is NULL, this parameter is
352                                   ignored.
353 
354   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
355   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed prior
356                                   to this service returning.
357   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
358   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
359   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
360                                   does not exist.
361   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
362 **/
363 EFI_STATUS
364 EFIAPI
PeiEnableDisableAP(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)365 PeiEnableDisableAP (
366   IN  CONST EFI_PEI_SERVICES    **PeiServices,
367   IN  EFI_PEI_MP_SERVICES_PPI   *This,
368   IN  UINTN                     ProcessorNumber,
369   IN  BOOLEAN                   EnableAP,
370   IN  UINT32                    *HealthFlag OPTIONAL
371   )
372 {
373   return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
374 }
375 
376 /**
377   This return the handle number for the calling processor.  This service may be
378   called from the BSP and APs.
379 
380   This service returns the processor handle number for the calling processor.
381   The returned value is in the range from 0 to the total number of logical
382   processors minus 1. The total number of logical processors can be retrieved
383   with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
384   called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
385   is returned. Otherwise, the current processors handle number is returned in
386   ProcessorNumber, and EFI_SUCCESS is returned.
387 
388   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
389                                   published by the PEI Foundation.
390   @param[in]  This                A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
391   @param[out] ProcessorNumber     The handle number of the AP. The range is from 0 to the
392                                   total number of logical processors minus 1. The total
393                                   number of logical processors can be retrieved by
394                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
395 
396   @retval EFI_SUCCESS             The current processor handle number was returned in
397                                   ProcessorNumber.
398   @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
399 **/
400 EFI_STATUS
401 EFIAPI
PeiWhoAmI(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,OUT UINTN * ProcessorNumber)402 PeiWhoAmI (
403   IN  CONST EFI_PEI_SERVICES   **PeiServices,
404   IN  EFI_PEI_MP_SERVICES_PPI  *This,
405   OUT UINTN                    *ProcessorNumber
406   )
407 {
408   return MpInitLibWhoAmI (ProcessorNumber);
409 }
410 
411 /**
412   The Entry point of the MP CPU PEIM.
413 
414   This function will wakeup APs and collect CPU AP count and install the
415   Mp Service Ppi.
416 
417   @param  FileHandle    Handle of the file being invoked.
418   @param  PeiServices   Describes the list of possible PEI Services.
419 
420   @retval EFI_SUCCESS   MpServicePpi is installed successfully.
421 
422 **/
423 EFI_STATUS
424 EFIAPI
CpuMpPeimInit(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)425 CpuMpPeimInit (
426   IN       EFI_PEI_FILE_HANDLE  FileHandle,
427   IN CONST EFI_PEI_SERVICES     **PeiServices
428   )
429 {
430   EFI_STATUS           Status;
431   EFI_VECTOR_HANDOFF_INFO         *VectorInfo;
432   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
433 
434   //
435   // Get Vector Hand-off Info PPI
436   //
437   VectorInfo = NULL;
438   Status = PeiServicesLocatePpi (
439              &gEfiVectorHandoffInfoPpiGuid,
440              0,
441              NULL,
442              (VOID **)&VectorHandoffInfoPpi
443              );
444   if (Status == EFI_SUCCESS) {
445     VectorInfo = VectorHandoffInfoPpi->Info;
446   }
447   Status = InitializeCpuExceptionHandlers (VectorInfo);
448   ASSERT_EFI_ERROR (Status);
449 
450   //
451   // Wakeup APs to do initialization
452   //
453   Status = MpInitLibInitialize ();
454   ASSERT_EFI_ERROR (Status);
455 
456   //
457   // Update and publish CPU BIST information
458   //
459   CollectBistDataFromPpi (PeiServices);
460 
461   //
462   // Install CPU MP PPI
463   //
464   Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
465   ASSERT_EFI_ERROR (Status);
466 
467   return Status;
468 }
469