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