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 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 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 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 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 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 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 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 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 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 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