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