1 /** @file 2 MP initialize support functions for DXE phase. 3 4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "MpLib.h" 16 17 #include <Library/UefiLib.h> 18 #include <Library/UefiBootServicesTableLib.h> 19 #include <Library/DebugAgentLib.h> 20 21 #include <Protocol/Timer.h> 22 23 #define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100)) 24 #define AP_SAFE_STACK_SIZE 128 25 26 CPU_MP_DATA *mCpuMpData = NULL; 27 EFI_EVENT mCheckAllApsEvent = NULL; 28 EFI_EVENT mMpInitExitBootServicesEvent = NULL; 29 EFI_EVENT mLegacyBootEvent = NULL; 30 volatile BOOLEAN mStopCheckAllApsStatus = TRUE; 31 VOID *mReservedApLoopFunc = NULL; 32 UINTN mReservedTopOfApStack; 33 volatile UINT32 mNumberToFinish = 0; 34 35 /** 36 Enable Debug Agent to support source debugging on AP function. 37 38 **/ 39 VOID 40 EnableDebugAgent ( 41 VOID 42 ) 43 { 44 // 45 // Initialize Debug Agent to support source level debug in DXE phase 46 // 47 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL); 48 } 49 50 /** 51 Get the pointer to CPU MP Data structure. 52 53 @return The pointer to CPU MP Data structure. 54 **/ 55 CPU_MP_DATA * 56 GetCpuMpData ( 57 VOID 58 ) 59 { 60 ASSERT (mCpuMpData != NULL); 61 return mCpuMpData; 62 } 63 64 /** 65 Save the pointer to CPU MP Data structure. 66 67 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved. 68 **/ 69 VOID 70 SaveCpuMpData ( 71 IN CPU_MP_DATA *CpuMpData 72 ) 73 { 74 mCpuMpData = CpuMpData; 75 } 76 77 /** 78 Allocate reset vector buffer. 79 80 @param[in, out] CpuMpData The pointer to CPU MP Data structure. 81 **/ 82 VOID 83 AllocateResetVector ( 84 IN OUT CPU_MP_DATA *CpuMpData 85 ) 86 { 87 EFI_STATUS Status; 88 UINTN ApResetVectorSize; 89 EFI_PHYSICAL_ADDRESS StartAddress; 90 91 if (CpuMpData->SaveRestoreFlag) { 92 BackupAndPrepareWakeupBuffer (CpuMpData); 93 } else { 94 ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + 95 sizeof (MP_CPU_EXCHANGE_INFO); 96 97 StartAddress = BASE_1MB; 98 Status = gBS->AllocatePages ( 99 AllocateMaxAddress, 100 EfiACPIMemoryNVS, 101 EFI_SIZE_TO_PAGES (ApResetVectorSize), 102 &StartAddress 103 ); 104 ASSERT_EFI_ERROR (Status); 105 106 CpuMpData->WakeupBuffer = (UINTN) StartAddress; 107 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) 108 (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize); 109 // 110 // copy AP reset code in it 111 // 112 CopyMem ( 113 (VOID *) CpuMpData->WakeupBuffer, 114 (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, 115 CpuMpData->AddressMap.RendezvousFunnelSize 116 ); 117 } 118 } 119 120 /** 121 Free AP reset vector buffer. 122 123 @param[in] CpuMpData The pointer to CPU MP Data structure. 124 **/ 125 VOID 126 FreeResetVector ( 127 IN CPU_MP_DATA *CpuMpData 128 ) 129 { 130 EFI_STATUS Status; 131 UINTN ApResetVectorSize; 132 133 if (CpuMpData->SaveRestoreFlag) { 134 RestoreWakeupBuffer (CpuMpData); 135 } else { 136 ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + 137 sizeof (MP_CPU_EXCHANGE_INFO); 138 Status = gBS->FreePages( 139 (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer, 140 EFI_SIZE_TO_PAGES (ApResetVectorSize) 141 ); 142 ASSERT_EFI_ERROR (Status); 143 } 144 } 145 146 /** 147 Checks APs status and updates APs status if needed. 148 149 **/ 150 VOID 151 CheckAndUpdateApsStatus ( 152 VOID 153 ) 154 { 155 UINTN ProcessorNumber; 156 EFI_STATUS Status; 157 CPU_MP_DATA *CpuMpData; 158 159 CpuMpData = GetCpuMpData (); 160 161 // 162 // First, check whether pending StartupAllAPs() exists. 163 // 164 if (CpuMpData->WaitEvent != NULL) { 165 166 Status = CheckAllAPs (); 167 // 168 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it. 169 // 170 if (Status != EFI_NOT_READY) { 171 Status = gBS->SignalEvent (CpuMpData->WaitEvent); 172 CpuMpData->WaitEvent = NULL; 173 } 174 } 175 176 // 177 // Second, check whether pending StartupThisAPs() callings exist. 178 // 179 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) { 180 181 if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) { 182 continue; 183 } 184 185 Status = CheckThisAP (ProcessorNumber); 186 187 if (Status != EFI_NOT_READY) { 188 gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent); 189 CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL; 190 } 191 } 192 } 193 194 /** 195 Checks APs' status periodically. 196 197 This function is triggered by timer periodically to check the 198 state of APs for StartupAllAPs() and StartupThisAP() executed 199 in non-blocking mode. 200 201 @param[in] Event Event triggered. 202 @param[in] Context Parameter passed with the event. 203 204 **/ 205 VOID 206 EFIAPI 207 CheckApsStatus ( 208 IN EFI_EVENT Event, 209 IN VOID *Context 210 ) 211 { 212 // 213 // If CheckApsStatus() is not stopped, otherwise return immediately. 214 // 215 if (!mStopCheckAllApsStatus) { 216 CheckAndUpdateApsStatus (); 217 } 218 } 219 220 /** 221 Get Protected mode code segment from current GDT table. 222 223 @return Protected mode code segment value. 224 **/ 225 UINT16 226 GetProtectedModeCS ( 227 VOID 228 ) 229 { 230 IA32_DESCRIPTOR GdtrDesc; 231 IA32_SEGMENT_DESCRIPTOR *GdtEntry; 232 UINTN GdtEntryCount; 233 UINT16 Index; 234 235 Index = (UINT16) -1; 236 AsmReadGdtr (&GdtrDesc); 237 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR); 238 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; 239 for (Index = 0; Index < GdtEntryCount; Index++) { 240 if (GdtEntry->Bits.L == 0) { 241 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) { 242 break; 243 } 244 } 245 GdtEntry++; 246 } 247 ASSERT (Index != -1); 248 return Index * 8; 249 } 250 251 /** 252 Do sync on APs. 253 254 @param[in, out] Buffer Pointer to private data buffer. 255 **/ 256 VOID 257 EFIAPI 258 RelocateApLoop ( 259 IN OUT VOID *Buffer 260 ) 261 { 262 CPU_MP_DATA *CpuMpData; 263 BOOLEAN MwaitSupport; 264 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc; 265 UINTN ProcessorNumber; 266 267 MpInitLibWhoAmI (&ProcessorNumber); 268 CpuMpData = GetCpuMpData (); 269 MwaitSupport = IsMwaitSupport (); 270 AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc; 271 AsmRelocateApLoopFunc ( 272 MwaitSupport, 273 CpuMpData->ApTargetCState, 274 CpuMpData->PmCodeSegment, 275 mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE, 276 (UINTN) &mNumberToFinish 277 ); 278 // 279 // It should never reach here 280 // 281 ASSERT (FALSE); 282 } 283 284 /** 285 Callback function for ExitBootServices. 286 287 @param[in] Event Event whose notification function is being invoked. 288 @param[in] Context The pointer to the notification function's context, 289 which is implementation-dependent. 290 291 **/ 292 VOID 293 EFIAPI 294 MpInitChangeApLoopCallback ( 295 IN EFI_EVENT Event, 296 IN VOID *Context 297 ) 298 { 299 CPU_MP_DATA *CpuMpData; 300 301 CpuMpData = GetCpuMpData (); 302 CpuMpData->SaveRestoreFlag = TRUE; 303 CpuMpData->PmCodeSegment = GetProtectedModeCS (); 304 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode); 305 mNumberToFinish = CpuMpData->CpuCount - 1; 306 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL); 307 while (mNumberToFinish > 0) { 308 CpuPause (); 309 } 310 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__)); 311 } 312 313 /** 314 Initialize global data for MP support. 315 316 @param[in] CpuMpData The pointer to CPU MP Data structure. 317 **/ 318 VOID 319 InitMpGlobalData ( 320 IN CPU_MP_DATA *CpuMpData 321 ) 322 { 323 EFI_STATUS Status; 324 EFI_PHYSICAL_ADDRESS Address; 325 UINTN ApSafeBufferSize; 326 327 SaveCpuMpData (CpuMpData); 328 329 if (CpuMpData->CpuCount == 1) { 330 // 331 // If only BSP exists, return 332 // 333 return; 334 } 335 336 // 337 // Avoid APs access invalid buffer data which allocated by BootServices, 338 // so we will allocate reserved data for AP loop code. We also need to 339 // allocate this buffer below 4GB due to APs may be transferred to 32bit 340 // protected mode on long mode DXE. 341 // Allocating it in advance since memory services are not available in 342 // Exit Boot Services callback function. 343 // 344 ApSafeBufferSize = CpuMpData->AddressMap.RelocateApLoopFuncSize; 345 ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE; 346 347 Address = BASE_4GB - 1; 348 Status = gBS->AllocatePages ( 349 AllocateMaxAddress, 350 EfiReservedMemoryType, 351 EFI_SIZE_TO_PAGES (ApSafeBufferSize), 352 &Address 353 ); 354 ASSERT_EFI_ERROR (Status); 355 mReservedApLoopFunc = (VOID *) (UINTN) Address; 356 ASSERT (mReservedApLoopFunc != NULL); 357 mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize)); 358 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0); 359 CopyMem ( 360 mReservedApLoopFunc, 361 CpuMpData->AddressMap.RelocateApLoopFuncAddress, 362 CpuMpData->AddressMap.RelocateApLoopFuncSize 363 ); 364 365 Status = gBS->CreateEvent ( 366 EVT_TIMER | EVT_NOTIFY_SIGNAL, 367 TPL_NOTIFY, 368 CheckApsStatus, 369 NULL, 370 &mCheckAllApsEvent 371 ); 372 ASSERT_EFI_ERROR (Status); 373 374 // 375 // Set timer to check all APs status. 376 // 377 Status = gBS->SetTimer ( 378 mCheckAllApsEvent, 379 TimerPeriodic, 380 AP_CHECK_INTERVAL 381 ); 382 ASSERT_EFI_ERROR (Status); 383 384 Status = gBS->CreateEvent ( 385 EVT_SIGNAL_EXIT_BOOT_SERVICES, 386 TPL_CALLBACK, 387 MpInitChangeApLoopCallback, 388 NULL, 389 &mMpInitExitBootServicesEvent 390 ); 391 ASSERT_EFI_ERROR (Status); 392 393 Status = gBS->CreateEventEx ( 394 EVT_NOTIFY_SIGNAL, 395 TPL_CALLBACK, 396 MpInitChangeApLoopCallback, 397 NULL, 398 &gEfiEventLegacyBootGuid, 399 &mLegacyBootEvent 400 ); 401 ASSERT_EFI_ERROR (Status); 402 } 403 404 /** 405 This service executes a caller provided function on all enabled APs. 406 407 @param[in] Procedure A pointer to the function to be run on 408 enabled APs of the system. See type 409 EFI_AP_PROCEDURE. 410 @param[in] SingleThread If TRUE, then all the enabled APs execute 411 the function specified by Procedure one by 412 one, in ascending order of processor handle 413 number. If FALSE, then all the enabled APs 414 execute the function specified by Procedure 415 simultaneously. 416 @param[in] WaitEvent The event created by the caller with CreateEvent() 417 service. If it is NULL, then execute in 418 blocking mode. BSP waits until all APs finish 419 or TimeoutInMicroSeconds expires. If it's 420 not NULL, then execute in non-blocking mode. 421 BSP requests the function specified by 422 Procedure to be started on all the enabled 423 APs, and go on executing immediately. If 424 all return from Procedure, or TimeoutInMicroSeconds 425 expires, this event is signaled. The BSP 426 can use the CheckEvent() or WaitForEvent() 427 services to check the state of event. Type 428 EFI_EVENT is defined in CreateEvent() in 429 the Unified Extensible Firmware Interface 430 Specification. 431 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for 432 APs to return from Procedure, either for 433 blocking or non-blocking mode. Zero means 434 infinity. If the timeout expires before 435 all APs return from Procedure, then Procedure 436 on the failed APs is terminated. All enabled 437 APs are available for next function assigned 438 by MpInitLibStartupAllAPs() or 439 MPInitLibStartupThisAP(). 440 If the timeout expires in blocking mode, 441 BSP returns EFI_TIMEOUT. If the timeout 442 expires in non-blocking mode, WaitEvent 443 is signaled with SignalEvent(). 444 @param[in] ProcedureArgument The parameter passed into Procedure for 445 all APs. 446 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise, 447 if all APs finish successfully, then its 448 content is set to NULL. If not all APs 449 finish before timeout expires, then its 450 content is set to address of the buffer 451 holding handle numbers of the failed APs. 452 The buffer is allocated by MP Initialization 453 library, and it's the caller's responsibility to 454 free the buffer with FreePool() service. 455 In blocking mode, it is ready for consumption 456 when the call returns. In non-blocking mode, 457 it is ready when WaitEvent is signaled. The 458 list of failed CPU is terminated by 459 END_OF_CPU_LIST. 460 461 @retval EFI_SUCCESS In blocking mode, all APs have finished before 462 the timeout expired. 463 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched 464 to all enabled APs. 465 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the 466 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was 467 signaled. 468 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not 469 supported. 470 @retval EFI_DEVICE_ERROR Caller processor is AP. 471 @retval EFI_NOT_STARTED No enabled APs exist in the system. 472 @retval EFI_NOT_READY Any enabled APs are busy. 473 @retval EFI_NOT_READY MP Initialize Library is not initialized. 474 @retval EFI_TIMEOUT In blocking mode, the timeout expired before 475 all enabled APs have finished. 476 @retval EFI_INVALID_PARAMETER Procedure is NULL. 477 478 **/ 479 EFI_STATUS 480 EFIAPI 481 MpInitLibStartupAllAPs ( 482 IN EFI_AP_PROCEDURE Procedure, 483 IN BOOLEAN SingleThread, 484 IN EFI_EVENT WaitEvent OPTIONAL, 485 IN UINTN TimeoutInMicroseconds, 486 IN VOID *ProcedureArgument OPTIONAL, 487 OUT UINTN **FailedCpuList OPTIONAL 488 ) 489 { 490 EFI_STATUS Status; 491 492 // 493 // Temporarily stop checkAllApsStatus for avoid resource dead-lock. 494 // 495 mStopCheckAllApsStatus = TRUE; 496 497 Status = StartupAllAPsWorker ( 498 Procedure, 499 SingleThread, 500 WaitEvent, 501 TimeoutInMicroseconds, 502 ProcedureArgument, 503 FailedCpuList 504 ); 505 506 // 507 // Start checkAllApsStatus 508 // 509 mStopCheckAllApsStatus = FALSE; 510 511 return Status; 512 } 513 514 /** 515 This service lets the caller get one enabled AP to execute a caller-provided 516 function. 517 518 @param[in] Procedure A pointer to the function to be run on the 519 designated AP of the system. See type 520 EFI_AP_PROCEDURE. 521 @param[in] ProcessorNumber The handle number of the AP. The range is 522 from 0 to the total number of logical 523 processors minus 1. The total number of 524 logical processors can be retrieved by 525 MpInitLibGetNumberOfProcessors(). 526 @param[in] WaitEvent The event created by the caller with CreateEvent() 527 service. If it is NULL, then execute in 528 blocking mode. BSP waits until this AP finish 529 or TimeoutInMicroSeconds expires. If it's 530 not NULL, then execute in non-blocking mode. 531 BSP requests the function specified by 532 Procedure to be started on this AP, 533 and go on executing immediately. If this AP 534 return from Procedure or TimeoutInMicroSeconds 535 expires, this event is signaled. The BSP 536 can use the CheckEvent() or WaitForEvent() 537 services to check the state of event. Type 538 EFI_EVENT is defined in CreateEvent() in 539 the Unified Extensible Firmware Interface 540 Specification. 541 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for 542 this AP to finish this Procedure, either for 543 blocking or non-blocking mode. Zero means 544 infinity. If the timeout expires before 545 this AP returns from Procedure, then Procedure 546 on the AP is terminated. The 547 AP is available for next function assigned 548 by MpInitLibStartupAllAPs() or 549 MpInitLibStartupThisAP(). 550 If the timeout expires in blocking mode, 551 BSP returns EFI_TIMEOUT. If the timeout 552 expires in non-blocking mode, WaitEvent 553 is signaled with SignalEvent(). 554 @param[in] ProcedureArgument The parameter passed into Procedure on the 555 specified AP. 556 @param[out] Finished If NULL, this parameter is ignored. In 557 blocking mode, this parameter is ignored. 558 In non-blocking mode, if AP returns from 559 Procedure before the timeout expires, its 560 content is set to TRUE. Otherwise, the 561 value is set to FALSE. The caller can 562 determine if the AP returned from Procedure 563 by evaluating this value. 564 565 @retval EFI_SUCCESS In blocking mode, specified AP finished before 566 the timeout expires. 567 @retval EFI_SUCCESS In non-blocking mode, the function has been 568 dispatched to specified AP. 569 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the 570 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was 571 signaled. 572 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not 573 supported. 574 @retval EFI_DEVICE_ERROR The calling processor is an AP. 575 @retval EFI_TIMEOUT In blocking mode, the timeout expired before 576 the specified AP has finished. 577 @retval EFI_NOT_READY The specified AP is busy. 578 @retval EFI_NOT_READY MP Initialize Library is not initialized. 579 @retval EFI_NOT_FOUND The processor with the handle specified by 580 ProcessorNumber does not exist. 581 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. 582 @retval EFI_INVALID_PARAMETER Procedure is NULL. 583 584 **/ 585 EFI_STATUS 586 EFIAPI 587 MpInitLibStartupThisAP ( 588 IN EFI_AP_PROCEDURE Procedure, 589 IN UINTN ProcessorNumber, 590 IN EFI_EVENT WaitEvent OPTIONAL, 591 IN UINTN TimeoutInMicroseconds, 592 IN VOID *ProcedureArgument OPTIONAL, 593 OUT BOOLEAN *Finished OPTIONAL 594 ) 595 { 596 EFI_STATUS Status; 597 598 // 599 // temporarily stop checkAllApsStatus for avoid resource dead-lock. 600 // 601 mStopCheckAllApsStatus = TRUE; 602 603 Status = StartupThisAPWorker ( 604 Procedure, 605 ProcessorNumber, 606 WaitEvent, 607 TimeoutInMicroseconds, 608 ProcedureArgument, 609 Finished 610 ); 611 612 mStopCheckAllApsStatus = FALSE; 613 614 return Status; 615 } 616 617 /** 618 This service switches the requested AP to be the BSP from that point onward. 619 This service changes the BSP for all purposes. This call can only be performed 620 by the current BSP. 621 622 @param[in] ProcessorNumber The handle number of AP that is to become the new 623 BSP. The range is from 0 to the total number of 624 logical processors minus 1. The total number of 625 logical processors can be retrieved by 626 MpInitLibGetNumberOfProcessors(). 627 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an 628 enabled AP. Otherwise, it will be disabled. 629 630 @retval EFI_SUCCESS BSP successfully switched. 631 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to 632 this service returning. 633 @retval EFI_UNSUPPORTED Switching the BSP is not supported. 634 @retval EFI_DEVICE_ERROR The calling processor is an AP. 635 @retval EFI_NOT_FOUND The processor with the handle specified by 636 ProcessorNumber does not exist. 637 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or 638 a disabled AP. 639 @retval EFI_NOT_READY The specified AP is busy. 640 @retval EFI_NOT_READY MP Initialize Library is not initialized. 641 642 **/ 643 EFI_STATUS 644 EFIAPI 645 MpInitLibSwitchBSP ( 646 IN UINTN ProcessorNumber, 647 IN BOOLEAN EnableOldBSP 648 ) 649 { 650 EFI_STATUS Status; 651 EFI_TIMER_ARCH_PROTOCOL *Timer; 652 UINT64 TimerPeriod; 653 654 TimerPeriod = 0; 655 // 656 // Locate Timer Arch Protocol 657 // 658 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer); 659 if (EFI_ERROR (Status)) { 660 Timer = NULL; 661 } 662 663 if (Timer != NULL) { 664 // 665 // Save current rate of DXE Timer 666 // 667 Timer->GetTimerPeriod (Timer, &TimerPeriod); 668 // 669 // Disable DXE Timer and drain pending interrupts 670 // 671 Timer->SetTimerPeriod (Timer, 0); 672 } 673 674 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP); 675 676 if (Timer != NULL) { 677 // 678 // Enable and restore rate of DXE Timer 679 // 680 Timer->SetTimerPeriod (Timer, TimerPeriod); 681 } 682 683 return Status; 684 } 685 686 /** 687 This service lets the caller enable or disable an AP from this point onward. 688 This service may only be called from the BSP. 689 690 @param[in] ProcessorNumber The handle number of AP. 691 The range is from 0 to the total number of 692 logical processors minus 1. The total number of 693 logical processors can be retrieved by 694 MpInitLibGetNumberOfProcessors(). 695 @param[in] EnableAP Specifies the new state for the processor for 696 enabled, FALSE for disabled. 697 @param[in] HealthFlag If not NULL, a pointer to a value that specifies 698 the new health status of the AP. This flag 699 corresponds to StatusFlag defined in 700 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only 701 the PROCESSOR_HEALTH_STATUS_BIT is used. All other 702 bits are ignored. If it is NULL, this parameter 703 is ignored. 704 705 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. 706 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed 707 prior to this service returning. 708 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. 709 @retval EFI_DEVICE_ERROR The calling processor is an AP. 710 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber 711 does not exist. 712 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. 713 @retval EFI_NOT_READY MP Initialize Library is not initialized. 714 715 **/ 716 EFI_STATUS 717 EFIAPI 718 MpInitLibEnableDisableAP ( 719 IN UINTN ProcessorNumber, 720 IN BOOLEAN EnableAP, 721 IN UINT32 *HealthFlag OPTIONAL 722 ) 723 { 724 EFI_STATUS Status; 725 BOOLEAN TempStopCheckState; 726 727 TempStopCheckState = FALSE; 728 // 729 // temporarily stop checkAllAPsStatus for initialize parameters. 730 // 731 if (!mStopCheckAllApsStatus) { 732 mStopCheckAllApsStatus = TRUE; 733 TempStopCheckState = TRUE; 734 } 735 736 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag); 737 738 if (TempStopCheckState) { 739 mStopCheckAllApsStatus = FALSE; 740 } 741 742 return Status; 743 } 744