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