TianoCore EDK2 master
PeiMpLib.c
Go to the documentation of this file.
1
9#include "MpLib.h"
11#include <Guid/S3SmmInitDone.h>
12#include <Ppi/ShadowMicrocode.h>
13
14STATIC UINT64 mSevEsPeiWakeupBuffer = BASE_1MB;
15
27EFIAPI
29 IN EFI_PEI_SERVICES **PeiServices,
30 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
31 IN VOID *InvokePpi
32 );
33
34//
35// Global function
36//
37EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {
38 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
39 &gEdkiiS3SmmInitDoneGuid,
41};
42
54EFIAPI
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
82VOID
84 VOID
85 )
86{
87}
88
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
122VOID
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;
134 &mCpuInitMpLibHobGuid,
135 (VOID *)&Data64,
136 sizeof (UINT64)
137 );
138}
139
149BOOLEAN
151 IN UINT64 WakeupBufferStart,
152 IN UINT64 WakeupBufferEnd
153 )
154{
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
194UINTN
196 IN UINTN WakeupBufferSize
197 )
198{
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
301UINTN
303 IN UINTN BufferSize
304 )
305{
306 EFI_STATUS Status;
307 EFI_PHYSICAL_ADDRESS Address;
308
309 Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES (BufferSize), &Address);
310 if (EFI_ERROR (Status)) {
311 Address = 0;
312 }
313
314 return (UINTN)Address;
315}
316
325UINTN
327 VOID
328 )
329{
330 //
331 // PEI phase doesn't need to do such transition. So simply return 0.
332 //
333 return 0;
334}
335
340VOID
342 VOID
343 )
344{
345}
346
354VOID
356 IN CPU_MP_DATA *CpuMpData
357 )
358{
359 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
360 UINTN HobDataLength;
361 UINT32 Index;
362
363 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
364 sizeof (UINT64) * CpuMpData->CpuCount;
365
366 MicrocodeHob = AllocatePool (HobDataLength);
367 if (MicrocodeHob == NULL) {
368 ASSERT (FALSE);
369 return;
370 }
371
372 //
373 // Store the information of the memory region that holds the microcode patches.
374 //
375 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
376 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
377
378 //
379 // Store the detected microcode patch for each processor as well.
380 //
381 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
382 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
383 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
384 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
385 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
386 } else {
387 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
388 }
389 }
390
392 &gEdkiiMicrocodePatchHobGuid,
393 MicrocodeHob,
394 HobDataLength
395 );
396
397 return;
398}
399
405VOID
407 IN CPU_MP_DATA *CpuMpData
408 )
409{
410 EFI_STATUS Status;
411
412 BuildMicrocodeCacheHob (CpuMpData);
413 SaveCpuMpData (CpuMpData);
414
418 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
419 ASSERT_EFI_ERROR (Status);
420}
421
498EFIAPI
500 IN EFI_AP_PROCEDURE Procedure,
501 IN BOOLEAN SingleThread,
502 IN EFI_EVENT WaitEvent OPTIONAL,
503 IN UINTN TimeoutInMicroseconds,
504 IN VOID *ProcedureArgument OPTIONAL,
505 OUT UINTN **FailedCpuList OPTIONAL
506 )
507{
508 if (WaitEvent != NULL) {
509 return EFI_UNSUPPORTED;
510 }
511
512 return StartupAllCPUsWorker (
513 Procedure,
514 SingleThread,
515 TRUE,
516 NULL,
517 TimeoutInMicroseconds,
518 ProcedureArgument,
519 FailedCpuList
520 );
521}
522
595EFIAPI
597 IN EFI_AP_PROCEDURE Procedure,
598 IN UINTN ProcessorNumber,
599 IN EFI_EVENT WaitEvent OPTIONAL,
600 IN UINTN TimeoutInMicroseconds,
601 IN VOID *ProcedureArgument OPTIONAL,
602 OUT BOOLEAN *Finished OPTIONAL
603 )
604{
605 if (WaitEvent != NULL) {
606 return EFI_UNSUPPORTED;
607 }
608
609 return StartupThisAPWorker (
610 Procedure,
611 ProcessorNumber,
612 NULL,
613 TimeoutInMicroseconds,
614 ProcedureArgument,
615 Finished
616 );
617}
618
646EFIAPI
648 IN UINTN ProcessorNumber,
649 IN BOOLEAN EnableOldBSP
650 )
651{
652 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
653}
654
686EFIAPI
688 IN UINTN ProcessorNumber,
689 IN BOOLEAN EnableAP,
690 IN UINT32 *HealthFlag OPTIONAL
691 )
692{
693 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
694}
695
709 IN OUT CPU_MP_DATA *CpuMpData
710 )
711{
712 EFI_STATUS Status;
713 EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;
714 UINTN CpuCount;
715 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;
716 UINTN Index;
717 UINTN BufferSize;
718 VOID *Buffer;
719
720 Status = PeiServicesLocatePpi (
721 &gEdkiiPeiShadowMicrocodePpiGuid,
722 0,
723 NULL,
724 (VOID **)&ShadowMicrocodePpi
725 );
726 if (EFI_ERROR (Status)) {
727 return EFI_UNSUPPORTED;
728 }
729
730 CpuCount = CpuMpData->CpuCount;
731 MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
732 if (MicrocodeCpuId == NULL) {
733 return EFI_OUT_OF_RESOURCES;
734 }
735
736 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
737 MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
738 MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
739 }
740
741 Status = ShadowMicrocodePpi->ShadowMicrocode (
742 ShadowMicrocodePpi,
743 CpuCount,
744 MicrocodeCpuId,
745 &BufferSize,
746 &Buffer
747 );
748 FreePool (MicrocodeCpuId);
749 if (EFI_ERROR (Status)) {
750 return EFI_NOT_FOUND;
751 }
752
753 CpuMpData->MicrocodePatchAddress = (UINTN)Buffer;
754 CpuMpData->MicrocodePatchRegionSize = BufferSize;
755
756 DEBUG ((
757 DEBUG_INFO,
758 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
759 __FUNCTION__,
760 CpuMpData->MicrocodePatchAddress,
761 CpuMpData->MicrocodePatchRegionSize
762 ));
763
764 return EFI_SUCCESS;
765}
UINT64 UINTN
VOID *EFIAPI BuildGuidDataHob(IN CONST EFI_GUID *Guid, IN VOID *Data, IN UINTN DataLength)
Definition: HobLib.c:375
VOID *EFIAPI GetHobList(VOID)
Definition: HobLib.c:76
#define NULL
Definition: Base.h:312
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:440
#define DEBUG(Expression)
Definition: DebugLib.h:417
#define ASSERT(Expression)
Definition: DebugLib.h:391
STATIC BOOLEAN EFIAPI ConfidentialComputingGuestHas(IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI PeiServicesLocatePpi(IN CONST EFI_GUID *Guid, IN UINTN Instance, IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, IN OUT VOID **Ppi)
EFI_STATUS EFIAPI PeiServicesNotifyPpi(IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList)
EFI_STATUS EFIAPI PeiServicesAllocatePages(IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, OUT EFI_PHYSICAL_ADDRESS *Memory)
#define GET_NEXT_HOB(HobStart)
Definition: HobLib.h:515
#define END_OF_HOB_LIST(HobStart)
Definition: HobLib.h:531
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
#define MSR_IA32_APIC_BASE
EFI_STATUS StartupThisAPWorker(IN EFI_AP_PROCEDURE Procedure, IN UINTN ProcessorNumber, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT BOOLEAN *Finished OPTIONAL)
Definition: MpLib.c:2626
CPU_MP_DATA * GetCpuMpDataFromGuidedHob(VOID)
Definition: MpLib.c:2720
EFI_STATUS EnableDisableApWorker(IN UINTN ProcessorNumber, IN BOOLEAN EnableAP, IN UINT32 *HealthFlag OPTIONAL)
Definition: MpLib.c:2295
EFI_STATUS StartupAllCPUsWorker(IN EFI_AP_PROCEDURE Procedure, IN BOOLEAN SingleThread, IN BOOLEAN ExcludeBsp, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT UINTN **FailedCpuList OPTIONAL)
Definition: MpLib.c:2468
EFI_STATUS SwitchBSPWorker(IN UINTN ProcessorNumber, IN BOOLEAN EnableOldBSP)
Definition: MpLib.c:2152
EFI_STATUS EFIAPI MpInitLibEnableDisableAP(IN UINTN ProcessorNumber, IN BOOLEAN EnableAP, IN UINT32 *HealthFlag OPTIONAL)
Definition: PeiMpLib.c:687
EFI_STATUS EFIAPI MpInitLibStartupAllAPs(IN EFI_AP_PROCEDURE Procedure, IN BOOLEAN SingleThread, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT UINTN **FailedCpuList OPTIONAL)
Definition: PeiMpLib.c:499
VOID CheckAndUpdateApsStatus(VOID)
Definition: PeiMpLib.c:341
UINTN GetWakeupBuffer(IN UINTN WakeupBufferSize)
Definition: PeiMpLib.c:195
EFI_STATUS EFIAPI MpInitLibSwitchBSP(IN UINTN ProcessorNumber, IN BOOLEAN EnableOldBSP)
Definition: PeiMpLib.c:647
VOID BuildMicrocodeCacheHob(IN CPU_MP_DATA *CpuMpData)
Definition: PeiMpLib.c:355
BOOLEAN CheckOverlapWithAllocatedBuffer(IN UINT64 WakeupBufferStart, IN UINT64 WakeupBufferEnd)
Definition: PeiMpLib.c:150
UINTN AllocateCodeBuffer(IN UINTN BufferSize)
Definition: PeiMpLib.c:302
EFI_STATUS EFIAPI NotifyOnS3SmmInitDonePpi(IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, IN VOID *InvokePpi)
Definition: PeiMpLib.c:55
CPU_MP_DATA * GetCpuMpData(VOID)
Definition: PeiMpLib.c:97
EFI_STATUS PlatformShadowMicrocode(IN OUT CPU_MP_DATA *CpuMpData)
Definition: PeiMpLib.c:708
UINTN GetSevEsAPMemory(VOID)
Definition: PeiMpLib.c:326
VOID InitMpGlobalData(IN CPU_MP_DATA *CpuMpData)
Definition: PeiMpLib.c:406
VOID EnableDebugAgent(VOID)
Definition: PeiMpLib.c:83
EFI_STATUS EFIAPI MpInitLibStartupThisAP(IN EFI_AP_PROCEDURE Procedure, IN UINTN ProcessorNumber, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT BOOLEAN *Finished OPTIONAL)
Definition: PeiMpLib.c:596
VOID SaveCpuMpData(IN CPU_MP_DATA *CpuMpData)
Definition: PeiMpLib.c:123
VOID(EFIAPI * EFI_AP_PROCEDURE)(IN OUT VOID *Buffer)
Definition: PiMultiPhase.h:191
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:49
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:28
VOID * EFI_EVENT
Definition: UefiBaseType.h:36
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:197
#define EFI_SUCCESS
Definition: UefiBaseType.h:111
@ EfiBootServicesCode
VOID EFIAPI AsmReadIdtr(OUT IA32_DESCRIPTOR *Idtr)
Definition: X86ReadIdtr.c:24
EFI_PHYSICAL_ADDRESS MemoryBaseAddress
Definition: PiHob.h:119
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor
Definition: PiHob.h:153
EFI_PHYSICAL_ADDRESS PhysicalStart
Definition: PiHob.h:325
EFI_RESOURCE_TYPE ResourceType
Definition: PiHob.h:317
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute
Definition: PiHob.h:321
struct MSR_IA32_APIC_BASE_REGISTER::@539 Bits