1 /** @file
2   Implementation of Multiple Processor PPI services.
3 
4   Copyright (c) 2015, 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 "PeiMpServices.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   Get CPU Package/Core/Thread location information.
38 
39   @param InitialApicId     CPU APIC ID
40   @param Location          Pointer to CPU location information
41 **/
42 VOID
ExtractProcessorLocation(IN UINT32 InitialApicId,OUT EFI_CPU_PHYSICAL_LOCATION * Location)43 ExtractProcessorLocation (
44   IN  UINT32                     InitialApicId,
45   OUT EFI_CPU_PHYSICAL_LOCATION  *Location
46   )
47 {
48   BOOLEAN  TopologyLeafSupported;
49   UINTN    ThreadBits;
50   UINTN    CoreBits;
51   UINT32   RegEax;
52   UINT32   RegEbx;
53   UINT32   RegEcx;
54   UINT32   RegEdx;
55   UINT32   MaxCpuIdIndex;
56   UINT32   SubIndex;
57   UINTN    LevelType;
58   UINT32   MaxLogicProcessorsPerPackage;
59   UINT32   MaxCoresPerPackage;
60 
61   //
62   // Check if the processor is capable of supporting more than one logical processor.
63   //
64   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
65   if ((RegEdx & BIT28) == 0) {
66     Location->Thread  = 0;
67     Location->Core    = 0;
68     Location->Package = 0;
69     return;
70   }
71 
72   ThreadBits = 0;
73   CoreBits = 0;
74 
75   //
76   // Assume three-level mapping of APIC ID: Package:Core:SMT.
77   //
78 
79   TopologyLeafSupported = FALSE;
80   //
81   // Get the max index of basic CPUID
82   //
83   AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
84 
85   //
86   // If the extended topology enumeration leaf is available, it
87   // is the preferred mechanism for enumerating topology.
88   //
89   if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
90     AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL);
91     //
92     // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
93     // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
94     // supported on that processor.
95     //
96     if (RegEbx != 0) {
97       TopologyLeafSupported = TRUE;
98 
99       //
100       // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
101       // the SMT sub-field of x2APIC ID.
102       //
103       LevelType = (RegEcx >> 8) & 0xff;
104       ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
105       ThreadBits = RegEax & 0x1f;
106 
107       //
108       // Software must not assume any "level type" encoding
109       // value to be related to any sub-leaf index, except sub-leaf 0.
110       //
111       SubIndex = 1;
112       do {
113         AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
114         LevelType = (RegEcx >> 8) & 0xff;
115         if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
116           CoreBits = (RegEax & 0x1f) - ThreadBits;
117           break;
118         }
119         SubIndex++;
120       } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
121     }
122   }
123 
124   if (!TopologyLeafSupported) {
125     AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
126     MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
127     if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
128       AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
129       MaxCoresPerPackage = (RegEax >> 26) + 1;
130     } else {
131       //
132       // Must be a single-core processor.
133       //
134       MaxCoresPerPackage = 1;
135     }
136 
137     ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
138     CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
139   }
140 
141   Location->Thread  = InitialApicId & ~((-1) << ThreadBits);
142   Location->Core    = (InitialApicId >> ThreadBits) & ~((-1) << CoreBits);
143   Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
144 }
145 
146 /**
147   Find the current Processor number by APIC ID.
148 
149   @param PeiCpuMpData        Pointer to PEI CPU MP Data
150   @param ProcessorNumber     Return the pocessor number found
151 
152   @retval EFI_SUCCESS        ProcessorNumber is found and returned.
153   @retval EFI_NOT_FOUND      ProcessorNumber is not found.
154 **/
155 EFI_STATUS
GetProcessorNumber(IN PEI_CPU_MP_DATA * PeiCpuMpData,OUT UINTN * ProcessorNumber)156 GetProcessorNumber (
157   IN PEI_CPU_MP_DATA         *PeiCpuMpData,
158   OUT UINTN                  *ProcessorNumber
159   )
160 {
161   UINTN                   TotalProcessorNumber;
162   UINTN                   Index;
163 
164   TotalProcessorNumber = PeiCpuMpData->CpuCount;
165   for (Index = 0; Index < TotalProcessorNumber; Index ++) {
166     if (PeiCpuMpData->CpuData[Index].ApicId == GetInitialApicId ()) {
167       *ProcessorNumber = Index;
168       return EFI_SUCCESS;
169     }
170   }
171   return EFI_NOT_FOUND;
172 }
173 
174 /**
175   Worker function for SwitchBSP().
176 
177   Worker function for SwitchBSP(), assigned to the AP which is intended to become BSP.
178 
179   @param Buffer        Pointer to CPU MP Data
180 **/
181 VOID
182 EFIAPI
FutureBSPProc(IN VOID * Buffer)183 FutureBSPProc (
184   IN  VOID                *Buffer
185   )
186 {
187   PEI_CPU_MP_DATA         *DataInHob;
188 
189   DataInHob = (PEI_CPU_MP_DATA *) Buffer;
190   AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
191 }
192 
193 /**
194   This service retrieves the number of logical processor in the platform
195   and the number of those logical processors that are enabled on this boot.
196   This service may only be called from the BSP.
197 
198   This function is used to retrieve the following information:
199     - The number of logical processors that are present in the system.
200     - The number of enabled logical processors in the system at the instant
201       this call is made.
202 
203   Because MP Service Ppi provides services to enable and disable processors
204   dynamically, the number of enabled logical processors may vary during the
205   course of a boot session.
206 
207   If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
208   If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
209   EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
210   is returned in NumberOfProcessors, the number of currently enabled processor
211   is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
212 
213   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
214                                   published by the PEI Foundation.
215   @param[in]  This                Pointer to this instance of the PPI.
216   @param[out] NumberOfProcessors  Pointer to the total number of logical processors in
217                                   the system, including the BSP and disabled APs.
218   @param[out] NumberOfEnabledProcessors
219                                   Number of processors in the system that are enabled.
220 
221   @retval EFI_SUCCESS             The number of logical processors and enabled
222                                   logical processors was retrieved.
223   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
224   @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
225                                   NumberOfEnabledProcessors is NULL.
226 **/
227 EFI_STATUS
228 EFIAPI
PeiGetNumberOfProcessors(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,OUT UINTN * NumberOfProcessors,OUT UINTN * NumberOfEnabledProcessors)229 PeiGetNumberOfProcessors (
230   IN  CONST EFI_PEI_SERVICES    **PeiServices,
231   IN  EFI_PEI_MP_SERVICES_PPI   *This,
232   OUT UINTN                     *NumberOfProcessors,
233   OUT UINTN                     *NumberOfEnabledProcessors
234   )
235 {
236   PEI_CPU_MP_DATA         *PeiCpuMpData;
237   UINTN                   CallerNumber;
238   UINTN                   ProcessorNumber;
239   UINTN                   EnabledProcessorNumber;
240   UINTN                   Index;
241 
242   PeiCpuMpData = GetMpHobData ();
243   if (PeiCpuMpData == NULL) {
244     return EFI_NOT_FOUND;
245   }
246 
247   if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
248     return EFI_INVALID_PARAMETER;
249   }
250 
251   //
252   // Check whether caller processor is BSP
253   //
254   PeiWhoAmI (PeiServices, This, &CallerNumber);
255   if (CallerNumber != PeiCpuMpData->BspNumber) {
256     return EFI_DEVICE_ERROR;
257   }
258 
259   ProcessorNumber        = PeiCpuMpData->CpuCount;
260   EnabledProcessorNumber = 0;
261   for (Index = 0; Index < ProcessorNumber; Index++) {
262     if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
263       EnabledProcessorNumber ++;
264     }
265   }
266 
267   *NumberOfProcessors = ProcessorNumber;
268   *NumberOfEnabledProcessors = EnabledProcessorNumber;
269 
270   return EFI_SUCCESS;
271 }
272 
273 /**
274   Gets detailed MP-related information on the requested processor at the
275   instant this call is made. This service may only be called from the BSP.
276 
277   This service retrieves detailed MP-related information about any processor
278   on the platform. Note the following:
279     - The processor information may change during the course of a boot session.
280     - The information presented here is entirely MP related.
281 
282   Information regarding the number of caches and their sizes, frequency of operation,
283   slot numbers is all considered platform-related information and is not provided
284   by this service.
285 
286   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
287                                   published by the PEI Foundation.
288   @param[in]  This                Pointer to this instance of the PPI.
289   @param[in]  ProcessorNumber     Pointer to the total number of logical processors in
290                                   the system, including the BSP and disabled APs.
291   @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled.
292 
293   @retval EFI_SUCCESS             Processor information was returned.
294   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
295   @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
296   @retval EFI_NOT_FOUND           The processor with the handle specified by
297                                   ProcessorNumber does not exist in the platform.
298 **/
299 EFI_STATUS
300 EFIAPI
PeiGetProcessorInfo(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN UINTN ProcessorNumber,OUT EFI_PROCESSOR_INFORMATION * ProcessorInfoBuffer)301 PeiGetProcessorInfo (
302   IN  CONST EFI_PEI_SERVICES     **PeiServices,
303   IN  EFI_PEI_MP_SERVICES_PPI    *This,
304   IN  UINTN                      ProcessorNumber,
305   OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
306   )
307 {
308   PEI_CPU_MP_DATA         *PeiCpuMpData;
309   UINTN                   CallerNumber;
310 
311   PeiCpuMpData = GetMpHobData ();
312   if (PeiCpuMpData == NULL) {
313     return EFI_NOT_FOUND;
314   }
315 
316   //
317   // Check whether caller processor is BSP
318   //
319   PeiWhoAmI (PeiServices, This, &CallerNumber);
320   if (CallerNumber != PeiCpuMpData->BspNumber) {
321     return EFI_DEVICE_ERROR;
322   }
323 
324   if (ProcessorInfoBuffer == NULL) {
325     return EFI_INVALID_PARAMETER;
326   }
327 
328   if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
329     return EFI_NOT_FOUND;
330   }
331 
332   ProcessorInfoBuffer->ProcessorId = (UINT64) PeiCpuMpData->CpuData[ProcessorNumber].ApicId;
333   ProcessorInfoBuffer->StatusFlag  = 0;
334   if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId == GetInitialApicId()) {
335     ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
336   }
337   if (PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
338     ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
339   }
340   if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
341     ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
342   } else {
343     ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
344   }
345 
346   //
347   // Get processor location information
348   //
349   ExtractProcessorLocation (PeiCpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
350 
351   return EFI_SUCCESS;
352 }
353 
354 /**
355   This service executes a caller provided function on all enabled APs. APs can
356   run either simultaneously or one at a time in sequence. This service supports
357   both blocking requests only. This service may only
358   be called from the BSP.
359 
360   This function is used to dispatch all the enabled APs to the function specified
361   by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
362   immediately and Procedure is not started on any AP.
363 
364   If SingleThread is TRUE, all the enabled APs execute the function specified by
365   Procedure one by one, in ascending order of processor handle number. Otherwise,
366   all the enabled APs execute the function specified by Procedure simultaneously.
367 
368   If the timeout specified by TimeoutInMicroSeconds expires before all APs return
369   from Procedure, then Procedure on the failed APs is terminated. All enabled APs
370   are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
371   and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
372   content points to the list of processor handle numbers in which Procedure was
373   terminated.
374 
375   Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
376   to make sure that the nature of the code that is executed on the BSP and the
377   dispatched APs is well controlled. The MP Services Ppi does not guarantee
378   that the Procedure function is MP-safe. Hence, the tasks that can be run in
379   parallel are limited to certain independent tasks and well-controlled exclusive
380   code. PEI services and Ppis may not be called by APs unless otherwise
381   specified.
382 
383   In blocking execution mode, BSP waits until all APs finish or
384   TimeoutInMicroSeconds expires.
385 
386   @param[in] PeiServices          An indirect pointer to the PEI Services Table
387                                   published by the PEI Foundation.
388   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
389   @param[in] Procedure            A pointer to the function to be run on enabled APs of
390                                   the system.
391   @param[in] SingleThread         If TRUE, then all the enabled APs execute the function
392                                   specified by Procedure one by one, in ascending order
393                                   of processor handle number. If FALSE, then all the
394                                   enabled APs execute the function specified by Procedure
395                                   simultaneously.
396   @param[in] TimeoutInMicroSeconds
397                                   Indicates the time limit in microseconds for APs to
398                                   return from Procedure, for blocking mode only. Zero
399                                   means infinity. If the timeout expires before all APs
400                                   return from Procedure, then Procedure on the failed APs
401                                   is terminated. All enabled APs are available for next
402                                   function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
403                                   or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
404                                   timeout expires in blocking mode, BSP returns
405                                   EFI_TIMEOUT.
406   @param[in] ProcedureArgument    The parameter passed into Procedure for all APs.
407 
408   @retval EFI_SUCCESS             In blocking mode, all APs have finished before the
409                                   timeout expired.
410   @retval EFI_DEVICE_ERROR        Caller processor is AP.
411   @retval EFI_NOT_STARTED         No enabled APs exist in the system.
412   @retval EFI_NOT_READY           Any enabled APs are busy.
413   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before all
414                                   enabled APs have finished.
415   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
416 **/
417 EFI_STATUS
418 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)419 PeiStartupAllAPs (
420   IN  CONST EFI_PEI_SERVICES    **PeiServices,
421   IN  EFI_PEI_MP_SERVICES_PPI   *This,
422   IN  EFI_AP_PROCEDURE          Procedure,
423   IN  BOOLEAN                   SingleThread,
424   IN  UINTN                     TimeoutInMicroSeconds,
425   IN  VOID                      *ProcedureArgument      OPTIONAL
426   )
427 {
428   PEI_CPU_MP_DATA         *PeiCpuMpData;
429   UINTN                   ProcessorNumber;
430   UINTN                   Index;
431   UINTN                   CallerNumber;
432   BOOLEAN                 HasEnabledAp;
433   BOOLEAN                 HasEnabledIdleAp;
434   volatile UINT32         *FinishedCount;
435   EFI_STATUS              Status;
436   UINTN                   WaitCountIndex;
437   UINTN                   WaitCountNumber;
438 
439   PeiCpuMpData = GetMpHobData ();
440   if (PeiCpuMpData == NULL) {
441     return EFI_NOT_FOUND;
442   }
443 
444   if (Procedure == NULL) {
445     return EFI_INVALID_PARAMETER;
446   }
447 
448   //
449   // Check whether caller processor is BSP
450   //
451   PeiWhoAmI (PeiServices, This, &CallerNumber);
452   if (CallerNumber != PeiCpuMpData->BspNumber) {
453     return EFI_DEVICE_ERROR;
454   }
455 
456   ProcessorNumber = PeiCpuMpData->CpuCount;
457 
458   HasEnabledAp     = FALSE;
459   HasEnabledIdleAp = FALSE;
460   for (Index = 0; Index < ProcessorNumber; Index ++) {
461     if (Index == CallerNumber) {
462       //
463       // Skip BSP
464       //
465       continue;
466     }
467     if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
468       HasEnabledAp = TRUE;
469       if (PeiCpuMpData->CpuData[Index].State != CpuStateBusy) {
470         HasEnabledIdleAp = TRUE;
471       }
472     }
473   }
474   if (!HasEnabledAp) {
475     //
476     // If no enabled AP exists, return EFI_NOT_STARTED.
477     //
478     return EFI_NOT_STARTED;
479   }
480   if (!HasEnabledIdleAp) {
481     //
482     // If any enabled APs are busy, return EFI_NOT_READY.
483     //
484     return EFI_NOT_READY;
485   }
486 
487   if (PeiCpuMpData->EndOfPeiFlag) {
488     //
489     // Backup original data and copy AP reset vector in it
490     //
491     BackupAndPrepareWakeupBuffer(PeiCpuMpData);
492   }
493 
494   WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1;
495   WaitCountIndex = 0;
496   FinishedCount = &PeiCpuMpData->FinishedCount;
497   if (!SingleThread) {
498     WakeUpAP (PeiCpuMpData, TRUE, 0, Procedure, ProcedureArgument);
499     //
500     // Wait to finish
501     //
502     if (TimeoutInMicroSeconds == 0) {
503       while (*FinishedCount < ProcessorNumber - 1) {
504         CpuPause ();
505       }
506       Status = EFI_SUCCESS;
507     } else {
508       Status = EFI_TIMEOUT;
509       for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
510         MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
511         if (*FinishedCount >= ProcessorNumber - 1) {
512           Status = EFI_SUCCESS;
513           break;
514         }
515       }
516     }
517   } else {
518     Status = EFI_SUCCESS;
519     for (Index = 0; Index < ProcessorNumber; Index++) {
520       if (Index == CallerNumber) {
521         continue;
522       }
523       WakeUpAP (PeiCpuMpData, FALSE, Index, Procedure, ProcedureArgument);
524       //
525       // Wait to finish
526       //
527       if (TimeoutInMicroSeconds == 0) {
528         while (*FinishedCount < 1) {
529           CpuPause ();
530         }
531       } else {
532         for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
533           MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
534           if (*FinishedCount >= 1) {
535             break;
536           }
537         }
538         if (WaitCountIndex == WaitCountNumber) {
539           Status = EFI_TIMEOUT;
540         }
541       }
542     }
543   }
544 
545   if (PeiCpuMpData->EndOfPeiFlag) {
546     //
547     // Restore original data
548     //
549     RestoreWakeupBuffer(PeiCpuMpData);
550   }
551 
552   return Status;
553 }
554 
555 /**
556   This service lets the caller get one enabled AP to execute a caller-provided
557   function. The caller can request the BSP to wait for the completion
558   of the AP. This service may only be called from the BSP.
559 
560   This function is used to dispatch one enabled AP to the function specified by
561   Procedure passing in the argument specified by ProcedureArgument.
562   The execution is in blocking mode. The BSP waits until the AP finishes or
563   TimeoutInMicroSecondss expires.
564 
565   If the timeout specified by TimeoutInMicroseconds expires before the AP returns
566   from Procedure, then execution of Procedure by the AP is terminated. The AP is
567   available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
568   EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
569 
570   @param[in] PeiServices          An indirect pointer to the PEI Services Table
571                                   published by the PEI Foundation.
572   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
573   @param[in] Procedure            A pointer to the function to be run on enabled APs of
574                                   the system.
575   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
576                                   total number of logical processors minus 1. The total
577                                   number of logical processors can be retrieved by
578                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
579   @param[in] TimeoutInMicroseconds
580                                   Indicates the time limit in microseconds for APs to
581                                   return from Procedure, for blocking mode only. Zero
582                                   means infinity. If the timeout expires before all APs
583                                   return from Procedure, then Procedure on the failed APs
584                                   is terminated. All enabled APs are available for next
585                                   function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
586                                   or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
587                                   timeout expires in blocking mode, BSP returns
588                                   EFI_TIMEOUT.
589   @param[in] ProcedureArgument    The parameter passed into Procedure for all APs.
590 
591   @retval EFI_SUCCESS             In blocking mode, specified AP finished before the
592                                   timeout expires.
593   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
594   @retval EFI_TIMEOUT             In blocking mode, the timeout expired before the
595                                   specified AP has finished.
596   @retval EFI_NOT_FOUND           The processor with the handle specified by
597                                   ProcessorNumber does not exist.
598   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
599   @retval EFI_INVALID_PARAMETER   Procedure is NULL.
600 **/
601 EFI_STATUS
602 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)603 PeiStartupThisAP (
604   IN  CONST EFI_PEI_SERVICES    **PeiServices,
605   IN  EFI_PEI_MP_SERVICES_PPI   *This,
606   IN  EFI_AP_PROCEDURE          Procedure,
607   IN  UINTN                     ProcessorNumber,
608   IN  UINTN                     TimeoutInMicroseconds,
609   IN  VOID                      *ProcedureArgument      OPTIONAL
610   )
611 {
612   PEI_CPU_MP_DATA         *PeiCpuMpData;
613   UINTN                   CallerNumber;
614   volatile UINT32         *FinishedCount;
615   EFI_STATUS              Status;
616   UINTN                   WaitCountIndex;
617   UINTN                   WaitCountNumber;
618 
619   PeiCpuMpData = GetMpHobData ();
620   if (PeiCpuMpData == NULL) {
621     return EFI_NOT_FOUND;
622   }
623 
624   //
625   // Check whether caller processor is BSP
626   //
627   PeiWhoAmI (PeiServices, This, &CallerNumber);
628   if (CallerNumber != PeiCpuMpData->BspNumber) {
629     return EFI_DEVICE_ERROR;
630   }
631 
632   if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
633     return EFI_NOT_FOUND;
634   }
635 
636   if (ProcessorNumber == PeiCpuMpData->BspNumber || Procedure == NULL) {
637     return EFI_INVALID_PARAMETER;
638   }
639 
640   //
641   // Check whether specified AP is disabled
642   //
643   if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
644     return EFI_INVALID_PARAMETER;
645   }
646 
647   if (PeiCpuMpData->EndOfPeiFlag) {
648     //
649     // Backup original data and copy AP reset vector in it
650     //
651     BackupAndPrepareWakeupBuffer(PeiCpuMpData);
652   }
653 
654   WaitCountNumber = TimeoutInMicroseconds / CPU_CHECK_AP_INTERVAL + 1;
655   WaitCountIndex = 0;
656   FinishedCount = &PeiCpuMpData->FinishedCount;
657 
658   WakeUpAP (PeiCpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);
659 
660   //
661   // Wait to finish
662   //
663   if (TimeoutInMicroseconds == 0) {
664     while (*FinishedCount < 1) {
665       CpuPause() ;
666     }
667     Status = EFI_SUCCESS;
668   } else {
669     Status = EFI_TIMEOUT;
670     for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
671       MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
672       if (*FinishedCount >= 1) {
673         Status = EFI_SUCCESS;
674         break;
675       }
676     }
677   }
678 
679   if (PeiCpuMpData->EndOfPeiFlag) {
680     //
681     // Backup original data and copy AP reset vector in it
682     //
683     RestoreWakeupBuffer(PeiCpuMpData);
684   }
685 
686   return Status;
687 }
688 
689 /**
690   This service switches the requested AP to be the BSP from that point onward.
691   This service changes the BSP for all purposes.   This call can only be performed
692   by the current BSP.
693 
694   This service switches the requested AP to be the BSP from that point onward.
695   This service changes the BSP for all purposes. The new BSP can take over the
696   execution of the old BSP and continue seamlessly from where the old one left
697   off.
698 
699   If the BSP cannot be switched prior to the return from this service, then
700   EFI_UNSUPPORTED must be returned.
701 
702   @param[in] PeiServices          An indirect pointer to the PEI Services Table
703                                   published by the PEI Foundation.
704   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
705   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
706                                   total number of logical processors minus 1. The total
707                                   number of logical processors can be retrieved by
708                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
709   @param[in] EnableOldBSP         If TRUE, then the old BSP will be listed as an enabled
710                                   AP. Otherwise, it will be disabled.
711 
712   @retval EFI_SUCCESS             BSP successfully switched.
713   @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to this
714                                   service returning.
715   @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
716   @retval EFI_SUCCESS             The calling processor is an AP.
717   @retval EFI_NOT_FOUND           The processor with the handle specified by
718                                   ProcessorNumber does not exist.
719   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or a disabled
720                                   AP.
721   @retval EFI_NOT_READY           The specified AP is busy.
722 **/
723 EFI_STATUS
724 EFIAPI
PeiSwitchBSP(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)725 PeiSwitchBSP (
726   IN  CONST EFI_PEI_SERVICES   **PeiServices,
727   IN  EFI_PEI_MP_SERVICES_PPI  *This,
728   IN  UINTN                    ProcessorNumber,
729   IN  BOOLEAN                  EnableOldBSP
730   )
731 {
732   PEI_CPU_MP_DATA         *PeiCpuMpData;
733   UINTN                   CallerNumber;
734   MSR_IA32_APIC_BASE      ApicBaseMsr;
735 
736   PeiCpuMpData = GetMpHobData ();
737   if (PeiCpuMpData == NULL) {
738     return EFI_NOT_FOUND;
739   }
740 
741   //
742   // Check whether caller processor is BSP
743   //
744   PeiWhoAmI (PeiServices, This, &CallerNumber);
745   if (CallerNumber != PeiCpuMpData->BspNumber) {
746     return EFI_SUCCESS;
747   }
748 
749   if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
750     return EFI_NOT_FOUND;
751   }
752 
753   //
754   // Check whether specified AP is disabled
755   //
756   if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
757     return EFI_INVALID_PARAMETER;
758   }
759 
760   //
761   // Check whether ProcessorNumber specifies the current BSP
762   //
763   if (ProcessorNumber == PeiCpuMpData->BspNumber) {
764     return EFI_INVALID_PARAMETER;
765   }
766 
767   //
768   // Check whether specified AP is busy
769   //
770   if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateBusy) {
771     return EFI_NOT_READY;
772   }
773 
774   //
775   // Clear the BSP bit of MSR_IA32_APIC_BASE
776   //
777   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
778   ApicBaseMsr.Bits.Bsp = 0;
779   AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
780 
781   PeiCpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
782   PeiCpuMpData->APInfo.State  = CPU_SWITCH_STATE_IDLE;
783 
784   if (PeiCpuMpData->EndOfPeiFlag) {
785     //
786     // Backup original data and copy AP reset vector in it
787     //
788     BackupAndPrepareWakeupBuffer(PeiCpuMpData);
789   }
790 
791   //
792   // Need to wakeUp AP (future BSP).
793   //
794   WakeUpAP (PeiCpuMpData, FALSE, ProcessorNumber, FutureBSPProc, PeiCpuMpData);
795 
796   AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo);
797 
798   if (PeiCpuMpData->EndOfPeiFlag) {
799     //
800     // Backup original data and copy AP reset vector in it
801     //
802     RestoreWakeupBuffer(PeiCpuMpData);
803   }
804 
805   //
806   // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
807   //
808   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
809   ApicBaseMsr.Bits.Bsp = 1;
810   AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
811   //
812   // Set old BSP enable state
813   //
814   if (!EnableOldBSP) {
815     PeiCpuMpData->CpuData[PeiCpuMpData->BspNumber].State = CpuStateDisabled;
816   }
817   //
818   // Save new BSP number
819   //
820   PeiCpuMpData->BspNumber = (UINT32) ProcessorNumber;
821 
822   return EFI_SUCCESS;
823 }
824 
825 /**
826   This service lets the caller enable or disable an AP from this point onward.
827   This service may only be called from the BSP.
828 
829   This service allows the caller enable or disable an AP from this point onward.
830   The caller can optionally specify the health status of the AP by Health. If
831   an AP is being disabled, then the state of the disabled AP is implementation
832   dependent. If an AP is enabled, then the implementation must guarantee that a
833   complete initialization sequence is performed on the AP, so the AP is in a state
834   that is compatible with an MP operating system.
835 
836   If the enable or disable AP operation cannot be completed prior to the return
837   from this service, then EFI_UNSUPPORTED must be returned.
838 
839   @param[in] PeiServices          An indirect pointer to the PEI Services Table
840                                   published by the PEI Foundation.
841   @param[in] This                 A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
842   @param[in] ProcessorNumber      The handle number of the AP. The range is from 0 to the
843                                   total number of logical processors minus 1. The total
844                                   number of logical processors can be retrieved by
845                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
846   @param[in] EnableAP             Specifies the new state for the processor for enabled,
847                                   FALSE for disabled.
848   @param[in] HealthFlag           If not NULL, a pointer to a value that specifies the
849                                   new health status of the AP. This flag corresponds to
850                                   StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo().
851                                   Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other
852                                   bits are ignored. If it is NULL, this parameter is
853                                   ignored.
854 
855   @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
856   @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed prior
857                                   to this service returning.
858   @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
859   @retval EFI_DEVICE_ERROR        The calling processor is an AP.
860   @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
861                                   does not exist.
862   @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
863 **/
864 EFI_STATUS
865 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)866 PeiEnableDisableAP (
867   IN  CONST EFI_PEI_SERVICES    **PeiServices,
868   IN  EFI_PEI_MP_SERVICES_PPI   *This,
869   IN  UINTN                     ProcessorNumber,
870   IN  BOOLEAN                   EnableAP,
871   IN  UINT32                    *HealthFlag OPTIONAL
872   )
873 {
874   PEI_CPU_MP_DATA         *PeiCpuMpData;
875   UINTN                   CallerNumber;
876 
877   PeiCpuMpData = GetMpHobData ();
878   if (PeiCpuMpData == NULL) {
879     return EFI_NOT_FOUND;
880   }
881 
882   //
883   // Check whether caller processor is BSP
884   //
885   PeiWhoAmI (PeiServices, This, &CallerNumber);
886   if (CallerNumber != PeiCpuMpData->BspNumber) {
887     return EFI_DEVICE_ERROR;
888   }
889 
890   if (ProcessorNumber == PeiCpuMpData->BspNumber) {
891     return EFI_INVALID_PARAMETER;
892   }
893 
894   if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
895     return EFI_NOT_FOUND;
896   }
897 
898   if (!EnableAP) {
899     PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateDisabled;
900   } else {
901     PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
902   }
903 
904   if (HealthFlag != NULL) {
905     PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy =
906           (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
907   }
908   return EFI_SUCCESS;
909 }
910 
911 /**
912   This return the handle number for the calling processor.  This service may be
913   called from the BSP and APs.
914 
915   This service returns the processor handle number for the calling processor.
916   The returned value is in the range from 0 to the total number of logical
917   processors minus 1. The total number of logical processors can be retrieved
918   with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
919   called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
920   is returned. Otherwise, the current processors handle number is returned in
921   ProcessorNumber, and EFI_SUCCESS is returned.
922 
923   @param[in]  PeiServices         An indirect pointer to the PEI Services Table
924                                   published by the PEI Foundation.
925   @param[in]  This                A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
926   @param[out] ProcessorNumber     The handle number of the AP. The range is from 0 to the
927                                   total number of logical processors minus 1. The total
928                                   number of logical processors can be retrieved by
929                                   EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
930 
931   @retval EFI_SUCCESS             The current processor handle number was returned in
932                                   ProcessorNumber.
933   @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
934 **/
935 EFI_STATUS
936 EFIAPI
PeiWhoAmI(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_MP_SERVICES_PPI * This,OUT UINTN * ProcessorNumber)937 PeiWhoAmI (
938   IN  CONST EFI_PEI_SERVICES   **PeiServices,
939   IN  EFI_PEI_MP_SERVICES_PPI  *This,
940   OUT UINTN                    *ProcessorNumber
941   )
942 {
943   PEI_CPU_MP_DATA         *PeiCpuMpData;
944 
945   PeiCpuMpData = GetMpHobData ();
946   if (PeiCpuMpData == NULL) {
947     return EFI_NOT_FOUND;
948   }
949 
950   if (ProcessorNumber == NULL) {
951     return EFI_INVALID_PARAMETER;
952   }
953 
954   return GetProcessorNumber (PeiCpuMpData, ProcessorNumber);
955 }
956 
957