VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/MpInitLib/MpLib.c@ 105670

Last change on this file since 105670 was 105670, checked in by vboxsync, 6 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette