]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
MpInitLib: Only allocate below 1MB memory for 16bit code
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
1 /** @file
2 CPU MP Initialize Library common functions.
3
4 Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "MpLib.h"
12 #include <Library/VmgExitLib.h>
13 #include <Register/Amd/Fam17Msr.h>
14 #include <Register/Amd/Ghcb.h>
15
16 EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
17
18 /**
19 The function will check if BSP Execute Disable is enabled.
20
21 DxeIpl may have enabled Execute Disable for BSP, APs need to
22 get the status and sync up the settings.
23 If BSP's CR0.Paging is not set, BSP execute Disble feature is
24 not working actually.
25
26 @retval TRUE BSP Execute Disable is enabled.
27 @retval FALSE BSP Execute Disable is not enabled.
28 **/
29 BOOLEAN
30 IsBspExecuteDisableEnabled (
31 VOID
32 )
33 {
34 UINT32 Eax;
35 CPUID_EXTENDED_CPU_SIG_EDX Edx;
36 MSR_IA32_EFER_REGISTER EferMsr;
37 BOOLEAN Enabled;
38 IA32_CR0 Cr0;
39
40 Enabled = FALSE;
41 Cr0.UintN = AsmReadCr0 ();
42 if (Cr0.Bits.PG != 0) {
43 //
44 // If CR0 Paging bit is set
45 //
46 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
47 if (Eax >= CPUID_EXTENDED_CPU_SIG) {
48 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
49 //
50 // CPUID 0x80000001
51 // Bit 20: Execute Disable Bit available.
52 //
53 if (Edx.Bits.NX != 0) {
54 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
55 //
56 // MSR 0xC0000080
57 // Bit 11: Execute Disable Bit enable.
58 //
59 if (EferMsr.Bits.NXE != 0) {
60 Enabled = TRUE;
61 }
62 }
63 }
64 }
65
66 return Enabled;
67 }
68
69 /**
70 Worker function for SwitchBSP().
71
72 Worker function for SwitchBSP(), assigned to the AP which is intended
73 to become BSP.
74
75 @param[in] Buffer Pointer to CPU MP Data
76 **/
77 VOID
78 EFIAPI
79 FutureBSPProc (
80 IN VOID *Buffer
81 )
82 {
83 CPU_MP_DATA *DataInHob;
84
85 DataInHob = (CPU_MP_DATA *)Buffer;
86 AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
87 }
88
89 /**
90 Get the Application Processors state.
91
92 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
93
94 @return The AP status
95 **/
96 CPU_STATE
97 GetApState (
98 IN CPU_AP_DATA *CpuData
99 )
100 {
101 return CpuData->State;
102 }
103
104 /**
105 Set the Application Processors state.
106
107 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
108 @param[in] State The AP status
109 **/
110 VOID
111 SetApState (
112 IN CPU_AP_DATA *CpuData,
113 IN CPU_STATE State
114 )
115 {
116 AcquireSpinLock (&CpuData->ApLock);
117 CpuData->State = State;
118 ReleaseSpinLock (&CpuData->ApLock);
119 }
120
121 /**
122 Save BSP's local APIC timer setting.
123
124 @param[in] CpuMpData Pointer to CPU MP Data
125 **/
126 VOID
127 SaveLocalApicTimerSetting (
128 IN CPU_MP_DATA *CpuMpData
129 )
130 {
131 //
132 // Record the current local APIC timer setting of BSP
133 //
134 GetApicTimerState (
135 &CpuMpData->DivideValue,
136 &CpuMpData->PeriodicMode,
137 &CpuMpData->Vector
138 );
139 CpuMpData->CurrentTimerCount = GetApicTimerCurrentCount ();
140 CpuMpData->TimerInterruptState = GetApicTimerInterruptState ();
141 }
142
143 /**
144 Sync local APIC timer setting from BSP to AP.
145
146 @param[in] CpuMpData Pointer to CPU MP Data
147 **/
148 VOID
149 SyncLocalApicTimerSetting (
150 IN CPU_MP_DATA *CpuMpData
151 )
152 {
153 //
154 // Sync local APIC timer setting from BSP to AP
155 //
156 InitializeApicTimer (
157 CpuMpData->DivideValue,
158 CpuMpData->CurrentTimerCount,
159 CpuMpData->PeriodicMode,
160 CpuMpData->Vector
161 );
162 //
163 // Disable AP's local APIC timer interrupt
164 //
165 DisableApicTimerInterrupt ();
166 }
167
168 /**
169 Save the volatile registers required to be restored following INIT IPI.
170
171 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
172 **/
173 VOID
174 SaveVolatileRegisters (
175 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
176 )
177 {
178 CPUID_VERSION_INFO_EDX VersionInfoEdx;
179
180 VolatileRegisters->Cr0 = AsmReadCr0 ();
181 VolatileRegisters->Cr3 = AsmReadCr3 ();
182 VolatileRegisters->Cr4 = AsmReadCr4 ();
183
184 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
185 if (VersionInfoEdx.Bits.DE != 0) {
186 //
187 // If processor supports Debugging Extensions feature
188 // by CPUID.[EAX=01H]:EDX.BIT2
189 //
190 VolatileRegisters->Dr0 = AsmReadDr0 ();
191 VolatileRegisters->Dr1 = AsmReadDr1 ();
192 VolatileRegisters->Dr2 = AsmReadDr2 ();
193 VolatileRegisters->Dr3 = AsmReadDr3 ();
194 VolatileRegisters->Dr6 = AsmReadDr6 ();
195 VolatileRegisters->Dr7 = AsmReadDr7 ();
196 }
197
198 AsmReadGdtr (&VolatileRegisters->Gdtr);
199 AsmReadIdtr (&VolatileRegisters->Idtr);
200 VolatileRegisters->Tr = AsmReadTr ();
201 }
202
203 /**
204 Restore the volatile registers following INIT IPI.
205
206 @param[in] VolatileRegisters Pointer to volatile resisters
207 @param[in] IsRestoreDr TRUE: Restore DRx if supported
208 FALSE: Do not restore DRx
209 **/
210 VOID
211 RestoreVolatileRegisters (
212 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
213 IN BOOLEAN IsRestoreDr
214 )
215 {
216 CPUID_VERSION_INFO_EDX VersionInfoEdx;
217 IA32_TSS_DESCRIPTOR *Tss;
218
219 AsmWriteCr3 (VolatileRegisters->Cr3);
220 AsmWriteCr4 (VolatileRegisters->Cr4);
221 AsmWriteCr0 (VolatileRegisters->Cr0);
222
223 if (IsRestoreDr) {
224 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
225 if (VersionInfoEdx.Bits.DE != 0) {
226 //
227 // If processor supports Debugging Extensions feature
228 // by CPUID.[EAX=01H]:EDX.BIT2
229 //
230 AsmWriteDr0 (VolatileRegisters->Dr0);
231 AsmWriteDr1 (VolatileRegisters->Dr1);
232 AsmWriteDr2 (VolatileRegisters->Dr2);
233 AsmWriteDr3 (VolatileRegisters->Dr3);
234 AsmWriteDr6 (VolatileRegisters->Dr6);
235 AsmWriteDr7 (VolatileRegisters->Dr7);
236 }
237 }
238
239 AsmWriteGdtr (&VolatileRegisters->Gdtr);
240 AsmWriteIdtr (&VolatileRegisters->Idtr);
241 if ((VolatileRegisters->Tr != 0) &&
242 (VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit))
243 {
244 Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +
245 VolatileRegisters->Tr);
246 if (Tss->Bits.P == 1) {
247 Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case
248 AsmWriteTr (VolatileRegisters->Tr);
249 }
250 }
251 }
252
253 /**
254 Detect whether Mwait-monitor feature is supported.
255
256 @retval TRUE Mwait-monitor feature is supported.
257 @retval FALSE Mwait-monitor feature is not supported.
258 **/
259 BOOLEAN
260 IsMwaitSupport (
261 VOID
262 )
263 {
264 CPUID_VERSION_INFO_ECX VersionInfoEcx;
265
266 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
267 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
268 }
269
270 /**
271 Get AP loop mode.
272
273 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
274
275 @return The AP loop mode.
276 **/
277 UINT8
278 GetApLoopMode (
279 OUT UINT32 *MonitorFilterSize
280 )
281 {
282 UINT8 ApLoopMode;
283 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
284
285 ASSERT (MonitorFilterSize != NULL);
286
287 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
288 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
289 if (ApLoopMode == ApInMwaitLoop) {
290 if (!IsMwaitSupport ()) {
291 //
292 // If processor does not support MONITOR/MWAIT feature,
293 // force AP in Hlt-loop mode
294 //
295 ApLoopMode = ApInHltLoop;
296 }
297
298 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
299 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
300 {
301 //
302 // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
303 // mode in order to use the GHCB protocol for starting APs
304 //
305 ApLoopMode = ApInHltLoop;
306 }
307 }
308
309 if (ApLoopMode != ApInMwaitLoop) {
310 *MonitorFilterSize = sizeof (UINT32);
311 } else {
312 //
313 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
314 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
315 //
316 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
317 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
318 }
319
320 return ApLoopMode;
321 }
322
323 /**
324 Sort the APIC ID of all processors.
325
326 This function sorts the APIC ID of all processors so that processor number is
327 assigned in the ascending order of APIC ID which eases MP debugging.
328
329 @param[in] CpuMpData Pointer to PEI CPU MP Data
330 **/
331 VOID
332 SortApicId (
333 IN CPU_MP_DATA *CpuMpData
334 )
335 {
336 UINTN Index1;
337 UINTN Index2;
338 UINTN Index3;
339 UINT32 ApicId;
340 CPU_INFO_IN_HOB CpuInfo;
341 UINT32 ApCount;
342 CPU_INFO_IN_HOB *CpuInfoInHob;
343 volatile UINT32 *StartupApSignal;
344
345 ApCount = CpuMpData->CpuCount - 1;
346 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
347 if (ApCount != 0) {
348 for (Index1 = 0; Index1 < ApCount; Index1++) {
349 Index3 = Index1;
350 //
351 // Sort key is the hardware default APIC ID
352 //
353 ApicId = CpuInfoInHob[Index1].ApicId;
354 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
355 if (ApicId > CpuInfoInHob[Index2].ApicId) {
356 Index3 = Index2;
357 ApicId = CpuInfoInHob[Index2].ApicId;
358 }
359 }
360
361 if (Index3 != Index1) {
362 CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));
363 CopyMem (
364 &CpuInfoInHob[Index3],
365 &CpuInfoInHob[Index1],
366 sizeof (CPU_INFO_IN_HOB)
367 );
368 CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));
369
370 //
371 // Also exchange the StartupApSignal.
372 //
373 StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;
374 CpuMpData->CpuData[Index3].StartupApSignal =
375 CpuMpData->CpuData[Index1].StartupApSignal;
376 CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;
377 }
378 }
379
380 //
381 // Get the processor number for the BSP
382 //
383 ApicId = GetInitialApicId ();
384 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
385 if (CpuInfoInHob[Index1].ApicId == ApicId) {
386 CpuMpData->BspNumber = (UINT32)Index1;
387 break;
388 }
389 }
390 }
391 }
392
393 /**
394 Enable x2APIC mode on APs.
395
396 @param[in, out] Buffer Pointer to private data buffer.
397 **/
398 VOID
399 EFIAPI
400 ApFuncEnableX2Apic (
401 IN OUT VOID *Buffer
402 )
403 {
404 SetApicMode (LOCAL_APIC_MODE_X2APIC);
405 }
406
407 /**
408 Do sync on APs.
409
410 @param[in, out] Buffer Pointer to private data buffer.
411 **/
412 VOID
413 EFIAPI
414 ApInitializeSync (
415 IN OUT VOID *Buffer
416 )
417 {
418 CPU_MP_DATA *CpuMpData;
419 UINTN ProcessorNumber;
420 EFI_STATUS Status;
421
422 CpuMpData = (CPU_MP_DATA *)Buffer;
423 Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);
424 ASSERT_EFI_ERROR (Status);
425 //
426 // Load microcode on AP
427 //
428 MicrocodeDetect (CpuMpData, ProcessorNumber);
429 //
430 // Sync BSP's MTRR table to AP
431 //
432 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
433 }
434
435 /**
436 Find the current Processor number by APIC ID.
437
438 @param[in] CpuMpData Pointer to PEI CPU MP Data
439 @param[out] ProcessorNumber Return the pocessor number found
440
441 @retval EFI_SUCCESS ProcessorNumber is found and returned.
442 @retval EFI_NOT_FOUND ProcessorNumber is not found.
443 **/
444 EFI_STATUS
445 GetProcessorNumber (
446 IN CPU_MP_DATA *CpuMpData,
447 OUT UINTN *ProcessorNumber
448 )
449 {
450 UINTN TotalProcessorNumber;
451 UINTN Index;
452 CPU_INFO_IN_HOB *CpuInfoInHob;
453 UINT32 CurrentApicId;
454
455 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
456
457 TotalProcessorNumber = CpuMpData->CpuCount;
458 CurrentApicId = GetApicId ();
459 for (Index = 0; Index < TotalProcessorNumber; Index++) {
460 if (CpuInfoInHob[Index].ApicId == CurrentApicId) {
461 *ProcessorNumber = Index;
462 return EFI_SUCCESS;
463 }
464 }
465
466 return EFI_NOT_FOUND;
467 }
468
469 /**
470 This function will get CPU count in the system.
471
472 @param[in] CpuMpData Pointer to PEI CPU MP Data
473
474 @return CPU count detected
475 **/
476 UINTN
477 CollectProcessorCount (
478 IN CPU_MP_DATA *CpuMpData
479 )
480 {
481 UINTN Index;
482 CPU_INFO_IN_HOB *CpuInfoInHob;
483 BOOLEAN X2Apic;
484
485 //
486 // Send 1st broadcast IPI to APs to wakeup APs
487 //
488 CpuMpData->InitFlag = ApInitConfig;
489 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);
490 CpuMpData->InitFlag = ApInitDone;
491 //
492 // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
493 // FinishedCount is the number of check-in APs.
494 //
495 CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;
496 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
497
498 //
499 // Enable x2APIC mode if
500 // 1. Number of CPU is greater than 255; or
501 // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.
502 //
503 X2Apic = FALSE;
504 if (CpuMpData->CpuCount > 255) {
505 //
506 // If there are more than 255 processor found, force to enable X2APIC
507 //
508 X2Apic = TRUE;
509 } else {
510 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
511 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
512 if (CpuInfoInHob[Index].InitialApicId >= 0xFF) {
513 X2Apic = TRUE;
514 break;
515 }
516 }
517 }
518
519 if (X2Apic) {
520 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
521 //
522 // Wakeup all APs to enable x2APIC mode
523 //
524 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL, TRUE);
525 //
526 // Wait for all known APs finished
527 //
528 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
529 CpuPause ();
530 }
531
532 //
533 // Enable x2APIC on BSP
534 //
535 SetApicMode (LOCAL_APIC_MODE_X2APIC);
536 //
537 // Set BSP/Aps state to IDLE
538 //
539 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
540 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
541 }
542 }
543
544 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
545 //
546 // Sort BSP/Aps by CPU APIC ID in ascending order
547 //
548 SortApicId (CpuMpData);
549
550 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
551
552 return CpuMpData->CpuCount;
553 }
554
555 /**
556 Initialize CPU AP Data when AP is wakeup at the first time.
557
558 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
559 @param[in] ProcessorNumber The handle number of processor
560 @param[in] BistData Processor BIST data
561 @param[in] ApTopOfStack Top of AP stack
562
563 **/
564 VOID
565 InitializeApData (
566 IN OUT CPU_MP_DATA *CpuMpData,
567 IN UINTN ProcessorNumber,
568 IN UINT32 BistData,
569 IN UINT64 ApTopOfStack
570 )
571 {
572 CPU_INFO_IN_HOB *CpuInfoInHob;
573 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
574
575 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
576 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
577 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
578 CpuInfoInHob[ProcessorNumber].Health = BistData;
579 CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;
580
581 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
582 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
583
584 //
585 // NOTE: PlatformId is not relevant on AMD platforms.
586 //
587 if (!StandardSignatureIsAuthenticAMD ()) {
588 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
589 CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;
590 }
591
592 AsmCpuid (
593 CPUID_VERSION_INFO,
594 &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature,
595 NULL,
596 NULL,
597 NULL
598 );
599
600 InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock);
601 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
602 }
603
604 /**
605 This function will be called from AP reset code if BSP uses WakeUpAP.
606
607 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
608 @param[in] ApIndex Number of current executing AP
609 **/
610 VOID
611 EFIAPI
612 ApWakeupFunction (
613 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
614 IN UINTN ApIndex
615 )
616 {
617 CPU_MP_DATA *CpuMpData;
618 UINTN ProcessorNumber;
619 EFI_AP_PROCEDURE Procedure;
620 VOID *Parameter;
621 UINT32 BistData;
622 volatile UINT32 *ApStartupSignalBuffer;
623 CPU_INFO_IN_HOB *CpuInfoInHob;
624 UINT64 ApTopOfStack;
625 UINTN CurrentApicMode;
626
627 //
628 // AP finished assembly code and begin to execute C code
629 //
630 CpuMpData = ExchangeInfo->CpuMpData;
631
632 //
633 // AP's local APIC settings will be lost after received INIT IPI
634 // We need to re-initialize them at here
635 //
636 ProgramVirtualWireMode ();
637 //
638 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
639 //
640 DisableLvtInterrupts ();
641 SyncLocalApicTimerSetting (CpuMpData);
642
643 CurrentApicMode = GetApicMode ();
644 while (TRUE) {
645 if (CpuMpData->InitFlag == ApInitConfig) {
646 ProcessorNumber = ApIndex;
647 //
648 // This is first time AP wakeup, get BIST information from AP stack
649 //
650 ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;
651 BistData = *(UINT32 *)((UINTN)ApTopOfStack - sizeof (UINTN));
652 //
653 // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,
654 // to initialize AP in InitConfig path.
655 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.
656 //
657 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
658 InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);
659 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
660 } else {
661 //
662 // Execute AP function if AP is ready
663 //
664 GetProcessorNumber (CpuMpData, &ProcessorNumber);
665 //
666 // Clear AP start-up signal when AP waken up
667 //
668 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
669 InterlockedCompareExchange32 (
670 (UINT32 *)ApStartupSignalBuffer,
671 WAKEUP_AP_SIGNAL,
672 0
673 );
674
675 if (CpuMpData->InitFlag == ApInitReconfig) {
676 //
677 // ApInitReconfig happens when:
678 // 1. AP is re-enabled after it's disabled, in either PEI or DXE phase.
679 // 2. AP is initialized in DXE phase.
680 // In either case, use the volatile registers value derived from BSP.
681 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a
682 // different IDT shared by all APs.
683 //
684 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
685 } else {
686 if (CpuMpData->ApLoopMode == ApInHltLoop) {
687 //
688 // Restore AP's volatile registers saved before AP is halted
689 //
690 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
691 } else {
692 //
693 // The CPU driver might not flush TLB for APs on spot after updating
694 // page attributes. AP in mwait loop mode needs to take care of it when
695 // woken up.
696 //
697 CpuFlushTlb ();
698 }
699 }
700
701 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
702 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
703 Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
704 if (Procedure != NULL) {
705 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
706 //
707 // Enable source debugging on AP function
708 //
709 EnableDebugAgent ();
710 //
711 // Invoke AP function here
712 //
713 Procedure (Parameter);
714 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
715 if (CpuMpData->SwitchBspFlag) {
716 //
717 // Re-get the processor number due to BSP/AP maybe exchange in AP function
718 //
719 GetProcessorNumber (CpuMpData, &ProcessorNumber);
720 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
721 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
722 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
723 CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack;
724 } else {
725 if ((CpuInfoInHob[ProcessorNumber].ApicId != GetApicId ()) ||
726 (CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()))
727 {
728 if (CurrentApicMode != GetApicMode ()) {
729 //
730 // If APIC mode change happened during AP function execution,
731 // we do not support APIC ID value changed.
732 //
733 ASSERT (FALSE);
734 CpuDeadLoop ();
735 } else {
736 //
737 // Re-get the CPU APICID and Initial APICID if they are changed
738 //
739 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
740 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
741 }
742 }
743 }
744 }
745
746 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
747 }
748 }
749
750 if (CpuMpData->ApLoopMode == ApInHltLoop) {
751 //
752 // Save AP volatile registers
753 //
754 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
755 }
756
757 //
758 // AP finished executing C code
759 //
760 InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);
761
762 if (CpuMpData->InitFlag == ApInitConfig) {
763 //
764 // Delay decrementing the APs executing count when SEV-ES is enabled
765 // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
766 // performs another INIT-SIPI-SIPI sequence.
767 //
768 if (!CpuMpData->UseSevEsAPMethod) {
769 InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
770 }
771 }
772
773 //
774 // Place AP is specified loop mode
775 //
776 if (CpuMpData->ApLoopMode == ApInHltLoop) {
777 //
778 // Place AP in HLT-loop
779 //
780 while (TRUE) {
781 DisableInterrupts ();
782 if (CpuMpData->UseSevEsAPMethod) {
783 SevEsPlaceApHlt (CpuMpData);
784 } else {
785 CpuSleep ();
786 }
787
788 CpuPause ();
789 }
790 }
791
792 while (TRUE) {
793 DisableInterrupts ();
794 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
795 //
796 // Place AP in MWAIT-loop
797 //
798 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);
799 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
800 //
801 // Check AP start-up signal again.
802 // If AP start-up signal is not set, place AP into
803 // the specified C-state
804 //
805 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
806 }
807 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
808 //
809 // Place AP in Run-loop
810 //
811 CpuPause ();
812 } else {
813 ASSERT (FALSE);
814 }
815
816 //
817 // If AP start-up signal is written, AP is waken up
818 // otherwise place AP in loop again
819 //
820 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
821 break;
822 }
823 }
824 }
825 }
826
827 /**
828 Wait for AP wakeup and write AP start-up signal till AP is waken up.
829
830 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
831 **/
832 VOID
833 WaitApWakeup (
834 IN volatile UINT32 *ApStartupSignalBuffer
835 )
836 {
837 //
838 // If AP is waken up, StartupApSignal should be cleared.
839 // Otherwise, write StartupApSignal again till AP waken up.
840 //
841 while (InterlockedCompareExchange32 (
842 (UINT32 *)ApStartupSignalBuffer,
843 WAKEUP_AP_SIGNAL,
844 WAKEUP_AP_SIGNAL
845 ) != 0)
846 {
847 CpuPause ();
848 }
849 }
850
851 /**
852 Calculate the size of the reset vector.
853
854 @param[in] AddressMap The pointer to Address Map structure.
855 @param[out] SizeBelow1Mb Return the size of below 1MB memory for AP reset area.
856 @param[out] SizeAbove1Mb Return the size of abvoe 1MB memory for AP reset area.
857 **/
858 STATIC
859 VOID
860 GetApResetVectorSize (
861 IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap,
862 OUT UINTN *SizeBelow1Mb OPTIONAL,
863 OUT UINTN *SizeAbove1Mb OPTIONAL
864 )
865 {
866 if (SizeBelow1Mb != NULL) {
867 *SizeBelow1Mb = AddressMap->ModeTransitionOffset + sizeof (MP_CPU_EXCHANGE_INFO);
868 }
869
870 if (SizeAbove1Mb != NULL) {
871 *SizeAbove1Mb = AddressMap->RendezvousFunnelSize - AddressMap->ModeTransitionOffset;
872 }
873 }
874
875 /**
876 This function will fill the exchange info structure.
877
878 @param[in] CpuMpData Pointer to CPU MP Data
879
880 **/
881 VOID
882 FillExchangeInfoData (
883 IN CPU_MP_DATA *CpuMpData
884 )
885 {
886 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
887 UINTN Size;
888 IA32_SEGMENT_DESCRIPTOR *Selector;
889 IA32_CR4 Cr4;
890
891 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
892 ExchangeInfo->StackStart = CpuMpData->Buffer;
893 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
894 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
895 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
896
897 ExchangeInfo->CodeSegment = AsmReadCs ();
898 ExchangeInfo->DataSegment = AsmReadDs ();
899
900 ExchangeInfo->Cr3 = AsmReadCr3 ();
901
902 ExchangeInfo->CFunction = (UINTN)ApWakeupFunction;
903 ExchangeInfo->ApIndex = 0;
904 ExchangeInfo->NumApsExecuting = 0;
905 ExchangeInfo->InitFlag = (UINTN)CpuMpData->InitFlag;
906 ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
907 ExchangeInfo->CpuMpData = CpuMpData;
908
909 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
910
911 ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;
912
913 //
914 // We can check either CPUID(7).ECX[bit16] or check CR4.LA57[bit12]
915 // to determin whether 5-Level Paging is enabled.
916 // CPUID(7).ECX[bit16] shows CPU's capability, CR4.LA57[bit12] shows
917 // current system setting.
918 // Using latter way is simpler because it also eliminates the needs to
919 // check whether platform wants to enable it.
920 //
921 Cr4.UintN = AsmReadCr4 ();
922 ExchangeInfo->Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);
923 DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
924
925 ExchangeInfo->SevEsIsEnabled = CpuMpData->SevEsIsEnabled;
926 ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
927 ExchangeInfo->GhcbBase = (UINTN)CpuMpData->GhcbBase;
928
929 //
930 // Populate SEV-ES specific exchange data.
931 //
932 if (ExchangeInfo->SevSnpIsEnabled) {
933 FillExchangeInfoDataSevEs (ExchangeInfo);
934 }
935
936 //
937 // Get the BSP's data of GDT and IDT
938 //
939 AsmReadGdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->GdtrProfile);
940 AsmReadIdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->IdtrProfile);
941
942 //
943 // Find a 32-bit code segment
944 //
945 Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;
946 Size = ExchangeInfo->GdtrProfile.Limit + 1;
947 while (Size > 0) {
948 if ((Selector->Bits.L == 0) && (Selector->Bits.Type >= 8)) {
949 ExchangeInfo->ModeTransitionSegment =
950 (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);
951 break;
952 }
953
954 Selector += 1;
955 Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);
956 }
957
958 //
959 // Copy all 32-bit code and 64-bit code into memory with type of
960 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
961 //
962 GetApResetVectorSize (&CpuMpData->AddressMap, NULL, &Size);
963 CopyMem (
964 (VOID *)CpuMpData->WakeupBufferHigh,
965 CpuMpData->AddressMap.RendezvousFunnelAddress +
966 CpuMpData->AddressMap.ModeTransitionOffset,
967 Size
968 );
969
970 ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;
971
972 ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +
973 (UINT32)ExchangeInfo->ModeOffset -
974 (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;
975 ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;
976 }
977
978 /**
979 Helper function that waits until the finished AP count reaches the specified
980 limit, or the specified timeout elapses (whichever comes first).
981
982 @param[in] CpuMpData Pointer to CPU MP Data.
983 @param[in] FinishedApLimit The number of finished APs to wait for.
984 @param[in] TimeLimit The number of microseconds to wait for.
985 **/
986 VOID
987 TimedWaitForApFinish (
988 IN CPU_MP_DATA *CpuMpData,
989 IN UINT32 FinishedApLimit,
990 IN UINT32 TimeLimit
991 );
992
993 /**
994 Get available system memory below 1MB by specified size.
995
996 @param[in] CpuMpData The pointer to CPU MP Data structure.
997 **/
998 VOID
999 BackupAndPrepareWakeupBuffer (
1000 IN CPU_MP_DATA *CpuMpData
1001 )
1002 {
1003 CopyMem (
1004 (VOID *)CpuMpData->BackupBuffer,
1005 (VOID *)CpuMpData->WakeupBuffer,
1006 CpuMpData->BackupBufferSize
1007 );
1008 CopyMem (
1009 (VOID *)CpuMpData->WakeupBuffer,
1010 (VOID *)CpuMpData->AddressMap.RendezvousFunnelAddress,
1011 CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO)
1012 );
1013 }
1014
1015 /**
1016 Restore wakeup buffer data.
1017
1018 @param[in] CpuMpData The pointer to CPU MP Data structure.
1019 **/
1020 VOID
1021 RestoreWakeupBuffer (
1022 IN CPU_MP_DATA *CpuMpData
1023 )
1024 {
1025 CopyMem (
1026 (VOID *)CpuMpData->WakeupBuffer,
1027 (VOID *)CpuMpData->BackupBuffer,
1028 CpuMpData->BackupBufferSize
1029 );
1030 }
1031
1032 /**
1033 Allocate reset vector buffer.
1034
1035 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1036 **/
1037 VOID
1038 AllocateResetVector (
1039 IN OUT CPU_MP_DATA *CpuMpData
1040 )
1041 {
1042 UINTN ApResetVectorSizeBelow1Mb;
1043 UINTN ApResetVectorSizeAbove1Mb;
1044 UINTN ApResetStackSize;
1045
1046 if (CpuMpData->WakeupBuffer == (UINTN)-1) {
1047 GetApResetVectorSize (&CpuMpData->AddressMap, &ApResetVectorSizeBelow1Mb, &ApResetVectorSizeAbove1Mb);
1048
1049 CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSizeBelow1Mb);
1050 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)
1051 (CpuMpData->WakeupBuffer + ApResetVectorSizeBelow1Mb - sizeof (MP_CPU_EXCHANGE_INFO));
1052 CpuMpData->WakeupBufferHigh = AllocateCodeBuffer (ApResetVectorSizeAbove1Mb);
1053 //
1054 // The AP reset stack is only used by SEV-ES guests. Do not allocate it
1055 // if SEV-ES is not enabled. An SEV-SNP guest is also considered
1056 // an SEV-ES guest, but uses a different method of AP startup, eliminating
1057 // the need for the allocation.
1058 //
1059 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
1060 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
1061 {
1062 //
1063 // Stack location is based on ProcessorNumber, so use the total number
1064 // of processors for calculating the total stack area.
1065 //
1066 ApResetStackSize = (AP_RESET_STACK_SIZE *
1067 PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
1068
1069 //
1070 // Invoke GetWakeupBuffer a second time to allocate the stack area
1071 // below 1MB. The returned buffer will be page aligned and sized and
1072 // below the previously allocated buffer.
1073 //
1074 CpuMpData->SevEsAPResetStackStart = GetWakeupBuffer (ApResetStackSize);
1075
1076 //
1077 // Check to be sure that the "allocate below" behavior hasn't changed.
1078 // This will also catch a failed allocation, as "-1" is returned on
1079 // failure.
1080 //
1081 if (CpuMpData->SevEsAPResetStackStart >= CpuMpData->WakeupBuffer) {
1082 DEBUG ((
1083 DEBUG_ERROR,
1084 "SEV-ES AP reset stack is not below wakeup buffer\n"
1085 ));
1086
1087 ASSERT (FALSE);
1088 CpuDeadLoop ();
1089 }
1090 }
1091 }
1092
1093 BackupAndPrepareWakeupBuffer (CpuMpData);
1094 }
1095
1096 /**
1097 Free AP reset vector buffer.
1098
1099 @param[in] CpuMpData The pointer to CPU MP Data structure.
1100 **/
1101 VOID
1102 FreeResetVector (
1103 IN CPU_MP_DATA *CpuMpData
1104 )
1105 {
1106 //
1107 // If SEV-ES is enabled, the reset area is needed for AP parking and
1108 // and AP startup in the OS, so the reset area is reserved. Do not
1109 // perform the restore as this will overwrite memory which has data
1110 // needed by SEV-ES.
1111 //
1112 if (!CpuMpData->UseSevEsAPMethod) {
1113 RestoreWakeupBuffer (CpuMpData);
1114 }
1115 }
1116
1117 /**
1118 This function will be called by BSP to wakeup AP.
1119
1120 @param[in] CpuMpData Pointer to CPU MP Data
1121 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
1122 FALSE: Send IPI to AP by ApicId
1123 @param[in] ProcessorNumber The handle number of specified processor
1124 @param[in] Procedure The function to be invoked by AP
1125 @param[in] ProcedureArgument The argument to be passed into AP function
1126 @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
1127 **/
1128 VOID
1129 WakeUpAP (
1130 IN CPU_MP_DATA *CpuMpData,
1131 IN BOOLEAN Broadcast,
1132 IN UINTN ProcessorNumber,
1133 IN EFI_AP_PROCEDURE Procedure OPTIONAL,
1134 IN VOID *ProcedureArgument OPTIONAL,
1135 IN BOOLEAN WakeUpDisabledAps
1136 )
1137 {
1138 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
1139 UINTN Index;
1140 CPU_AP_DATA *CpuData;
1141 BOOLEAN ResetVectorRequired;
1142 CPU_INFO_IN_HOB *CpuInfoInHob;
1143
1144 CpuMpData->FinishedCount = 0;
1145 ResetVectorRequired = FALSE;
1146
1147 if (CpuMpData->WakeUpByInitSipiSipi ||
1148 (CpuMpData->InitFlag != ApInitDone))
1149 {
1150 ResetVectorRequired = TRUE;
1151 AllocateResetVector (CpuMpData);
1152 AllocateSevEsAPMemory (CpuMpData);
1153 FillExchangeInfoData (CpuMpData);
1154 SaveLocalApicTimerSetting (CpuMpData);
1155 }
1156
1157 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
1158 //
1159 // Get AP target C-state each time when waking up AP,
1160 // for it maybe updated by platform again
1161 //
1162 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
1163 }
1164
1165 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
1166
1167 if (Broadcast) {
1168 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1169 if (Index != CpuMpData->BspNumber) {
1170 CpuData = &CpuMpData->CpuData[Index];
1171 //
1172 // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but
1173 // the AP procedure will be skipped for disabled AP because AP state
1174 // is not CpuStateReady.
1175 //
1176 if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) {
1177 continue;
1178 }
1179
1180 CpuData->ApFunction = (UINTN)Procedure;
1181 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
1182 SetApState (CpuData, CpuStateReady);
1183 if (CpuMpData->InitFlag != ApInitConfig) {
1184 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1185 }
1186 }
1187 }
1188
1189 if (ResetVectorRequired) {
1190 //
1191 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1192 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1193 // from the original INIT-SIPI-SIPI.
1194 //
1195 if (CpuMpData->SevEsIsEnabled) {
1196 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1197 }
1198
1199 //
1200 // Wakeup all APs
1201 // Must use the INIT-SIPI-SIPI method for initial configuration in
1202 // order to obtain the APIC ID.
1203 //
1204 if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {
1205 SevSnpCreateAP (CpuMpData, -1);
1206 } else {
1207 SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);
1208 }
1209 }
1210
1211 if (CpuMpData->InitFlag == ApInitConfig) {
1212 if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
1213 //
1214 // The AP enumeration algorithm below is suitable only when the
1215 // platform can tell us the *exact* boot CPU count in advance.
1216 //
1217 // The wait below finishes only when the detected AP count reaches
1218 // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
1219 // takes. If at least one AP fails to check in (meaning a platform
1220 // hardware bug), the detection hangs forever, by design. If the actual
1221 // boot CPU count in the system is higher than
1222 // PcdCpuBootLogicalProcessorNumber (meaning a platform
1223 // misconfiguration), then some APs may complete initialization after
1224 // the wait finishes, and cause undefined behavior.
1225 //
1226 TimedWaitForApFinish (
1227 CpuMpData,
1228 PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,
1229 MAX_UINT32 // approx. 71 minutes
1230 );
1231 } else {
1232 //
1233 // The AP enumeration algorithm below is suitable for two use cases.
1234 //
1235 // (1) The check-in time for an individual AP is bounded, and APs run
1236 // through their initialization routines strongly concurrently. In
1237 // particular, the number of concurrently running APs
1238 // ("NumApsExecuting") is never expected to fall to zero
1239 // *temporarily* -- it is expected to fall to zero only when all
1240 // APs have checked-in.
1241 //
1242 // In this case, the platform is supposed to set
1243 // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
1244 // enough for one AP to start initialization). The timeout will be
1245 // reached soon, and remaining APs are collected by watching
1246 // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
1247 // mid-process, while some APs have not completed initialization,
1248 // the behavior is undefined.
1249 //
1250 // (2) The check-in time for an individual AP is unbounded, and/or APs
1251 // may complete their initializations widely spread out. In
1252 // particular, some APs may finish initialization before some APs
1253 // even start.
1254 //
1255 // In this case, the platform is supposed to set
1256 // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
1257 // enumeration will always take that long (except when the boot CPU
1258 // count happens to be maximal, that is,
1259 // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
1260 // check-in before the timeout, and NumApsExecuting is assumed zero
1261 // at timeout. APs that miss the time-out may cause undefined
1262 // behavior.
1263 //
1264 TimedWaitForApFinish (
1265 CpuMpData,
1266 PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
1267 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
1268 );
1269
1270 while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
1271 CpuPause ();
1272 }
1273 }
1274 } else {
1275 //
1276 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1277 //
1278 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1279 CpuData = &CpuMpData->CpuData[Index];
1280 if (Index != CpuMpData->BspNumber) {
1281 WaitApWakeup (CpuData->StartupApSignal);
1282 }
1283 }
1284 }
1285 } else {
1286 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1287 CpuData->ApFunction = (UINTN)Procedure;
1288 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
1289 SetApState (CpuData, CpuStateReady);
1290 //
1291 // Wakeup specified AP
1292 //
1293 ASSERT (CpuMpData->InitFlag != ApInitConfig);
1294 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1295 if (ResetVectorRequired) {
1296 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
1297
1298 //
1299 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1300 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1301 // from the original INIT-SIPI-SIPI.
1302 //
1303 if (CpuMpData->SevEsIsEnabled) {
1304 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1305 }
1306
1307 if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {
1308 SevSnpCreateAP (CpuMpData, (INTN)ProcessorNumber);
1309 } else {
1310 SendInitSipiSipi (
1311 CpuInfoInHob[ProcessorNumber].ApicId,
1312 (UINT32)ExchangeInfo->BufferStart
1313 );
1314 }
1315 }
1316
1317 //
1318 // Wait specified AP waken up
1319 //
1320 WaitApWakeup (CpuData->StartupApSignal);
1321 }
1322
1323 if (ResetVectorRequired) {
1324 FreeResetVector (CpuMpData);
1325 }
1326
1327 //
1328 // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with
1329 // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by
1330 // S3SmmInitDone Ppi.
1331 //
1332 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
1333 }
1334
1335 /**
1336 Calculate timeout value and return the current performance counter value.
1337
1338 Calculate the number of performance counter ticks required for a timeout.
1339 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1340 as infinity.
1341
1342 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1343 @param[out] CurrentTime Returns the current value of the performance counter.
1344
1345 @return Expected time stamp counter for timeout.
1346 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1347 as infinity.
1348
1349 **/
1350 UINT64
1351 CalculateTimeout (
1352 IN UINTN TimeoutInMicroseconds,
1353 OUT UINT64 *CurrentTime
1354 )
1355 {
1356 UINT64 TimeoutInSeconds;
1357 UINT64 TimestampCounterFreq;
1358
1359 //
1360 // Read the current value of the performance counter
1361 //
1362 *CurrentTime = GetPerformanceCounter ();
1363
1364 //
1365 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1366 // as infinity.
1367 //
1368 if (TimeoutInMicroseconds == 0) {
1369 return 0;
1370 }
1371
1372 //
1373 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1374 // in Hz.
1375 //
1376 TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
1377
1378 //
1379 // Check the potential overflow before calculate the number of ticks for the timeout value.
1380 //
1381 if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
1382 //
1383 // Convert microseconds into seconds if direct multiplication overflows
1384 //
1385 TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
1386 //
1387 // Assertion if the final tick count exceeds MAX_UINT64
1388 //
1389 ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
1390 return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
1391 } else {
1392 //
1393 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1394 // it by 1,000,000, to get the number of ticks for the timeout value.
1395 //
1396 return DivU64x32 (
1397 MultU64x64 (
1398 TimestampCounterFreq,
1399 TimeoutInMicroseconds
1400 ),
1401 1000000
1402 );
1403 }
1404 }
1405
1406 /**
1407 Checks whether timeout expires.
1408
1409 Check whether the number of elapsed performance counter ticks required for
1410 a timeout condition has been reached.
1411 If Timeout is zero, which means infinity, return value is always FALSE.
1412
1413 @param[in, out] PreviousTime On input, the value of the performance counter
1414 when it was last read.
1415 On output, the current value of the performance
1416 counter
1417 @param[in] TotalTime The total amount of elapsed time in performance
1418 counter ticks.
1419 @param[in] Timeout The number of performance counter ticks required
1420 to reach a timeout condition.
1421
1422 @retval TRUE A timeout condition has been reached.
1423 @retval FALSE A timeout condition has not been reached.
1424
1425 **/
1426 BOOLEAN
1427 CheckTimeout (
1428 IN OUT UINT64 *PreviousTime,
1429 IN UINT64 *TotalTime,
1430 IN UINT64 Timeout
1431 )
1432 {
1433 UINT64 Start;
1434 UINT64 End;
1435 UINT64 CurrentTime;
1436 INT64 Delta;
1437 INT64 Cycle;
1438
1439 if (Timeout == 0) {
1440 return FALSE;
1441 }
1442
1443 GetPerformanceCounterProperties (&Start, &End);
1444 Cycle = End - Start;
1445 if (Cycle < 0) {
1446 Cycle = -Cycle;
1447 }
1448
1449 Cycle++;
1450 CurrentTime = GetPerformanceCounter ();
1451 Delta = (INT64)(CurrentTime - *PreviousTime);
1452 if (Start > End) {
1453 Delta = -Delta;
1454 }
1455
1456 if (Delta < 0) {
1457 Delta += Cycle;
1458 }
1459
1460 *TotalTime += Delta;
1461 *PreviousTime = CurrentTime;
1462 if (*TotalTime > Timeout) {
1463 return TRUE;
1464 }
1465
1466 return FALSE;
1467 }
1468
1469 /**
1470 Helper function that waits until the finished AP count reaches the specified
1471 limit, or the specified timeout elapses (whichever comes first).
1472
1473 @param[in] CpuMpData Pointer to CPU MP Data.
1474 @param[in] FinishedApLimit The number of finished APs to wait for.
1475 @param[in] TimeLimit The number of microseconds to wait for.
1476 **/
1477 VOID
1478 TimedWaitForApFinish (
1479 IN CPU_MP_DATA *CpuMpData,
1480 IN UINT32 FinishedApLimit,
1481 IN UINT32 TimeLimit
1482 )
1483 {
1484 //
1485 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1486 // "infinity", so check for (TimeLimit == 0) explicitly.
1487 //
1488 if (TimeLimit == 0) {
1489 return;
1490 }
1491
1492 CpuMpData->TotalTime = 0;
1493 CpuMpData->ExpectedTime = CalculateTimeout (
1494 TimeLimit,
1495 &CpuMpData->CurrentTime
1496 );
1497 while (CpuMpData->FinishedCount < FinishedApLimit &&
1498 !CheckTimeout (
1499 &CpuMpData->CurrentTime,
1500 &CpuMpData->TotalTime,
1501 CpuMpData->ExpectedTime
1502 ))
1503 {
1504 CpuPause ();
1505 }
1506
1507 if (CpuMpData->FinishedCount >= FinishedApLimit) {
1508 DEBUG ((
1509 DEBUG_VERBOSE,
1510 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1511 __FUNCTION__,
1512 FinishedApLimit,
1513 DivU64x64Remainder (
1514 MultU64x32 (CpuMpData->TotalTime, 1000000),
1515 GetPerformanceCounterProperties (NULL, NULL),
1516 NULL
1517 )
1518 ));
1519 }
1520 }
1521
1522 /**
1523 Reset an AP to Idle state.
1524
1525 Any task being executed by the AP will be aborted and the AP
1526 will be waiting for a new task in Wait-For-SIPI state.
1527
1528 @param[in] ProcessorNumber The handle number of processor.
1529 **/
1530 VOID
1531 ResetProcessorToIdleState (
1532 IN UINTN ProcessorNumber
1533 )
1534 {
1535 CPU_MP_DATA *CpuMpData;
1536
1537 CpuMpData = GetCpuMpData ();
1538
1539 CpuMpData->InitFlag = ApInitReconfig;
1540 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);
1541 while (CpuMpData->FinishedCount < 1) {
1542 CpuPause ();
1543 }
1544
1545 CpuMpData->InitFlag = ApInitDone;
1546
1547 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1548 }
1549
1550 /**
1551 Searches for the next waiting AP.
1552
1553 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1554
1555 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1556
1557 @retval EFI_SUCCESS The next waiting AP has been found.
1558 @retval EFI_NOT_FOUND No waiting AP exists.
1559
1560 **/
1561 EFI_STATUS
1562 GetNextWaitingProcessorNumber (
1563 OUT UINTN *NextProcessorNumber
1564 )
1565 {
1566 UINTN ProcessorNumber;
1567 CPU_MP_DATA *CpuMpData;
1568
1569 CpuMpData = GetCpuMpData ();
1570
1571 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1572 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1573 *NextProcessorNumber = ProcessorNumber;
1574 return EFI_SUCCESS;
1575 }
1576 }
1577
1578 return EFI_NOT_FOUND;
1579 }
1580
1581 /** Checks status of specified AP.
1582
1583 This function checks whether the specified AP has finished the task assigned
1584 by StartupThisAP(), and whether timeout expires.
1585
1586 @param[in] ProcessorNumber The handle number of processor.
1587
1588 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1589 @retval EFI_TIMEOUT The timeout expires.
1590 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1591 **/
1592 EFI_STATUS
1593 CheckThisAP (
1594 IN UINTN ProcessorNumber
1595 )
1596 {
1597 CPU_MP_DATA *CpuMpData;
1598 CPU_AP_DATA *CpuData;
1599
1600 CpuMpData = GetCpuMpData ();
1601 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1602
1603 //
1604 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1605 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1606 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1607 //
1608 //
1609 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1610 //
1611 if (GetApState (CpuData) == CpuStateFinished) {
1612 if (CpuData->Finished != NULL) {
1613 *(CpuData->Finished) = TRUE;
1614 }
1615
1616 SetApState (CpuData, CpuStateIdle);
1617 return EFI_SUCCESS;
1618 } else {
1619 //
1620 // If timeout expires for StartupThisAP(), report timeout.
1621 //
1622 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
1623 if (CpuData->Finished != NULL) {
1624 *(CpuData->Finished) = FALSE;
1625 }
1626
1627 //
1628 // Reset failed AP to idle state
1629 //
1630 ResetProcessorToIdleState (ProcessorNumber);
1631
1632 return EFI_TIMEOUT;
1633 }
1634 }
1635
1636 return EFI_NOT_READY;
1637 }
1638
1639 /**
1640 Checks status of all APs.
1641
1642 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1643 and whether timeout expires.
1644
1645 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1646 @retval EFI_TIMEOUT The timeout expires.
1647 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1648 **/
1649 EFI_STATUS
1650 CheckAllAPs (
1651 VOID
1652 )
1653 {
1654 UINTN ProcessorNumber;
1655 UINTN NextProcessorNumber;
1656 UINTN ListIndex;
1657 EFI_STATUS Status;
1658 CPU_MP_DATA *CpuMpData;
1659 CPU_AP_DATA *CpuData;
1660
1661 CpuMpData = GetCpuMpData ();
1662
1663 NextProcessorNumber = 0;
1664
1665 //
1666 // Go through all APs that are responsible for the StartupAllAPs().
1667 //
1668 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1669 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
1670 continue;
1671 }
1672
1673 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1674 //
1675 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1676 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1677 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1678 //
1679 if (GetApState (CpuData) == CpuStateFinished) {
1680 CpuMpData->RunningCount--;
1681 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1682 SetApState (CpuData, CpuStateIdle);
1683
1684 //
1685 // If in Single Thread mode, then search for the next waiting AP for execution.
1686 //
1687 if (CpuMpData->SingleThread) {
1688 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
1689
1690 if (!EFI_ERROR (Status)) {
1691 WakeUpAP (
1692 CpuMpData,
1693 FALSE,
1694 (UINT32)NextProcessorNumber,
1695 CpuMpData->Procedure,
1696 CpuMpData->ProcArguments,
1697 TRUE
1698 );
1699 }
1700 }
1701 }
1702 }
1703
1704 //
1705 // If all APs finish, return EFI_SUCCESS.
1706 //
1707 if (CpuMpData->RunningCount == 0) {
1708 return EFI_SUCCESS;
1709 }
1710
1711 //
1712 // If timeout expires, report timeout.
1713 //
1714 if (CheckTimeout (
1715 &CpuMpData->CurrentTime,
1716 &CpuMpData->TotalTime,
1717 CpuMpData->ExpectedTime
1718 )
1719 )
1720 {
1721 //
1722 // If FailedCpuList is not NULL, record all failed APs in it.
1723 //
1724 if (CpuMpData->FailedCpuList != NULL) {
1725 *CpuMpData->FailedCpuList =
1726 AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));
1727 ASSERT (*CpuMpData->FailedCpuList != NULL);
1728 }
1729
1730 ListIndex = 0;
1731
1732 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1733 //
1734 // Check whether this processor is responsible for StartupAllAPs().
1735 //
1736 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1737 //
1738 // Reset failed APs to idle state
1739 //
1740 ResetProcessorToIdleState (ProcessorNumber);
1741 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1742 if (CpuMpData->FailedCpuList != NULL) {
1743 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
1744 }
1745 }
1746 }
1747
1748 if (CpuMpData->FailedCpuList != NULL) {
1749 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
1750 }
1751
1752 return EFI_TIMEOUT;
1753 }
1754
1755 return EFI_NOT_READY;
1756 }
1757
1758 /**
1759 MP Initialize Library initialization.
1760
1761 This service will allocate AP reset vector and wakeup all APs to do APs
1762 initialization.
1763
1764 This service must be invoked before all other MP Initialize Library
1765 service are invoked.
1766
1767 @retval EFI_SUCCESS MP initialization succeeds.
1768 @retval Others MP initialization fails.
1769
1770 **/
1771 EFI_STATUS
1772 EFIAPI
1773 MpInitLibInitialize (
1774 VOID
1775 )
1776 {
1777 CPU_MP_DATA *OldCpuMpData;
1778 CPU_INFO_IN_HOB *CpuInfoInHob;
1779 UINT32 MaxLogicalProcessorNumber;
1780 UINT32 ApStackSize;
1781 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
1782 CPU_VOLATILE_REGISTERS VolatileRegisters;
1783 UINTN BufferSize;
1784 UINT32 MonitorFilterSize;
1785 VOID *MpBuffer;
1786 UINTN Buffer;
1787 CPU_MP_DATA *CpuMpData;
1788 UINT8 ApLoopMode;
1789 UINT8 *MonitorBuffer;
1790 UINTN Index;
1791 UINTN ApResetVectorSizeBelow1Mb;
1792 UINTN BackupBufferAddr;
1793 UINTN ApIdtBase;
1794
1795 OldCpuMpData = GetCpuMpDataFromGuidedHob ();
1796 if (OldCpuMpData == NULL) {
1797 MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1798 } else {
1799 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
1800 }
1801
1802 ASSERT (MaxLogicalProcessorNumber != 0);
1803
1804 AsmGetAddressMap (&AddressMap);
1805 GetApResetVectorSize (&AddressMap, &ApResetVectorSizeBelow1Mb, NULL);
1806 ApStackSize = PcdGet32 (PcdCpuApStackSize);
1807 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
1808
1809 //
1810 // Save BSP's Control registers for APs.
1811 //
1812 SaveVolatileRegisters (&VolatileRegisters);
1813
1814 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
1815 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
1816 BufferSize += ApResetVectorSizeBelow1Mb;
1817 BufferSize = ALIGN_VALUE (BufferSize, 8);
1818 BufferSize += VolatileRegisters.Idtr.Limit + 1;
1819 BufferSize += sizeof (CPU_MP_DATA);
1820 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
1821 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
1822 ASSERT (MpBuffer != NULL);
1823 ZeroMem (MpBuffer, BufferSize);
1824 Buffer = (UINTN)MpBuffer;
1825
1826 //
1827 // The layout of the Buffer is as below:
1828 //
1829 // +--------------------+ <-- Buffer
1830 // AP Stacks (N)
1831 // +--------------------+ <-- MonitorBuffer
1832 // AP Monitor Filters (N)
1833 // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
1834 // Backup Buffer
1835 // +--------------------+
1836 // Padding
1837 // +--------------------+ <-- ApIdtBase (8-byte boundary)
1838 // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
1839 // +--------------------+ <-- CpuMpData
1840 // CPU_MP_DATA
1841 // +--------------------+ <-- CpuMpData->CpuData
1842 // CPU_AP_DATA (N)
1843 // +--------------------+ <-- CpuMpData->CpuInfoInHob
1844 // CPU_INFO_IN_HOB (N)
1845 // +--------------------+
1846 //
1847 MonitorBuffer = (UINT8 *)(Buffer + ApStackSize * MaxLogicalProcessorNumber);
1848 BackupBufferAddr = (UINTN)MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
1849 ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSizeBelow1Mb, 8);
1850 CpuMpData = (CPU_MP_DATA *)(ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
1851 CpuMpData->Buffer = Buffer;
1852 CpuMpData->CpuApStackSize = ApStackSize;
1853 CpuMpData->BackupBuffer = BackupBufferAddr;
1854 CpuMpData->BackupBufferSize = ApResetVectorSizeBelow1Mb;
1855 CpuMpData->WakeupBuffer = (UINTN)-1;
1856 CpuMpData->CpuCount = 1;
1857 CpuMpData->BspNumber = 0;
1858 CpuMpData->WaitEvent = NULL;
1859 CpuMpData->SwitchBspFlag = FALSE;
1860 CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1);
1861 CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);
1862 InitializeSpinLock (&CpuMpData->MpLock);
1863 CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
1864 CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
1865 CpuMpData->SevEsAPBuffer = (UINTN)-1;
1866 CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
1867 CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;
1868
1869 if (CpuMpData->SevSnpIsEnabled) {
1870 ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);
1871 }
1872
1873 //
1874 // Make sure no memory usage outside of the allocated buffer.
1875 //
1876 ASSERT (
1877 (CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
1878 Buffer + BufferSize
1879 );
1880
1881 //
1882 // Duplicate BSP's IDT to APs.
1883 // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
1884 //
1885 CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);
1886 VolatileRegisters.Idtr.Base = ApIdtBase;
1887 //
1888 // Don't pass BSP's TR to APs to avoid AP init failure.
1889 //
1890 VolatileRegisters.Tr = 0;
1891 CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));
1892 //
1893 // Set BSP basic information
1894 //
1895 InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);
1896 //
1897 // Save assembly code information
1898 //
1899 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
1900 //
1901 // Finally set AP loop mode
1902 //
1903 CpuMpData->ApLoopMode = ApLoopMode;
1904 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
1905
1906 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
1907
1908 //
1909 // Set up APs wakeup signal buffer
1910 //
1911 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
1912 CpuMpData->CpuData[Index].StartupApSignal =
1913 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
1914 }
1915
1916 //
1917 // Enable the local APIC for Virtual Wire Mode.
1918 //
1919 ProgramVirtualWireMode ();
1920
1921 if (OldCpuMpData == NULL) {
1922 if (MaxLogicalProcessorNumber > 1) {
1923 //
1924 // Wakeup all APs and calculate the processor count in system
1925 //
1926 CollectProcessorCount (CpuMpData);
1927 }
1928 } else {
1929 //
1930 // APs have been wakeup before, just get the CPU Information
1931 // from HOB
1932 //
1933 OldCpuMpData->NewCpuMpData = CpuMpData;
1934 CpuMpData->CpuCount = OldCpuMpData->CpuCount;
1935 CpuMpData->BspNumber = OldCpuMpData->BspNumber;
1936 CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;
1937 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
1938 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1939 InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
1940 CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE;
1941 CpuMpData->CpuData[Index].ApFunction = 0;
1942 }
1943 }
1944
1945 if (!GetMicrocodePatchInfoFromHob (
1946 &CpuMpData->MicrocodePatchAddress,
1947 &CpuMpData->MicrocodePatchRegionSize
1948 ))
1949 {
1950 //
1951 // The microcode patch information cache HOB does not exist, which means
1952 // the microcode patches data has not been loaded into memory yet
1953 //
1954 ShadowMicrocodeUpdatePatch (CpuMpData);
1955 }
1956
1957 //
1958 // Detect and apply Microcode on BSP
1959 //
1960 MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);
1961 //
1962 // Store BSP's MTRR setting
1963 //
1964 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
1965
1966 //
1967 // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
1968 //
1969 if (CpuMpData->CpuCount > 1) {
1970 if (OldCpuMpData != NULL) {
1971 //
1972 // Only needs to use this flag for DXE phase to update the wake up
1973 // buffer. Wakeup buffer allocated in PEI phase is no longer valid
1974 // in DXE.
1975 //
1976 CpuMpData->InitFlag = ApInitReconfig;
1977 }
1978
1979 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);
1980 //
1981 // Wait for all APs finished initialization
1982 //
1983 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
1984 CpuPause ();
1985 }
1986
1987 if (OldCpuMpData != NULL) {
1988 CpuMpData->InitFlag = ApInitDone;
1989 }
1990
1991 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1992 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
1993 }
1994 }
1995
1996 //
1997 // Dump the microcode revision for each core.
1998 //
1999 DEBUG_CODE_BEGIN ();
2000 UINT32 ThreadId;
2001 UINT32 ExpectedMicrocodeRevision;
2002
2003 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
2004 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2005 GetProcessorLocationByApicId (CpuInfoInHob[Index].InitialApicId, NULL, NULL, &ThreadId);
2006 if (ThreadId == 0) {
2007 //
2008 // MicrocodeDetect() loads microcode in first thread of each core, so,
2009 // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.
2010 //
2011 ExpectedMicrocodeRevision = 0;
2012 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
2013 ExpectedMicrocodeRevision = ((CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->CpuData[Index].MicrocodeEntryAddr)->UpdateRevision;
2014 }
2015
2016 DEBUG ((
2017 DEBUG_INFO,
2018 "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",
2019 Index,
2020 CpuMpData->CpuData[Index].MicrocodeRevision,
2021 ExpectedMicrocodeRevision
2022 ));
2023 }
2024 }
2025
2026 DEBUG_CODE_END ();
2027 //
2028 // Initialize global data for MP support
2029 //
2030 InitMpGlobalData (CpuMpData);
2031
2032 return EFI_SUCCESS;
2033 }
2034
2035 /**
2036 Gets detailed MP-related information on the requested processor at the
2037 instant this call is made. This service may only be called from the BSP.
2038
2039 @param[in] ProcessorNumber The handle number of processor.
2040 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
2041 the requested processor is deposited.
2042 @param[out] HealthData Return processor health data.
2043
2044 @retval EFI_SUCCESS Processor information was returned.
2045 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2046 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
2047 @retval EFI_NOT_FOUND The processor with the handle specified by
2048 ProcessorNumber does not exist in the platform.
2049 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2050
2051 **/
2052 EFI_STATUS
2053 EFIAPI
2054 MpInitLibGetProcessorInfo (
2055 IN UINTN ProcessorNumber,
2056 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
2057 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
2058 )
2059 {
2060 CPU_MP_DATA *CpuMpData;
2061 UINTN CallerNumber;
2062 CPU_INFO_IN_HOB *CpuInfoInHob;
2063 UINTN OriginalProcessorNumber;
2064
2065 CpuMpData = GetCpuMpData ();
2066 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
2067
2068 //
2069 // Lower 24 bits contains the actual processor number.
2070 //
2071 OriginalProcessorNumber = ProcessorNumber;
2072 ProcessorNumber &= BIT24 - 1;
2073
2074 //
2075 // Check whether caller processor is BSP
2076 //
2077 MpInitLibWhoAmI (&CallerNumber);
2078 if (CallerNumber != CpuMpData->BspNumber) {
2079 return EFI_DEVICE_ERROR;
2080 }
2081
2082 if (ProcessorInfoBuffer == NULL) {
2083 return EFI_INVALID_PARAMETER;
2084 }
2085
2086 if (ProcessorNumber >= CpuMpData->CpuCount) {
2087 return EFI_NOT_FOUND;
2088 }
2089
2090 ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId;
2091 ProcessorInfoBuffer->StatusFlag = 0;
2092 if (ProcessorNumber == CpuMpData->BspNumber) {
2093 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
2094 }
2095
2096 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
2097 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
2098 }
2099
2100 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
2101 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
2102 } else {
2103 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
2104 }
2105
2106 //
2107 // Get processor location information
2108 //
2109 GetProcessorLocationByApicId (
2110 CpuInfoInHob[ProcessorNumber].ApicId,
2111 &ProcessorInfoBuffer->Location.Package,
2112 &ProcessorInfoBuffer->Location.Core,
2113 &ProcessorInfoBuffer->Location.Thread
2114 );
2115
2116 if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {
2117 GetProcessorLocation2ByApicId (
2118 CpuInfoInHob[ProcessorNumber].ApicId,
2119 &ProcessorInfoBuffer->ExtendedInformation.Location2.Package,
2120 &ProcessorInfoBuffer->ExtendedInformation.Location2.Die,
2121 &ProcessorInfoBuffer->ExtendedInformation.Location2.Tile,
2122 &ProcessorInfoBuffer->ExtendedInformation.Location2.Module,
2123 &ProcessorInfoBuffer->ExtendedInformation.Location2.Core,
2124 &ProcessorInfoBuffer->ExtendedInformation.Location2.Thread
2125 );
2126 }
2127
2128 if (HealthData != NULL) {
2129 HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
2130 }
2131
2132 return EFI_SUCCESS;
2133 }
2134
2135 /**
2136 Worker function to switch the requested AP to be the BSP from that point onward.
2137
2138 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
2139 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
2140 enabled AP. Otherwise, it will be disabled.
2141
2142 @retval EFI_SUCCESS BSP successfully switched.
2143 @retval others Failed to switch BSP.
2144
2145 **/
2146 EFI_STATUS
2147 SwitchBSPWorker (
2148 IN UINTN ProcessorNumber,
2149 IN BOOLEAN EnableOldBSP
2150 )
2151 {
2152 CPU_MP_DATA *CpuMpData;
2153 UINTN CallerNumber;
2154 CPU_STATE State;
2155 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
2156 BOOLEAN OldInterruptState;
2157 BOOLEAN OldTimerInterruptState;
2158
2159 //
2160 // Save and Disable Local APIC timer interrupt
2161 //
2162 OldTimerInterruptState = GetApicTimerInterruptState ();
2163 DisableApicTimerInterrupt ();
2164 //
2165 // Before send both BSP and AP to a procedure to exchange their roles,
2166 // interrupt must be disabled. This is because during the exchange role
2167 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
2168 // be corrupted, since interrupt return address will be pushed to stack
2169 // by hardware.
2170 //
2171 OldInterruptState = SaveAndDisableInterrupts ();
2172
2173 //
2174 // Mask LINT0 & LINT1 for the old BSP
2175 //
2176 DisableLvtInterrupts ();
2177
2178 CpuMpData = GetCpuMpData ();
2179
2180 //
2181 // Check whether caller processor is BSP
2182 //
2183 MpInitLibWhoAmI (&CallerNumber);
2184 if (CallerNumber != CpuMpData->BspNumber) {
2185 return EFI_DEVICE_ERROR;
2186 }
2187
2188 if (ProcessorNumber >= CpuMpData->CpuCount) {
2189 return EFI_NOT_FOUND;
2190 }
2191
2192 //
2193 // Check whether specified AP is disabled
2194 //
2195 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
2196 if (State == CpuStateDisabled) {
2197 return EFI_INVALID_PARAMETER;
2198 }
2199
2200 //
2201 // Check whether ProcessorNumber specifies the current BSP
2202 //
2203 if (ProcessorNumber == CpuMpData->BspNumber) {
2204 return EFI_INVALID_PARAMETER;
2205 }
2206
2207 //
2208 // Check whether specified AP is busy
2209 //
2210 if (State == CpuStateBusy) {
2211 return EFI_NOT_READY;
2212 }
2213
2214 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
2215 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
2216 CpuMpData->SwitchBspFlag = TRUE;
2217 CpuMpData->NewBspNumber = ProcessorNumber;
2218
2219 //
2220 // Clear the BSP bit of MSR_IA32_APIC_BASE
2221 //
2222 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2223 ApicBaseMsr.Bits.BSP = 0;
2224 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2225
2226 //
2227 // Need to wakeUp AP (future BSP).
2228 //
2229 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);
2230
2231 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
2232
2233 //
2234 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
2235 //
2236 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2237 ApicBaseMsr.Bits.BSP = 1;
2238 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2239 ProgramVirtualWireMode ();
2240
2241 //
2242 // Wait for old BSP finished AP task
2243 //
2244 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
2245 CpuPause ();
2246 }
2247
2248 CpuMpData->SwitchBspFlag = FALSE;
2249 //
2250 // Set old BSP enable state
2251 //
2252 if (!EnableOldBSP) {
2253 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
2254 } else {
2255 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);
2256 }
2257
2258 //
2259 // Save new BSP number
2260 //
2261 CpuMpData->BspNumber = (UINT32)ProcessorNumber;
2262
2263 //
2264 // Restore interrupt state.
2265 //
2266 SetInterruptState (OldInterruptState);
2267
2268 if (OldTimerInterruptState) {
2269 EnableApicTimerInterrupt ();
2270 }
2271
2272 return EFI_SUCCESS;
2273 }
2274
2275 /**
2276 Worker function to let the caller enable or disable an AP from this point onward.
2277 This service may only be called from the BSP.
2278
2279 @param[in] ProcessorNumber The handle number of AP.
2280 @param[in] EnableAP Specifies the new state for the processor for
2281 enabled, FALSE for disabled.
2282 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
2283 the new health status of the AP.
2284
2285 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
2286 @retval others Failed to Enable/Disable AP.
2287
2288 **/
2289 EFI_STATUS
2290 EnableDisableApWorker (
2291 IN UINTN ProcessorNumber,
2292 IN BOOLEAN EnableAP,
2293 IN UINT32 *HealthFlag OPTIONAL
2294 )
2295 {
2296 CPU_MP_DATA *CpuMpData;
2297 UINTN CallerNumber;
2298
2299 CpuMpData = GetCpuMpData ();
2300
2301 //
2302 // Check whether caller processor is BSP
2303 //
2304 MpInitLibWhoAmI (&CallerNumber);
2305 if (CallerNumber != CpuMpData->BspNumber) {
2306 return EFI_DEVICE_ERROR;
2307 }
2308
2309 if (ProcessorNumber == CpuMpData->BspNumber) {
2310 return EFI_INVALID_PARAMETER;
2311 }
2312
2313 if (ProcessorNumber >= CpuMpData->CpuCount) {
2314 return EFI_NOT_FOUND;
2315 }
2316
2317 if (!EnableAP) {
2318 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
2319 } else {
2320 ResetProcessorToIdleState (ProcessorNumber);
2321 }
2322
2323 if (HealthFlag != NULL) {
2324 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
2325 (BOOLEAN)((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
2326 }
2327
2328 return EFI_SUCCESS;
2329 }
2330
2331 /**
2332 This return the handle number for the calling processor. This service may be
2333 called from the BSP and APs.
2334
2335 @param[out] ProcessorNumber Pointer to the handle number of AP.
2336 The range is from 0 to the total number of
2337 logical processors minus 1. The total number of
2338 logical processors can be retrieved by
2339 MpInitLibGetNumberOfProcessors().
2340
2341 @retval EFI_SUCCESS The current processor handle number was returned
2342 in ProcessorNumber.
2343 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
2344 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2345
2346 **/
2347 EFI_STATUS
2348 EFIAPI
2349 MpInitLibWhoAmI (
2350 OUT UINTN *ProcessorNumber
2351 )
2352 {
2353 CPU_MP_DATA *CpuMpData;
2354
2355 if (ProcessorNumber == NULL) {
2356 return EFI_INVALID_PARAMETER;
2357 }
2358
2359 CpuMpData = GetCpuMpData ();
2360
2361 return GetProcessorNumber (CpuMpData, ProcessorNumber);
2362 }
2363
2364 /**
2365 Retrieves the number of logical processor in the platform and the number of
2366 those logical processors that are enabled on this boot. This service may only
2367 be called from the BSP.
2368
2369 @param[out] NumberOfProcessors Pointer to the total number of logical
2370 processors in the system, including the BSP
2371 and disabled APs.
2372 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
2373 processors that exist in system, including
2374 the BSP.
2375
2376 @retval EFI_SUCCESS The number of logical processors and enabled
2377 logical processors was retrieved.
2378 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2379 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
2380 is NULL.
2381 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2382
2383 **/
2384 EFI_STATUS
2385 EFIAPI
2386 MpInitLibGetNumberOfProcessors (
2387 OUT UINTN *NumberOfProcessors OPTIONAL,
2388 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
2389 )
2390 {
2391 CPU_MP_DATA *CpuMpData;
2392 UINTN CallerNumber;
2393 UINTN ProcessorNumber;
2394 UINTN EnabledProcessorNumber;
2395 UINTN Index;
2396
2397 CpuMpData = GetCpuMpData ();
2398
2399 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
2400 return EFI_INVALID_PARAMETER;
2401 }
2402
2403 //
2404 // Check whether caller processor is BSP
2405 //
2406 MpInitLibWhoAmI (&CallerNumber);
2407 if (CallerNumber != CpuMpData->BspNumber) {
2408 return EFI_DEVICE_ERROR;
2409 }
2410
2411 ProcessorNumber = CpuMpData->CpuCount;
2412 EnabledProcessorNumber = 0;
2413 for (Index = 0; Index < ProcessorNumber; Index++) {
2414 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
2415 EnabledProcessorNumber++;
2416 }
2417 }
2418
2419 if (NumberOfProcessors != NULL) {
2420 *NumberOfProcessors = ProcessorNumber;
2421 }
2422
2423 if (NumberOfEnabledProcessors != NULL) {
2424 *NumberOfEnabledProcessors = EnabledProcessorNumber;
2425 }
2426
2427 return EFI_SUCCESS;
2428 }
2429
2430 /**
2431 Worker function to execute a caller provided function on all enabled APs.
2432
2433 @param[in] Procedure A pointer to the function to be run on
2434 enabled APs of the system.
2435 @param[in] SingleThread If TRUE, then all the enabled APs execute
2436 the function specified by Procedure one by
2437 one, in ascending order of processor handle
2438 number. If FALSE, then all the enabled APs
2439 execute the function specified by Procedure
2440 simultaneously.
2441 @param[in] ExcludeBsp Whether let BSP also trig this task.
2442 @param[in] WaitEvent The event created by the caller with CreateEvent()
2443 service.
2444 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2445 APs to return from Procedure, either for
2446 blocking or non-blocking mode.
2447 @param[in] ProcedureArgument The parameter passed into Procedure for
2448 all APs.
2449 @param[out] FailedCpuList If all APs finish successfully, then its
2450 content is set to NULL. If not all APs
2451 finish before timeout expires, then its
2452 content is set to address of the buffer
2453 holding handle numbers of the failed APs.
2454
2455 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2456 the timeout expired.
2457 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2458 to all enabled APs.
2459 @retval others Failed to Startup all APs.
2460
2461 **/
2462 EFI_STATUS
2463 StartupAllCPUsWorker (
2464 IN EFI_AP_PROCEDURE Procedure,
2465 IN BOOLEAN SingleThread,
2466 IN BOOLEAN ExcludeBsp,
2467 IN EFI_EVENT WaitEvent OPTIONAL,
2468 IN UINTN TimeoutInMicroseconds,
2469 IN VOID *ProcedureArgument OPTIONAL,
2470 OUT UINTN **FailedCpuList OPTIONAL
2471 )
2472 {
2473 EFI_STATUS Status;
2474 CPU_MP_DATA *CpuMpData;
2475 UINTN ProcessorCount;
2476 UINTN ProcessorNumber;
2477 UINTN CallerNumber;
2478 CPU_AP_DATA *CpuData;
2479 BOOLEAN HasEnabledAp;
2480 CPU_STATE ApState;
2481
2482 CpuMpData = GetCpuMpData ();
2483
2484 if (FailedCpuList != NULL) {
2485 *FailedCpuList = NULL;
2486 }
2487
2488 if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {
2489 return EFI_NOT_STARTED;
2490 }
2491
2492 if (Procedure == NULL) {
2493 return EFI_INVALID_PARAMETER;
2494 }
2495
2496 //
2497 // Check whether caller processor is BSP
2498 //
2499 MpInitLibWhoAmI (&CallerNumber);
2500 if (CallerNumber != CpuMpData->BspNumber) {
2501 return EFI_DEVICE_ERROR;
2502 }
2503
2504 //
2505 // Update AP state
2506 //
2507 CheckAndUpdateApsStatus ();
2508
2509 ProcessorCount = CpuMpData->CpuCount;
2510 HasEnabledAp = FALSE;
2511 //
2512 // Check whether all enabled APs are idle.
2513 // If any enabled AP is not idle, return EFI_NOT_READY.
2514 //
2515 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2516 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2517 if (ProcessorNumber != CpuMpData->BspNumber) {
2518 ApState = GetApState (CpuData);
2519 if (ApState != CpuStateDisabled) {
2520 HasEnabledAp = TRUE;
2521 if (ApState != CpuStateIdle) {
2522 //
2523 // If any enabled APs are busy, return EFI_NOT_READY.
2524 //
2525 return EFI_NOT_READY;
2526 }
2527 }
2528 }
2529 }
2530
2531 if (!HasEnabledAp && ExcludeBsp) {
2532 //
2533 // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
2534 //
2535 return EFI_NOT_STARTED;
2536 }
2537
2538 CpuMpData->RunningCount = 0;
2539 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2540 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2541 CpuData->Waiting = FALSE;
2542 if (ProcessorNumber != CpuMpData->BspNumber) {
2543 if (CpuData->State == CpuStateIdle) {
2544 //
2545 // Mark this processor as responsible for current calling.
2546 //
2547 CpuData->Waiting = TRUE;
2548 CpuMpData->RunningCount++;
2549 }
2550 }
2551 }
2552
2553 CpuMpData->Procedure = Procedure;
2554 CpuMpData->ProcArguments = ProcedureArgument;
2555 CpuMpData->SingleThread = SingleThread;
2556 CpuMpData->FinishedCount = 0;
2557 CpuMpData->FailedCpuList = FailedCpuList;
2558 CpuMpData->ExpectedTime = CalculateTimeout (
2559 TimeoutInMicroseconds,
2560 &CpuMpData->CurrentTime
2561 );
2562 CpuMpData->TotalTime = 0;
2563 CpuMpData->WaitEvent = WaitEvent;
2564
2565 if (!SingleThread) {
2566 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
2567 } else {
2568 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2569 if (ProcessorNumber == CallerNumber) {
2570 continue;
2571 }
2572
2573 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
2574 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
2575 break;
2576 }
2577 }
2578 }
2579
2580 if (!ExcludeBsp) {
2581 //
2582 // Start BSP.
2583 //
2584 Procedure (ProcedureArgument);
2585 }
2586
2587 Status = EFI_SUCCESS;
2588 if (WaitEvent == NULL) {
2589 do {
2590 Status = CheckAllAPs ();
2591 } while (Status == EFI_NOT_READY);
2592 }
2593
2594 return Status;
2595 }
2596
2597 /**
2598 Worker function to let the caller get one enabled AP to execute a caller-provided
2599 function.
2600
2601 @param[in] Procedure A pointer to the function to be run on
2602 enabled APs of the system.
2603 @param[in] ProcessorNumber The handle number of the AP.
2604 @param[in] WaitEvent The event created by the caller with CreateEvent()
2605 service.
2606 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2607 APs to return from Procedure, either for
2608 blocking or non-blocking mode.
2609 @param[in] ProcedureArgument The parameter passed into Procedure for
2610 all APs.
2611 @param[out] Finished If AP returns from Procedure before the
2612 timeout expires, its content is set to TRUE.
2613 Otherwise, the value is set to FALSE.
2614
2615 @retval EFI_SUCCESS In blocking mode, specified AP finished before
2616 the timeout expires.
2617 @retval others Failed to Startup AP.
2618
2619 **/
2620 EFI_STATUS
2621 StartupThisAPWorker (
2622 IN EFI_AP_PROCEDURE Procedure,
2623 IN UINTN ProcessorNumber,
2624 IN EFI_EVENT WaitEvent OPTIONAL,
2625 IN UINTN TimeoutInMicroseconds,
2626 IN VOID *ProcedureArgument OPTIONAL,
2627 OUT BOOLEAN *Finished OPTIONAL
2628 )
2629 {
2630 EFI_STATUS Status;
2631 CPU_MP_DATA *CpuMpData;
2632 CPU_AP_DATA *CpuData;
2633 UINTN CallerNumber;
2634
2635 CpuMpData = GetCpuMpData ();
2636
2637 if (Finished != NULL) {
2638 *Finished = FALSE;
2639 }
2640
2641 //
2642 // Check whether caller processor is BSP
2643 //
2644 MpInitLibWhoAmI (&CallerNumber);
2645 if (CallerNumber != CpuMpData->BspNumber) {
2646 return EFI_DEVICE_ERROR;
2647 }
2648
2649 //
2650 // Check whether processor with the handle specified by ProcessorNumber exists
2651 //
2652 if (ProcessorNumber >= CpuMpData->CpuCount) {
2653 return EFI_NOT_FOUND;
2654 }
2655
2656 //
2657 // Check whether specified processor is BSP
2658 //
2659 if (ProcessorNumber == CpuMpData->BspNumber) {
2660 return EFI_INVALID_PARAMETER;
2661 }
2662
2663 //
2664 // Check parameter Procedure
2665 //
2666 if (Procedure == NULL) {
2667 return EFI_INVALID_PARAMETER;
2668 }
2669
2670 //
2671 // Update AP state
2672 //
2673 CheckAndUpdateApsStatus ();
2674
2675 //
2676 // Check whether specified AP is disabled
2677 //
2678 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
2679 return EFI_INVALID_PARAMETER;
2680 }
2681
2682 //
2683 // If WaitEvent is not NULL, execute in non-blocking mode.
2684 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
2685 // CheckAPsStatus() will check completion and timeout periodically.
2686 //
2687 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2688 CpuData->WaitEvent = WaitEvent;
2689 CpuData->Finished = Finished;
2690 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
2691 CpuData->TotalTime = 0;
2692
2693 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
2694
2695 //
2696 // If WaitEvent is NULL, execute in blocking mode.
2697 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
2698 //
2699 Status = EFI_SUCCESS;
2700 if (WaitEvent == NULL) {
2701 do {
2702 Status = CheckThisAP (ProcessorNumber);
2703 } while (Status == EFI_NOT_READY);
2704 }
2705
2706 return Status;
2707 }
2708
2709 /**
2710 Get pointer to CPU MP Data structure from GUIDed HOB.
2711
2712 @return The pointer to CPU MP Data structure.
2713 **/
2714 CPU_MP_DATA *
2715 GetCpuMpDataFromGuidedHob (
2716 VOID
2717 )
2718 {
2719 EFI_HOB_GUID_TYPE *GuidHob;
2720 VOID *DataInHob;
2721 CPU_MP_DATA *CpuMpData;
2722
2723 CpuMpData = NULL;
2724 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
2725 if (GuidHob != NULL) {
2726 DataInHob = GET_GUID_HOB_DATA (GuidHob);
2727 CpuMpData = (CPU_MP_DATA *)(*(UINTN *)DataInHob);
2728 }
2729
2730 return CpuMpData;
2731 }
2732
2733 /**
2734 This service executes a caller provided function on all enabled CPUs.
2735
2736 @param[in] Procedure A pointer to the function to be run on
2737 enabled APs of the system. See type
2738 EFI_AP_PROCEDURE.
2739 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2740 APs to return from Procedure, either for
2741 blocking or non-blocking mode. Zero means
2742 infinity. TimeoutInMicroseconds is ignored
2743 for BSP.
2744 @param[in] ProcedureArgument The parameter passed into Procedure for
2745 all APs.
2746
2747 @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
2748 the timeout expired.
2749 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2750 to all enabled CPUs.
2751 @retval EFI_DEVICE_ERROR Caller processor is AP.
2752 @retval EFI_NOT_READY Any enabled APs are busy.
2753 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2754 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
2755 all enabled APs have finished.
2756 @retval EFI_INVALID_PARAMETER Procedure is NULL.
2757
2758 **/
2759 EFI_STATUS
2760 EFIAPI
2761 MpInitLibStartupAllCPUs (
2762 IN EFI_AP_PROCEDURE Procedure,
2763 IN UINTN TimeoutInMicroseconds,
2764 IN VOID *ProcedureArgument OPTIONAL
2765 )
2766 {
2767 return StartupAllCPUsWorker (
2768 Procedure,
2769 FALSE,
2770 FALSE,
2771 NULL,
2772 TimeoutInMicroseconds,
2773 ProcedureArgument,
2774 NULL
2775 );
2776 }
2777
2778 /**
2779 The function check if the specified Attr is set.
2780
2781 @param[in] CurrentAttr The current attribute.
2782 @param[in] Attr The attribute to check.
2783
2784 @retval TRUE The specified Attr is set.
2785 @retval FALSE The specified Attr is not set.
2786
2787 **/
2788 STATIC
2789 BOOLEAN
2790 AmdMemEncryptionAttrCheck (
2791 IN UINT64 CurrentAttr,
2792 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
2793 )
2794 {
2795 switch (Attr) {
2796 case CCAttrAmdSev:
2797 //
2798 // SEV is automatically enabled if SEV-ES or SEV-SNP is active.
2799 //
2800 return CurrentAttr >= CCAttrAmdSev;
2801 case CCAttrAmdSevEs:
2802 //
2803 // SEV-ES is automatically enabled if SEV-SNP is active.
2804 //
2805 return CurrentAttr >= CCAttrAmdSevEs;
2806 case CCAttrAmdSevSnp:
2807 return CurrentAttr == CCAttrAmdSevSnp;
2808 default:
2809 return FALSE;
2810 }
2811 }
2812
2813 /**
2814 Check if the specified confidential computing attribute is active.
2815
2816 @param[in] Attr The attribute to check.
2817
2818 @retval TRUE The specified Attr is active.
2819 @retval FALSE The specified Attr is not active.
2820
2821 **/
2822 BOOLEAN
2823 EFIAPI
2824 ConfidentialComputingGuestHas (
2825 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
2826 )
2827 {
2828 UINT64 CurrentAttr;
2829
2830 //
2831 // Get the current CC attribute.
2832 //
2833 CurrentAttr = PcdGet64 (PcdConfidentialComputingGuestAttr);
2834
2835 //
2836 // If attr is for the AMD group then call AMD specific checks.
2837 //
2838 if (((RShiftU64 (CurrentAttr, 8)) & 0xff) == 1) {
2839 return AmdMemEncryptionAttrCheck (CurrentAttr, Attr);
2840 }
2841
2842 return (CurrentAttr == Attr);
2843 }