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