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
EnableDebugAgent(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 *
GetCpuMpData(VOID)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
SaveCpuMpData(IN CPU_MP_DATA * CpuMpData)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
AllocateResetVector(IN OUT CPU_MP_DATA * CpuMpData)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
FreeResetVector(IN CPU_MP_DATA * CpuMpData)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
CheckAndUpdateApsStatus(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
CheckApsStatus(IN EFI_EVENT Event,IN VOID * Context)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
GetProtectedModeCS(VOID)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
RelocateApLoop(IN OUT VOID * Buffer)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
MpInitChangeApLoopCallback(IN EFI_EVENT Event,IN VOID * Context)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
InitMpGlobalData(IN CPU_MP_DATA * CpuMpData)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
MpInitLibStartupAllAPs(IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)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
MpInitLibStartupThisAP(IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)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
MpInitLibSwitchBSP(IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)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
MpInitLibEnableDisableAP(IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)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