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