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