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