]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
1 /** @file
2 MP initialize support functions for PEI 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 #include <Library/PeiServicesLib.h>
11 #include <Guid/S3SmmInitDone.h>
12 #include <Ppi/ShadowMicrocode.h>
13
14 STATIC UINT64 mSevEsPeiWakeupBuffer = BASE_1MB;
15
16 /**
17 S3 SMM Init Done notification function.
18
19 @param PeiServices Indirect reference to the PEI Services Table.
20 @param NotifyDesc Address of the notification descriptor data structure.
21 @param InvokePpi Address of the PPI that was invoked.
22
23 @retval EFI_SUCCESS The function completes successfully.
24
25 **/
26 EFI_STATUS
27 EFIAPI
28 NotifyOnS3SmmInitDonePpi (
29 IN EFI_PEI_SERVICES **PeiServices,
30 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
31 IN VOID *InvokePpi
32 );
33
34 //
35 // Global function
36 //
37 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {
38 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
39 &gEdkiiS3SmmInitDoneGuid,
40 NotifyOnS3SmmInitDonePpi
41 };
42
43 /**
44 S3 SMM Init Done notification function.
45
46 @param PeiServices Indirect reference to the PEI Services Table.
47 @param NotifyDesc Address of the notification descriptor data structure.
48 @param InvokePpi Address of the PPI that was invoked.
49
50 @retval EFI_SUCCESS The function completes successfully.
51
52 **/
53 EFI_STATUS
54 EFIAPI
55 NotifyOnS3SmmInitDonePpi (
56 IN EFI_PEI_SERVICES **PeiServices,
57 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
58 IN VOID *InvokePpi
59 )
60 {
61 CPU_MP_DATA *CpuMpData;
62
63 CpuMpData = GetCpuMpData ();
64
65 //
66 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
67 // So in this notify function, code need to check the current loop
68 // mode, if it is not HLT mode, code need to change loop mode back
69 // to the original mode.
70 //
71 if (CpuMpData->ApLoopMode != ApInHltLoop) {
72 CpuMpData->WakeUpByInitSipiSipi = TRUE;
73 }
74
75 return EFI_SUCCESS;
76 }
77
78 /**
79 Enable Debug Agent to support source debugging on AP function.
80
81 **/
82 VOID
83 EnableDebugAgent (
84 VOID
85 )
86 {
87 }
88
89 /**
90 Get pointer to CPU MP Data structure.
91 For BSP, the pointer is retrieved from HOB.
92 For AP, the structure is just after IDT.
93
94 @return The pointer to CPU MP Data structure.
95 **/
96 CPU_MP_DATA *
97 GetCpuMpData (
98 VOID
99 )
100 {
101 CPU_MP_DATA *CpuMpData;
102 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
103 IA32_DESCRIPTOR Idtr;
104
105 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
106 if (ApicBaseMsr.Bits.BSP == 1) {
107 CpuMpData = GetCpuMpDataFromGuidedHob ();
108 ASSERT (CpuMpData != NULL);
109 } else {
110 AsmReadIdtr (&Idtr);
111 CpuMpData = (CPU_MP_DATA *)(Idtr.Base + Idtr.Limit + 1);
112 }
113
114 return CpuMpData;
115 }
116
117 /**
118 Save the pointer to CPU MP Data structure.
119
120 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
121 **/
122 VOID
123 SaveCpuMpData (
124 IN CPU_MP_DATA *CpuMpData
125 )
126 {
127 UINT64 Data64;
128
129 //
130 // Build location of CPU MP DATA buffer in HOB
131 //
132 Data64 = (UINT64)(UINTN)CpuMpData;
133 BuildGuidDataHob (
134 &mCpuInitMpLibHobGuid,
135 (VOID *)&Data64,
136 sizeof (UINT64)
137 );
138 }
139
140 /**
141 Check if AP wakeup buffer is overlapped with existing allocated buffer.
142
143 @param[in] WakeupBufferStart AP wakeup buffer start address.
144 @param[in] WakeupBufferEnd AP wakeup buffer end address.
145
146 @retval TRUE There is overlap.
147 @retval FALSE There is no overlap.
148 **/
149 BOOLEAN
150 CheckOverlapWithAllocatedBuffer (
151 IN UINT64 WakeupBufferStart,
152 IN UINT64 WakeupBufferEnd
153 )
154 {
155 EFI_PEI_HOB_POINTERS Hob;
156 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
157 BOOLEAN Overlapped;
158 UINT64 MemoryStart;
159 UINT64 MemoryEnd;
160
161 Overlapped = FALSE;
162 //
163 // Get the HOB list for processing
164 //
165 Hob.Raw = GetHobList ();
166 //
167 // Collect memory ranges
168 //
169 while (!END_OF_HOB_LIST (Hob)) {
170 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
171 MemoryHob = Hob.MemoryAllocation;
172 MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
173 MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
174 if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
175 Overlapped = TRUE;
176 break;
177 }
178 }
179
180 Hob.Raw = GET_NEXT_HOB (Hob);
181 }
182
183 return Overlapped;
184 }
185
186 /**
187 Get available system memory below 1MB by specified size.
188
189 @param[in] WakeupBufferSize Wakeup buffer size required
190
191 @retval other Return wakeup buffer address below 1MB.
192 @retval -1 Cannot find free memory below 1MB.
193 **/
194 UINTN
195 GetWakeupBuffer (
196 IN UINTN WakeupBufferSize
197 )
198 {
199 EFI_PEI_HOB_POINTERS Hob;
200 UINT64 WakeupBufferStart;
201 UINT64 WakeupBufferEnd;
202
203 WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
204
205 //
206 // Get the HOB list for processing
207 //
208 Hob.Raw = GetHobList ();
209
210 //
211 // Collect memory ranges
212 //
213 while (!END_OF_HOB_LIST (Hob)) {
214 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
215 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
216 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
217 ((Hob.ResourceDescriptor->ResourceAttribute &
218 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
219 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
220 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
221 )) == 0)
222 )
223 {
224 //
225 // Need memory under 1MB to be collected here
226 //
227 WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
228 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
229 (WakeupBufferEnd > mSevEsPeiWakeupBuffer))
230 {
231 //
232 // SEV-ES Wakeup buffer should be under 1MB and under any previous one
233 //
234 WakeupBufferEnd = mSevEsPeiWakeupBuffer;
235 } else if (WakeupBufferEnd > BASE_1MB) {
236 //
237 // Wakeup buffer should be under 1MB
238 //
239 WakeupBufferEnd = BASE_1MB;
240 }
241
242 while (WakeupBufferEnd > WakeupBufferSize) {
243 //
244 // Wakeup buffer should be aligned on 4KB
245 //
246 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
247 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
248 break;
249 }
250
251 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
252 //
253 // If this range is overlapped with existing allocated buffer, skip it
254 // and find the next range
255 //
256 WakeupBufferEnd -= WakeupBufferSize;
257 continue;
258 }
259
260 DEBUG ((
261 DEBUG_INFO,
262 "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
263 WakeupBufferStart,
264 WakeupBufferSize
265 ));
266
267 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
268 //
269 // Next SEV-ES wakeup buffer allocation must be below this
270 // allocation
271 //
272 mSevEsPeiWakeupBuffer = WakeupBufferStart;
273 }
274
275 return (UINTN)WakeupBufferStart;
276 }
277 }
278 }
279
280 //
281 // Find the next HOB
282 //
283 Hob.Raw = GET_NEXT_HOB (Hob);
284 }
285
286 return (UINTN)-1;
287 }
288
289 /**
290 Get available EfiBootServicesCode memory below 4GB by specified size.
291
292 This buffer is required to safely transfer AP from real address mode to
293 protected mode or long mode, due to the fact that the buffer returned by
294 GetWakeupBuffer() may be marked as non-executable.
295
296 @param[in] BufferSize Wakeup transition buffer size.
297
298 @retval other Return wakeup transition buffer address below 4GB.
299 @retval 0 Cannot find free memory below 4GB.
300 **/
301 UINTN
302 GetModeTransitionBuffer (
303 IN UINTN BufferSize
304 )
305 {
306 //
307 // PEI phase doesn't need to do such transition. So simply return 0.
308 //
309 return 0;
310 }
311
312 /**
313 Return the address of the SEV-ES AP jump table.
314
315 This buffer is required in order for an SEV-ES guest to transition from
316 UEFI into an OS.
317
318 @return Return SEV-ES AP jump table buffer
319 **/
320 UINTN
321 GetSevEsAPMemory (
322 VOID
323 )
324 {
325 //
326 // PEI phase doesn't need to do such transition. So simply return 0.
327 //
328 return 0;
329 }
330
331 /**
332 Checks APs status and updates APs status if needed.
333
334 **/
335 VOID
336 CheckAndUpdateApsStatus (
337 VOID
338 )
339 {
340 }
341
342 /**
343 Build the microcode patch HOB that contains the base address and size of the
344 microcode patch stored in the memory.
345
346 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
347
348 **/
349 VOID
350 BuildMicrocodeCacheHob (
351 IN CPU_MP_DATA *CpuMpData
352 )
353 {
354 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
355 UINTN HobDataLength;
356 UINT32 Index;
357
358 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
359 sizeof (UINT64) * CpuMpData->CpuCount;
360
361 MicrocodeHob = AllocatePool (HobDataLength);
362 if (MicrocodeHob == NULL) {
363 ASSERT (FALSE);
364 return;
365 }
366
367 //
368 // Store the information of the memory region that holds the microcode patches.
369 //
370 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
371 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
372
373 //
374 // Store the detected microcode patch for each processor as well.
375 //
376 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
377 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
378 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
379 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
380 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
381 } else {
382 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
383 }
384 }
385
386 BuildGuidDataHob (
387 &gEdkiiMicrocodePatchHobGuid,
388 MicrocodeHob,
389 HobDataLength
390 );
391
392 return;
393 }
394
395 /**
396 Initialize global data for MP support.
397
398 @param[in] CpuMpData The pointer to CPU MP Data structure.
399 **/
400 VOID
401 InitMpGlobalData (
402 IN CPU_MP_DATA *CpuMpData
403 )
404 {
405 EFI_STATUS Status;
406
407 BuildMicrocodeCacheHob (CpuMpData);
408 SaveCpuMpData (CpuMpData);
409
410 ///
411 /// Install Notify
412 ///
413 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
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 if (WaitEvent != NULL) {
504 return EFI_UNSUPPORTED;
505 }
506
507 return StartupAllCPUsWorker (
508 Procedure,
509 SingleThread,
510 TRUE,
511 NULL,
512 TimeoutInMicroseconds,
513 ProcedureArgument,
514 FailedCpuList
515 );
516 }
517
518 /**
519 This service lets the caller get one enabled AP to execute a caller-provided
520 function.
521
522 @param[in] Procedure A pointer to the function to be run on the
523 designated AP of the system. See type
524 EFI_AP_PROCEDURE.
525 @param[in] ProcessorNumber The handle number of the AP. The range is
526 from 0 to the total number of logical
527 processors minus 1. The total number of
528 logical processors can be retrieved by
529 MpInitLibGetNumberOfProcessors().
530 @param[in] WaitEvent The event created by the caller with CreateEvent()
531 service. If it is NULL, then execute in
532 blocking mode. BSP waits until this AP finish
533 or TimeoutInMicroSeconds expires. If it's
534 not NULL, then execute in non-blocking mode.
535 BSP requests the function specified by
536 Procedure to be started on this AP,
537 and go on executing immediately. If this AP
538 return from Procedure or TimeoutInMicroSeconds
539 expires, this event is signaled. The BSP
540 can use the CheckEvent() or WaitForEvent()
541 services to check the state of event. Type
542 EFI_EVENT is defined in CreateEvent() in
543 the Unified Extensible Firmware Interface
544 Specification.
545 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
546 this AP to finish this Procedure, either for
547 blocking or non-blocking mode. Zero means
548 infinity. If the timeout expires before
549 this AP returns from Procedure, then Procedure
550 on the AP is terminated. The
551 AP is available for next function assigned
552 by MpInitLibStartupAllAPs() or
553 MpInitLibStartupThisAP().
554 If the timeout expires in blocking mode,
555 BSP returns EFI_TIMEOUT. If the timeout
556 expires in non-blocking mode, WaitEvent
557 is signaled with SignalEvent().
558 @param[in] ProcedureArgument The parameter passed into Procedure on the
559 specified AP.
560 @param[out] Finished If NULL, this parameter is ignored. In
561 blocking mode, this parameter is ignored.
562 In non-blocking mode, if AP returns from
563 Procedure before the timeout expires, its
564 content is set to TRUE. Otherwise, the
565 value is set to FALSE. The caller can
566 determine if the AP returned from Procedure
567 by evaluating this value.
568
569 @retval EFI_SUCCESS In blocking mode, specified AP finished before
570 the timeout expires.
571 @retval EFI_SUCCESS In non-blocking mode, the function has been
572 dispatched to specified AP.
573 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
574 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
575 signaled.
576 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
577 supported.
578 @retval EFI_DEVICE_ERROR The calling processor is an AP.
579 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
580 the specified AP has finished.
581 @retval EFI_NOT_READY The specified AP is busy.
582 @retval EFI_NOT_READY MP Initialize Library is not initialized.
583 @retval EFI_NOT_FOUND The processor with the handle specified by
584 ProcessorNumber does not exist.
585 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
586 @retval EFI_INVALID_PARAMETER Procedure is NULL.
587
588 **/
589 EFI_STATUS
590 EFIAPI
591 MpInitLibStartupThisAP (
592 IN EFI_AP_PROCEDURE Procedure,
593 IN UINTN ProcessorNumber,
594 IN EFI_EVENT WaitEvent OPTIONAL,
595 IN UINTN TimeoutInMicroseconds,
596 IN VOID *ProcedureArgument OPTIONAL,
597 OUT BOOLEAN *Finished OPTIONAL
598 )
599 {
600 if (WaitEvent != NULL) {
601 return EFI_UNSUPPORTED;
602 }
603
604 return StartupThisAPWorker (
605 Procedure,
606 ProcessorNumber,
607 NULL,
608 TimeoutInMicroseconds,
609 ProcedureArgument,
610 Finished
611 );
612 }
613
614 /**
615 This service switches the requested AP to be the BSP from that point onward.
616 This service changes the BSP for all purposes. This call can only be performed
617 by the current BSP.
618
619 @param[in] ProcessorNumber The handle number of AP that is to become the new
620 BSP. The range is from 0 to the total number of
621 logical processors minus 1. The total number of
622 logical processors can be retrieved by
623 MpInitLibGetNumberOfProcessors().
624 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
625 enabled AP. Otherwise, it will be disabled.
626
627 @retval EFI_SUCCESS BSP successfully switched.
628 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
629 this service returning.
630 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
631 @retval EFI_DEVICE_ERROR The calling processor is an AP.
632 @retval EFI_NOT_FOUND The processor with the handle specified by
633 ProcessorNumber does not exist.
634 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
635 a disabled AP.
636 @retval EFI_NOT_READY The specified AP is busy.
637 @retval EFI_NOT_READY MP Initialize Library is not initialized.
638
639 **/
640 EFI_STATUS
641 EFIAPI
642 MpInitLibSwitchBSP (
643 IN UINTN ProcessorNumber,
644 IN BOOLEAN EnableOldBSP
645 )
646 {
647 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
648 }
649
650 /**
651 This service lets the caller enable or disable an AP from this point onward.
652 This service may only be called from the BSP.
653
654 @param[in] ProcessorNumber The handle number of AP.
655 The range is from 0 to the total number of
656 logical processors minus 1. The total number of
657 logical processors can be retrieved by
658 MpInitLibGetNumberOfProcessors().
659 @param[in] EnableAP Specifies the new state for the processor for
660 enabled, FALSE for disabled.
661 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
662 the new health status of the AP. This flag
663 corresponds to StatusFlag defined in
664 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
665 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
666 bits are ignored. If it is NULL, this parameter
667 is ignored.
668
669 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
670 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
671 prior to this service returning.
672 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
673 @retval EFI_DEVICE_ERROR The calling processor is an AP.
674 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
675 does not exist.
676 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
677 @retval EFI_NOT_READY MP Initialize Library is not initialized.
678
679 **/
680 EFI_STATUS
681 EFIAPI
682 MpInitLibEnableDisableAP (
683 IN UINTN ProcessorNumber,
684 IN BOOLEAN EnableAP,
685 IN UINT32 *HealthFlag OPTIONAL
686 )
687 {
688 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
689 }
690
691 /**
692 This funtion will try to invoke platform specific microcode shadow logic to
693 relocate microcode update patches into memory.
694
695 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
696
697 @retval EFI_SUCCESS Shadow microcode success.
698 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
699 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
700 PPI/Protocol.
701 **/
702 EFI_STATUS
703 PlatformShadowMicrocode (
704 IN OUT CPU_MP_DATA *CpuMpData
705 )
706 {
707 EFI_STATUS Status;
708 EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;
709 UINTN CpuCount;
710 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;
711 UINTN Index;
712 UINTN BufferSize;
713 VOID *Buffer;
714
715 Status = PeiServicesLocatePpi (
716 &gEdkiiPeiShadowMicrocodePpiGuid,
717 0,
718 NULL,
719 (VOID **)&ShadowMicrocodePpi
720 );
721 if (EFI_ERROR (Status)) {
722 return EFI_UNSUPPORTED;
723 }
724
725 CpuCount = CpuMpData->CpuCount;
726 MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
727 if (MicrocodeCpuId == NULL) {
728 return EFI_OUT_OF_RESOURCES;
729 }
730
731 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
732 MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
733 MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
734 }
735
736 Status = ShadowMicrocodePpi->ShadowMicrocode (
737 ShadowMicrocodePpi,
738 CpuCount,
739 MicrocodeCpuId,
740 &BufferSize,
741 &Buffer
742 );
743 FreePool (MicrocodeCpuId);
744 if (EFI_ERROR (Status)) {
745 return EFI_NOT_FOUND;
746 }
747
748 CpuMpData->MicrocodePatchAddress = (UINTN)Buffer;
749 CpuMpData->MicrocodePatchRegionSize = BufferSize;
750
751 DEBUG ((
752 DEBUG_INFO,
753 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
754 __FUNCTION__,
755 CpuMpData->MicrocodePatchAddress,
756 CpuMpData->MicrocodePatchRegionSize
757 ));
758
759 return EFI_SUCCESS;
760 }