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