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