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