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