VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c@ 109019

Last change on this file since 109019 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette