]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg: Allow AP booting under SEV-ES
[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 Return the address of the SEV-ES AP jump table.
285
286 This buffer is required in order for an SEV-ES guest to transition from
287 UEFI into an OS.
288
289 @return Return SEV-ES AP jump table buffer
290 **/
291 UINTN
292 GetSevEsAPMemory (
293 VOID
294 )
295 {
296 //
297 // PEI phase doesn't need to do such transition. So simply return 0.
298 //
299 return 0;
300 }
301
302 /**
303 Checks APs status and updates APs status if needed.
304
305 **/
306 VOID
307 CheckAndUpdateApsStatus (
308 VOID
309 )
310 {
311 }
312
313 /**
314 Build the microcode patch HOB that contains the base address and size of the
315 microcode patch stored in the memory.
316
317 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
318
319 **/
320 VOID
321 BuildMicrocodeCacheHob (
322 IN CPU_MP_DATA *CpuMpData
323 )
324 {
325 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
326 UINTN HobDataLength;
327 UINT32 Index;
328
329 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
330 sizeof (UINT64) * CpuMpData->CpuCount;
331
332 MicrocodeHob = AllocatePool (HobDataLength);
333 if (MicrocodeHob == NULL) {
334 ASSERT (FALSE);
335 return;
336 }
337
338 //
339 // Store the information of the memory region that holds the microcode patches.
340 //
341 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
342 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
343
344 //
345 // Store the detected microcode patch for each processor as well.
346 //
347 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
348 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
349 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
350 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
351 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
352 } else {
353 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
354 }
355 }
356
357 BuildGuidDataHob (
358 &gEdkiiMicrocodePatchHobGuid,
359 MicrocodeHob,
360 HobDataLength
361 );
362
363 return;
364 }
365
366 /**
367 Initialize global data for MP support.
368
369 @param[in] CpuMpData The pointer to CPU MP Data structure.
370 **/
371 VOID
372 InitMpGlobalData (
373 IN CPU_MP_DATA *CpuMpData
374 )
375 {
376 EFI_STATUS Status;
377
378 BuildMicrocodeCacheHob (CpuMpData);
379 SaveCpuMpData (CpuMpData);
380
381 ///
382 /// Install Notify
383 ///
384 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
385 ASSERT_EFI_ERROR (Status);
386 }
387
388 /**
389 This service executes a caller provided function on all enabled APs.
390
391 @param[in] Procedure A pointer to the function to be run on
392 enabled APs of the system. See type
393 EFI_AP_PROCEDURE.
394 @param[in] SingleThread If TRUE, then all the enabled APs execute
395 the function specified by Procedure one by
396 one, in ascending order of processor handle
397 number. If FALSE, then all the enabled APs
398 execute the function specified by Procedure
399 simultaneously.
400 @param[in] WaitEvent The event created by the caller with CreateEvent()
401 service. If it is NULL, then execute in
402 blocking mode. BSP waits until all APs finish
403 or TimeoutInMicroSeconds expires. If it's
404 not NULL, then execute in non-blocking mode.
405 BSP requests the function specified by
406 Procedure to be started on all the enabled
407 APs, and go on executing immediately. If
408 all return from Procedure, or TimeoutInMicroSeconds
409 expires, this event is signaled. The BSP
410 can use the CheckEvent() or WaitForEvent()
411 services to check the state of event. Type
412 EFI_EVENT is defined in CreateEvent() in
413 the Unified Extensible Firmware Interface
414 Specification.
415 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
416 APs to return from Procedure, either for
417 blocking or non-blocking mode. Zero means
418 infinity. If the timeout expires before
419 all APs return from Procedure, then Procedure
420 on the failed APs is terminated. All enabled
421 APs are available for next function assigned
422 by MpInitLibStartupAllAPs() or
423 MPInitLibStartupThisAP().
424 If the timeout expires in blocking mode,
425 BSP returns EFI_TIMEOUT. If the timeout
426 expires in non-blocking mode, WaitEvent
427 is signaled with SignalEvent().
428 @param[in] ProcedureArgument The parameter passed into Procedure for
429 all APs.
430 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
431 if all APs finish successfully, then its
432 content is set to NULL. If not all APs
433 finish before timeout expires, then its
434 content is set to address of the buffer
435 holding handle numbers of the failed APs.
436 The buffer is allocated by MP Initialization
437 library, and it's the caller's responsibility to
438 free the buffer with FreePool() service.
439 In blocking mode, it is ready for consumption
440 when the call returns. In non-blocking mode,
441 it is ready when WaitEvent is signaled. The
442 list of failed CPU is terminated by
443 END_OF_CPU_LIST.
444
445 @retval EFI_SUCCESS In blocking mode, all APs have finished before
446 the timeout expired.
447 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
448 to all enabled APs.
449 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
450 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
451 signaled.
452 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
453 supported.
454 @retval EFI_DEVICE_ERROR Caller processor is AP.
455 @retval EFI_NOT_STARTED No enabled APs exist in the system.
456 @retval EFI_NOT_READY Any enabled APs are busy.
457 @retval EFI_NOT_READY MP Initialize Library is not initialized.
458 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
459 all enabled APs have finished.
460 @retval EFI_INVALID_PARAMETER Procedure is NULL.
461
462 **/
463 EFI_STATUS
464 EFIAPI
465 MpInitLibStartupAllAPs (
466 IN EFI_AP_PROCEDURE Procedure,
467 IN BOOLEAN SingleThread,
468 IN EFI_EVENT WaitEvent OPTIONAL,
469 IN UINTN TimeoutInMicroseconds,
470 IN VOID *ProcedureArgument OPTIONAL,
471 OUT UINTN **FailedCpuList OPTIONAL
472 )
473 {
474 if (WaitEvent != NULL) {
475 return EFI_UNSUPPORTED;
476 }
477
478 return StartupAllCPUsWorker (
479 Procedure,
480 SingleThread,
481 TRUE,
482 NULL,
483 TimeoutInMicroseconds,
484 ProcedureArgument,
485 FailedCpuList
486 );
487 }
488
489 /**
490 This service lets the caller get one enabled AP to execute a caller-provided
491 function.
492
493 @param[in] Procedure A pointer to the function to be run on the
494 designated AP of the system. See type
495 EFI_AP_PROCEDURE.
496 @param[in] ProcessorNumber The handle number of the AP. The range is
497 from 0 to the total number of logical
498 processors minus 1. The total number of
499 logical processors can be retrieved by
500 MpInitLibGetNumberOfProcessors().
501 @param[in] WaitEvent The event created by the caller with CreateEvent()
502 service. If it is NULL, then execute in
503 blocking mode. BSP waits until this AP finish
504 or TimeoutInMicroSeconds expires. If it's
505 not NULL, then execute in non-blocking mode.
506 BSP requests the function specified by
507 Procedure to be started on this AP,
508 and go on executing immediately. If this AP
509 return from Procedure or TimeoutInMicroSeconds
510 expires, this event is signaled. The BSP
511 can use the CheckEvent() or WaitForEvent()
512 services to check the state of event. Type
513 EFI_EVENT is defined in CreateEvent() in
514 the Unified Extensible Firmware Interface
515 Specification.
516 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
517 this AP to finish this Procedure, either for
518 blocking or non-blocking mode. Zero means
519 infinity. If the timeout expires before
520 this AP returns from Procedure, then Procedure
521 on the AP is terminated. The
522 AP is available for next function assigned
523 by MpInitLibStartupAllAPs() or
524 MpInitLibStartupThisAP().
525 If the timeout expires in blocking mode,
526 BSP returns EFI_TIMEOUT. If the timeout
527 expires in non-blocking mode, WaitEvent
528 is signaled with SignalEvent().
529 @param[in] ProcedureArgument The parameter passed into Procedure on the
530 specified AP.
531 @param[out] Finished If NULL, this parameter is ignored. In
532 blocking mode, this parameter is ignored.
533 In non-blocking mode, if AP returns from
534 Procedure before the timeout expires, its
535 content is set to TRUE. Otherwise, the
536 value is set to FALSE. The caller can
537 determine if the AP returned from Procedure
538 by evaluating this value.
539
540 @retval EFI_SUCCESS In blocking mode, specified AP finished before
541 the timeout expires.
542 @retval EFI_SUCCESS In non-blocking mode, the function has been
543 dispatched to specified AP.
544 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
545 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
546 signaled.
547 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
548 supported.
549 @retval EFI_DEVICE_ERROR The calling processor is an AP.
550 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
551 the specified AP has finished.
552 @retval EFI_NOT_READY The specified AP is busy.
553 @retval EFI_NOT_READY MP Initialize Library is not initialized.
554 @retval EFI_NOT_FOUND The processor with the handle specified by
555 ProcessorNumber does not exist.
556 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
557 @retval EFI_INVALID_PARAMETER Procedure is NULL.
558
559 **/
560 EFI_STATUS
561 EFIAPI
562 MpInitLibStartupThisAP (
563 IN EFI_AP_PROCEDURE Procedure,
564 IN UINTN ProcessorNumber,
565 IN EFI_EVENT WaitEvent OPTIONAL,
566 IN UINTN TimeoutInMicroseconds,
567 IN VOID *ProcedureArgument OPTIONAL,
568 OUT BOOLEAN *Finished OPTIONAL
569 )
570 {
571 if (WaitEvent != NULL) {
572 return EFI_UNSUPPORTED;
573 }
574
575 return StartupThisAPWorker (
576 Procedure,
577 ProcessorNumber,
578 NULL,
579 TimeoutInMicroseconds,
580 ProcedureArgument,
581 Finished
582 );
583 }
584
585 /**
586 This service switches the requested AP to be the BSP from that point onward.
587 This service changes the BSP for all purposes. This call can only be performed
588 by the current BSP.
589
590 @param[in] ProcessorNumber The handle number of AP that is to become the new
591 BSP. The range is from 0 to the total number of
592 logical processors minus 1. The total number of
593 logical processors can be retrieved by
594 MpInitLibGetNumberOfProcessors().
595 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
596 enabled AP. Otherwise, it will be disabled.
597
598 @retval EFI_SUCCESS BSP successfully switched.
599 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
600 this service returning.
601 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
602 @retval EFI_DEVICE_ERROR The calling processor is an AP.
603 @retval EFI_NOT_FOUND The processor with the handle specified by
604 ProcessorNumber does not exist.
605 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
606 a disabled AP.
607 @retval EFI_NOT_READY The specified AP is busy.
608 @retval EFI_NOT_READY MP Initialize Library is not initialized.
609
610 **/
611 EFI_STATUS
612 EFIAPI
613 MpInitLibSwitchBSP (
614 IN UINTN ProcessorNumber,
615 IN BOOLEAN EnableOldBSP
616 )
617 {
618 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
619 }
620
621 /**
622 This service lets the caller enable or disable an AP from this point onward.
623 This service may only be called from the BSP.
624
625 @param[in] ProcessorNumber The handle number of AP.
626 The range is from 0 to the total number of
627 logical processors minus 1. The total number of
628 logical processors can be retrieved by
629 MpInitLibGetNumberOfProcessors().
630 @param[in] EnableAP Specifies the new state for the processor for
631 enabled, FALSE for disabled.
632 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
633 the new health status of the AP. This flag
634 corresponds to StatusFlag defined in
635 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
636 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
637 bits are ignored. If it is NULL, this parameter
638 is ignored.
639
640 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
641 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
642 prior to this service returning.
643 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
644 @retval EFI_DEVICE_ERROR The calling processor is an AP.
645 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
646 does not exist.
647 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
648 @retval EFI_NOT_READY MP Initialize Library is not initialized.
649
650 **/
651 EFI_STATUS
652 EFIAPI
653 MpInitLibEnableDisableAP (
654 IN UINTN ProcessorNumber,
655 IN BOOLEAN EnableAP,
656 IN UINT32 *HealthFlag OPTIONAL
657 )
658 {
659 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
660 }
661
662 /**
663 This funtion will try to invoke platform specific microcode shadow logic to
664 relocate microcode update patches into memory.
665
666 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
667
668 @retval EFI_SUCCESS Shadow microcode success.
669 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
670 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
671 PPI/Protocol.
672 **/
673 EFI_STATUS
674 PlatformShadowMicrocode (
675 IN OUT CPU_MP_DATA *CpuMpData
676 )
677 {
678 EFI_STATUS Status;
679 EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;
680 UINTN CpuCount;
681 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;
682 UINTN Index;
683 UINTN BufferSize;
684 VOID *Buffer;
685
686 Status = PeiServicesLocatePpi (
687 &gEdkiiPeiShadowMicrocodePpiGuid,
688 0,
689 NULL,
690 (VOID **) &ShadowMicrocodePpi
691 );
692 if (EFI_ERROR (Status)) {
693 return EFI_UNSUPPORTED;
694 }
695
696 CpuCount = CpuMpData->CpuCount;
697 MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *) AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
698 if (MicrocodeCpuId == NULL) {
699 return EFI_OUT_OF_RESOURCES;
700 }
701
702 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
703 MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
704 MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
705 }
706
707 Status = ShadowMicrocodePpi->ShadowMicrocode (
708 ShadowMicrocodePpi,
709 CpuCount,
710 MicrocodeCpuId,
711 &BufferSize,
712 &Buffer
713 );
714 FreePool (MicrocodeCpuId);
715 if (EFI_ERROR (Status)) {
716 return EFI_NOT_FOUND;
717 }
718
719 CpuMpData->MicrocodePatchAddress = (UINTN) Buffer;
720 CpuMpData->MicrocodePatchRegionSize = BufferSize;
721
722 DEBUG ((
723 DEBUG_INFO,
724 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
725 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
726 ));
727
728 return EFI_SUCCESS;
729 }