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