]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg: Change OPTIONAL keyword usage style
[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 return Size;
1168 }
1169
1170 /**
1171 Allocate reset vector buffer.
1172
1173 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1174 **/
1175 VOID
1176 AllocateResetVector (
1177 IN OUT CPU_MP_DATA *CpuMpData
1178 )
1179 {
1180 UINTN ApResetVectorSize;
1181 UINTN ApResetStackSize;
1182
1183 if (CpuMpData->WakeupBuffer == (UINTN) -1) {
1184 ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);
1185
1186 CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
1187 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
1188 (CpuMpData->WakeupBuffer +
1189 CpuMpData->AddressMap.RendezvousFunnelSize +
1190 CpuMpData->AddressMap.SwitchToRealSize);
1191 CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (
1192 CpuMpData->AddressMap.RendezvousFunnelSize +
1193 CpuMpData->AddressMap.SwitchToRealSize -
1194 CpuMpData->AddressMap.ModeTransitionOffset
1195 );
1196 //
1197 // The AP reset stack is only used by SEV-ES guests. Do not allocate it
1198 // if SEV-ES is not enabled.
1199 //
1200 if (PcdGetBool (PcdSevEsIsEnabled)) {
1201 //
1202 // Stack location is based on ProcessorNumber, so use the total number
1203 // of processors for calculating the total stack area.
1204 //
1205 ApResetStackSize = (AP_RESET_STACK_SIZE *
1206 PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
1207
1208 //
1209 // Invoke GetWakeupBuffer a second time to allocate the stack area
1210 // below 1MB. The returned buffer will be page aligned and sized and
1211 // below the previously allocated buffer.
1212 //
1213 CpuMpData->SevEsAPResetStackStart = GetWakeupBuffer (ApResetStackSize);
1214
1215 //
1216 // Check to be sure that the "allocate below" behavior hasn't changed.
1217 // This will also catch a failed allocation, as "-1" is returned on
1218 // failure.
1219 //
1220 if (CpuMpData->SevEsAPResetStackStart >= CpuMpData->WakeupBuffer) {
1221 DEBUG ((
1222 DEBUG_ERROR,
1223 "SEV-ES AP reset stack is not below wakeup buffer\n"
1224 ));
1225
1226 ASSERT (FALSE);
1227 CpuDeadLoop ();
1228 }
1229 }
1230 }
1231 BackupAndPrepareWakeupBuffer (CpuMpData);
1232 }
1233
1234 /**
1235 Free AP reset vector buffer.
1236
1237 @param[in] CpuMpData The pointer to CPU MP Data structure.
1238 **/
1239 VOID
1240 FreeResetVector (
1241 IN CPU_MP_DATA *CpuMpData
1242 )
1243 {
1244 //
1245 // If SEV-ES is enabled, the reset area is needed for AP parking and
1246 // and AP startup in the OS, so the reset area is reserved. Do not
1247 // perform the restore as this will overwrite memory which has data
1248 // needed by SEV-ES.
1249 //
1250 if (!CpuMpData->SevEsIsEnabled) {
1251 RestoreWakeupBuffer (CpuMpData);
1252 }
1253 }
1254
1255 /**
1256 Allocate the SEV-ES AP jump table buffer.
1257
1258 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1259 **/
1260 VOID
1261 AllocateSevEsAPMemory (
1262 IN OUT CPU_MP_DATA *CpuMpData
1263 )
1264 {
1265 if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
1266 CpuMpData->SevEsAPBuffer =
1267 CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
1268 }
1269 }
1270
1271 /**
1272 Program the SEV-ES AP jump table buffer.
1273
1274 @param[in] SipiVector The SIPI vector used for the AP Reset
1275 **/
1276 VOID
1277 SetSevEsJumpTable (
1278 IN UINTN SipiVector
1279 )
1280 {
1281 SEV_ES_AP_JMP_FAR *JmpFar;
1282 UINT32 Offset, InsnByte;
1283 UINT8 LoNib, HiNib;
1284
1285 JmpFar = (SEV_ES_AP_JMP_FAR *) (UINTN) FixedPcdGet32 (PcdSevEsWorkAreaBase);
1286 ASSERT (JmpFar != NULL);
1287
1288 //
1289 // Obtain the address of the Segment/Rip location in the workarea.
1290 // This will be set to a value derived from the SIPI vector and will
1291 // be the memory address used for the far jump below.
1292 //
1293 Offset = FixedPcdGet32 (PcdSevEsWorkAreaBase);
1294 Offset += sizeof (JmpFar->InsnBuffer);
1295 LoNib = (UINT8) Offset;
1296 HiNib = (UINT8) (Offset >> 8);
1297
1298 //
1299 // Program the workarea (which is the initial AP boot address) with
1300 // far jump to the SIPI vector (where XX and YY represent the
1301 // address of where the SIPI vector is stored.
1302 //
1303 // JMP FAR [CS:XXYY] => 2E FF 2E YY XX
1304 //
1305 InsnByte = 0;
1306 JmpFar->InsnBuffer[InsnByte++] = 0x2E; // CS override prefix
1307 JmpFar->InsnBuffer[InsnByte++] = 0xFF; // JMP (FAR)
1308 JmpFar->InsnBuffer[InsnByte++] = 0x2E; // ModRM (JMP memory location)
1309 JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...
1310 JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...
1311
1312 //
1313 // Program the Segment/Rip based on the SIPI vector (always at least
1314 // 16-byte aligned, so Rip is set to 0).
1315 //
1316 JmpFar->Rip = 0;
1317 JmpFar->Segment = (UINT16) (SipiVector >> 4);
1318 }
1319
1320 /**
1321 This function will be called by BSP to wakeup AP.
1322
1323 @param[in] CpuMpData Pointer to CPU MP Data
1324 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
1325 FALSE: Send IPI to AP by ApicId
1326 @param[in] ProcessorNumber The handle number of specified processor
1327 @param[in] Procedure The function to be invoked by AP
1328 @param[in] ProcedureArgument The argument to be passed into AP function
1329 @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
1330 **/
1331 VOID
1332 WakeUpAP (
1333 IN CPU_MP_DATA *CpuMpData,
1334 IN BOOLEAN Broadcast,
1335 IN UINTN ProcessorNumber,
1336 IN EFI_AP_PROCEDURE Procedure OPTIONAL,
1337 IN VOID *ProcedureArgument OPTIONAL,
1338 IN BOOLEAN WakeUpDisabledAps
1339 )
1340 {
1341 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
1342 UINTN Index;
1343 CPU_AP_DATA *CpuData;
1344 BOOLEAN ResetVectorRequired;
1345 CPU_INFO_IN_HOB *CpuInfoInHob;
1346
1347 CpuMpData->FinishedCount = 0;
1348 ResetVectorRequired = FALSE;
1349
1350 if (CpuMpData->WakeUpByInitSipiSipi ||
1351 CpuMpData->InitFlag != ApInitDone) {
1352 ResetVectorRequired = TRUE;
1353 AllocateResetVector (CpuMpData);
1354 AllocateSevEsAPMemory (CpuMpData);
1355 FillExchangeInfoData (CpuMpData);
1356 SaveLocalApicTimerSetting (CpuMpData);
1357 }
1358
1359 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
1360 //
1361 // Get AP target C-state each time when waking up AP,
1362 // for it maybe updated by platform again
1363 //
1364 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
1365 }
1366
1367 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
1368
1369 if (Broadcast) {
1370 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1371 if (Index != CpuMpData->BspNumber) {
1372 CpuData = &CpuMpData->CpuData[Index];
1373 //
1374 // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but
1375 // the AP procedure will be skipped for disabled AP because AP state
1376 // is not CpuStateReady.
1377 //
1378 if (GetApState (CpuData) == CpuStateDisabled && !WakeUpDisabledAps) {
1379 continue;
1380 }
1381
1382 CpuData->ApFunction = (UINTN) Procedure;
1383 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
1384 SetApState (CpuData, CpuStateReady);
1385 if (CpuMpData->InitFlag != ApInitConfig) {
1386 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1387 }
1388 }
1389 }
1390 if (ResetVectorRequired) {
1391 //
1392 // For SEV-ES, the initial AP boot address will be defined by
1393 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1394 // from the original INIT-SIPI-SIPI.
1395 //
1396 if (CpuMpData->SevEsIsEnabled) {
1397 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1398 }
1399
1400 //
1401 // Wakeup all APs
1402 //
1403 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
1404 }
1405 if (CpuMpData->InitFlag == ApInitConfig) {
1406 if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
1407 //
1408 // The AP enumeration algorithm below is suitable only when the
1409 // platform can tell us the *exact* boot CPU count in advance.
1410 //
1411 // The wait below finishes only when the detected AP count reaches
1412 // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
1413 // takes. If at least one AP fails to check in (meaning a platform
1414 // hardware bug), the detection hangs forever, by design. If the actual
1415 // boot CPU count in the system is higher than
1416 // PcdCpuBootLogicalProcessorNumber (meaning a platform
1417 // misconfiguration), then some APs may complete initialization after
1418 // the wait finishes, and cause undefined behavior.
1419 //
1420 TimedWaitForApFinish (
1421 CpuMpData,
1422 PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,
1423 MAX_UINT32 // approx. 71 minutes
1424 );
1425 } else {
1426 //
1427 // The AP enumeration algorithm below is suitable for two use cases.
1428 //
1429 // (1) The check-in time for an individual AP is bounded, and APs run
1430 // through their initialization routines strongly concurrently. In
1431 // particular, the number of concurrently running APs
1432 // ("NumApsExecuting") is never expected to fall to zero
1433 // *temporarily* -- it is expected to fall to zero only when all
1434 // APs have checked-in.
1435 //
1436 // In this case, the platform is supposed to set
1437 // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
1438 // enough for one AP to start initialization). The timeout will be
1439 // reached soon, and remaining APs are collected by watching
1440 // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
1441 // mid-process, while some APs have not completed initialization,
1442 // the behavior is undefined.
1443 //
1444 // (2) The check-in time for an individual AP is unbounded, and/or APs
1445 // may complete their initializations widely spread out. In
1446 // particular, some APs may finish initialization before some APs
1447 // even start.
1448 //
1449 // In this case, the platform is supposed to set
1450 // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
1451 // enumeration will always take that long (except when the boot CPU
1452 // count happens to be maximal, that is,
1453 // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
1454 // check-in before the timeout, and NumApsExecuting is assumed zero
1455 // at timeout. APs that miss the time-out may cause undefined
1456 // behavior.
1457 //
1458 TimedWaitForApFinish (
1459 CpuMpData,
1460 PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
1461 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
1462 );
1463
1464 while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
1465 CpuPause();
1466 }
1467 }
1468 } else {
1469 //
1470 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1471 //
1472 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1473 CpuData = &CpuMpData->CpuData[Index];
1474 if (Index != CpuMpData->BspNumber) {
1475 WaitApWakeup (CpuData->StartupApSignal);
1476 }
1477 }
1478 }
1479 } else {
1480 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1481 CpuData->ApFunction = (UINTN) Procedure;
1482 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
1483 SetApState (CpuData, CpuStateReady);
1484 //
1485 // Wakeup specified AP
1486 //
1487 ASSERT (CpuMpData->InitFlag != ApInitConfig);
1488 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1489 if (ResetVectorRequired) {
1490 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
1491
1492 //
1493 // For SEV-ES, the initial AP boot address will be defined by
1494 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1495 // from the original INIT-SIPI-SIPI.
1496 //
1497 if (CpuMpData->SevEsIsEnabled) {
1498 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1499 }
1500
1501 SendInitSipiSipi (
1502 CpuInfoInHob[ProcessorNumber].ApicId,
1503 (UINT32) ExchangeInfo->BufferStart
1504 );
1505 }
1506 //
1507 // Wait specified AP waken up
1508 //
1509 WaitApWakeup (CpuData->StartupApSignal);
1510 }
1511
1512 if (ResetVectorRequired) {
1513 FreeResetVector (CpuMpData);
1514 }
1515
1516 //
1517 // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with
1518 // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by
1519 // S3SmmInitDone Ppi.
1520 //
1521 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
1522 }
1523
1524 /**
1525 Calculate timeout value and return the current performance counter value.
1526
1527 Calculate the number of performance counter ticks required for a timeout.
1528 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1529 as infinity.
1530
1531 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1532 @param[out] CurrentTime Returns the current value of the performance counter.
1533
1534 @return Expected time stamp counter for timeout.
1535 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1536 as infinity.
1537
1538 **/
1539 UINT64
1540 CalculateTimeout (
1541 IN UINTN TimeoutInMicroseconds,
1542 OUT UINT64 *CurrentTime
1543 )
1544 {
1545 UINT64 TimeoutInSeconds;
1546 UINT64 TimestampCounterFreq;
1547
1548 //
1549 // Read the current value of the performance counter
1550 //
1551 *CurrentTime = GetPerformanceCounter ();
1552
1553 //
1554 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1555 // as infinity.
1556 //
1557 if (TimeoutInMicroseconds == 0) {
1558 return 0;
1559 }
1560
1561 //
1562 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1563 // in Hz.
1564 //
1565 TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
1566
1567 //
1568 // Check the potential overflow before calculate the number of ticks for the timeout value.
1569 //
1570 if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
1571 //
1572 // Convert microseconds into seconds if direct multiplication overflows
1573 //
1574 TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
1575 //
1576 // Assertion if the final tick count exceeds MAX_UINT64
1577 //
1578 ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
1579 return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
1580 } else {
1581 //
1582 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1583 // it by 1,000,000, to get the number of ticks for the timeout value.
1584 //
1585 return DivU64x32 (
1586 MultU64x64 (
1587 TimestampCounterFreq,
1588 TimeoutInMicroseconds
1589 ),
1590 1000000
1591 );
1592 }
1593 }
1594
1595 /**
1596 Checks whether timeout expires.
1597
1598 Check whether the number of elapsed performance counter ticks required for
1599 a timeout condition has been reached.
1600 If Timeout is zero, which means infinity, return value is always FALSE.
1601
1602 @param[in, out] PreviousTime On input, the value of the performance counter
1603 when it was last read.
1604 On output, the current value of the performance
1605 counter
1606 @param[in] TotalTime The total amount of elapsed time in performance
1607 counter ticks.
1608 @param[in] Timeout The number of performance counter ticks required
1609 to reach a timeout condition.
1610
1611 @retval TRUE A timeout condition has been reached.
1612 @retval FALSE A timeout condition has not been reached.
1613
1614 **/
1615 BOOLEAN
1616 CheckTimeout (
1617 IN OUT UINT64 *PreviousTime,
1618 IN UINT64 *TotalTime,
1619 IN UINT64 Timeout
1620 )
1621 {
1622 UINT64 Start;
1623 UINT64 End;
1624 UINT64 CurrentTime;
1625 INT64 Delta;
1626 INT64 Cycle;
1627
1628 if (Timeout == 0) {
1629 return FALSE;
1630 }
1631 GetPerformanceCounterProperties (&Start, &End);
1632 Cycle = End - Start;
1633 if (Cycle < 0) {
1634 Cycle = -Cycle;
1635 }
1636 Cycle++;
1637 CurrentTime = GetPerformanceCounter();
1638 Delta = (INT64) (CurrentTime - *PreviousTime);
1639 if (Start > End) {
1640 Delta = -Delta;
1641 }
1642 if (Delta < 0) {
1643 Delta += Cycle;
1644 }
1645 *TotalTime += Delta;
1646 *PreviousTime = CurrentTime;
1647 if (*TotalTime > Timeout) {
1648 return TRUE;
1649 }
1650 return FALSE;
1651 }
1652
1653 /**
1654 Helper function that waits until the finished AP count reaches the specified
1655 limit, or the specified timeout elapses (whichever comes first).
1656
1657 @param[in] CpuMpData Pointer to CPU MP Data.
1658 @param[in] FinishedApLimit The number of finished APs to wait for.
1659 @param[in] TimeLimit The number of microseconds to wait for.
1660 **/
1661 VOID
1662 TimedWaitForApFinish (
1663 IN CPU_MP_DATA *CpuMpData,
1664 IN UINT32 FinishedApLimit,
1665 IN UINT32 TimeLimit
1666 )
1667 {
1668 //
1669 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1670 // "infinity", so check for (TimeLimit == 0) explicitly.
1671 //
1672 if (TimeLimit == 0) {
1673 return;
1674 }
1675
1676 CpuMpData->TotalTime = 0;
1677 CpuMpData->ExpectedTime = CalculateTimeout (
1678 TimeLimit,
1679 &CpuMpData->CurrentTime
1680 );
1681 while (CpuMpData->FinishedCount < FinishedApLimit &&
1682 !CheckTimeout (
1683 &CpuMpData->CurrentTime,
1684 &CpuMpData->TotalTime,
1685 CpuMpData->ExpectedTime
1686 )) {
1687 CpuPause ();
1688 }
1689
1690 if (CpuMpData->FinishedCount >= FinishedApLimit) {
1691 DEBUG ((
1692 DEBUG_VERBOSE,
1693 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1694 __FUNCTION__,
1695 FinishedApLimit,
1696 DivU64x64Remainder (
1697 MultU64x32 (CpuMpData->TotalTime, 1000000),
1698 GetPerformanceCounterProperties (NULL, NULL),
1699 NULL
1700 )
1701 ));
1702 }
1703 }
1704
1705 /**
1706 Reset an AP to Idle state.
1707
1708 Any task being executed by the AP will be aborted and the AP
1709 will be waiting for a new task in Wait-For-SIPI state.
1710
1711 @param[in] ProcessorNumber The handle number of processor.
1712 **/
1713 VOID
1714 ResetProcessorToIdleState (
1715 IN UINTN ProcessorNumber
1716 )
1717 {
1718 CPU_MP_DATA *CpuMpData;
1719
1720 CpuMpData = GetCpuMpData ();
1721
1722 CpuMpData->InitFlag = ApInitReconfig;
1723 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);
1724 while (CpuMpData->FinishedCount < 1) {
1725 CpuPause ();
1726 }
1727 CpuMpData->InitFlag = ApInitDone;
1728
1729 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1730 }
1731
1732 /**
1733 Searches for the next waiting AP.
1734
1735 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1736
1737 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1738
1739 @retval EFI_SUCCESS The next waiting AP has been found.
1740 @retval EFI_NOT_FOUND No waiting AP exists.
1741
1742 **/
1743 EFI_STATUS
1744 GetNextWaitingProcessorNumber (
1745 OUT UINTN *NextProcessorNumber
1746 )
1747 {
1748 UINTN ProcessorNumber;
1749 CPU_MP_DATA *CpuMpData;
1750
1751 CpuMpData = GetCpuMpData ();
1752
1753 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1754 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1755 *NextProcessorNumber = ProcessorNumber;
1756 return EFI_SUCCESS;
1757 }
1758 }
1759
1760 return EFI_NOT_FOUND;
1761 }
1762
1763 /** Checks status of specified AP.
1764
1765 This function checks whether the specified AP has finished the task assigned
1766 by StartupThisAP(), and whether timeout expires.
1767
1768 @param[in] ProcessorNumber The handle number of processor.
1769
1770 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1771 @retval EFI_TIMEOUT The timeout expires.
1772 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1773 **/
1774 EFI_STATUS
1775 CheckThisAP (
1776 IN UINTN ProcessorNumber
1777 )
1778 {
1779 CPU_MP_DATA *CpuMpData;
1780 CPU_AP_DATA *CpuData;
1781
1782 CpuMpData = GetCpuMpData ();
1783 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1784
1785 //
1786 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1787 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1788 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1789 //
1790 //
1791 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1792 //
1793 if (GetApState(CpuData) == CpuStateFinished) {
1794 if (CpuData->Finished != NULL) {
1795 *(CpuData->Finished) = TRUE;
1796 }
1797 SetApState (CpuData, CpuStateIdle);
1798 return EFI_SUCCESS;
1799 } else {
1800 //
1801 // If timeout expires for StartupThisAP(), report timeout.
1802 //
1803 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
1804 if (CpuData->Finished != NULL) {
1805 *(CpuData->Finished) = FALSE;
1806 }
1807 //
1808 // Reset failed AP to idle state
1809 //
1810 ResetProcessorToIdleState (ProcessorNumber);
1811
1812 return EFI_TIMEOUT;
1813 }
1814 }
1815 return EFI_NOT_READY;
1816 }
1817
1818 /**
1819 Checks status of all APs.
1820
1821 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1822 and whether timeout expires.
1823
1824 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1825 @retval EFI_TIMEOUT The timeout expires.
1826 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1827 **/
1828 EFI_STATUS
1829 CheckAllAPs (
1830 VOID
1831 )
1832 {
1833 UINTN ProcessorNumber;
1834 UINTN NextProcessorNumber;
1835 UINTN ListIndex;
1836 EFI_STATUS Status;
1837 CPU_MP_DATA *CpuMpData;
1838 CPU_AP_DATA *CpuData;
1839
1840 CpuMpData = GetCpuMpData ();
1841
1842 NextProcessorNumber = 0;
1843
1844 //
1845 // Go through all APs that are responsible for the StartupAllAPs().
1846 //
1847 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1848 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
1849 continue;
1850 }
1851
1852 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1853 //
1854 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1855 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1856 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1857 //
1858 if (GetApState(CpuData) == CpuStateFinished) {
1859 CpuMpData->RunningCount --;
1860 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1861 SetApState(CpuData, CpuStateIdle);
1862
1863 //
1864 // If in Single Thread mode, then search for the next waiting AP for execution.
1865 //
1866 if (CpuMpData->SingleThread) {
1867 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
1868
1869 if (!EFI_ERROR (Status)) {
1870 WakeUpAP (
1871 CpuMpData,
1872 FALSE,
1873 (UINT32) NextProcessorNumber,
1874 CpuMpData->Procedure,
1875 CpuMpData->ProcArguments,
1876 TRUE
1877 );
1878 }
1879 }
1880 }
1881 }
1882
1883 //
1884 // If all APs finish, return EFI_SUCCESS.
1885 //
1886 if (CpuMpData->RunningCount == 0) {
1887 return EFI_SUCCESS;
1888 }
1889
1890 //
1891 // If timeout expires, report timeout.
1892 //
1893 if (CheckTimeout (
1894 &CpuMpData->CurrentTime,
1895 &CpuMpData->TotalTime,
1896 CpuMpData->ExpectedTime)
1897 ) {
1898 //
1899 // If FailedCpuList is not NULL, record all failed APs in it.
1900 //
1901 if (CpuMpData->FailedCpuList != NULL) {
1902 *CpuMpData->FailedCpuList =
1903 AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));
1904 ASSERT (*CpuMpData->FailedCpuList != NULL);
1905 }
1906 ListIndex = 0;
1907
1908 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1909 //
1910 // Check whether this processor is responsible for StartupAllAPs().
1911 //
1912 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1913 //
1914 // Reset failed APs to idle state
1915 //
1916 ResetProcessorToIdleState (ProcessorNumber);
1917 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1918 if (CpuMpData->FailedCpuList != NULL) {
1919 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
1920 }
1921 }
1922 }
1923 if (CpuMpData->FailedCpuList != NULL) {
1924 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
1925 }
1926 return EFI_TIMEOUT;
1927 }
1928 return EFI_NOT_READY;
1929 }
1930
1931 /**
1932 MP Initialize Library initialization.
1933
1934 This service will allocate AP reset vector and wakeup all APs to do APs
1935 initialization.
1936
1937 This service must be invoked before all other MP Initialize Library
1938 service are invoked.
1939
1940 @retval EFI_SUCCESS MP initialization succeeds.
1941 @retval Others MP initialization fails.
1942
1943 **/
1944 EFI_STATUS
1945 EFIAPI
1946 MpInitLibInitialize (
1947 VOID
1948 )
1949 {
1950 CPU_MP_DATA *OldCpuMpData;
1951 CPU_INFO_IN_HOB *CpuInfoInHob;
1952 UINT32 MaxLogicalProcessorNumber;
1953 UINT32 ApStackSize;
1954 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
1955 CPU_VOLATILE_REGISTERS VolatileRegisters;
1956 UINTN BufferSize;
1957 UINT32 MonitorFilterSize;
1958 VOID *MpBuffer;
1959 UINTN Buffer;
1960 CPU_MP_DATA *CpuMpData;
1961 UINT8 ApLoopMode;
1962 UINT8 *MonitorBuffer;
1963 UINTN Index;
1964 UINTN ApResetVectorSize;
1965 UINTN BackupBufferAddr;
1966 UINTN ApIdtBase;
1967
1968 OldCpuMpData = GetCpuMpDataFromGuidedHob ();
1969 if (OldCpuMpData == NULL) {
1970 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
1971 } else {
1972 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
1973 }
1974 ASSERT (MaxLogicalProcessorNumber != 0);
1975
1976 AsmGetAddressMap (&AddressMap);
1977 ApResetVectorSize = GetApResetVectorSize (&AddressMap);
1978 ApStackSize = PcdGet32(PcdCpuApStackSize);
1979 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
1980
1981 //
1982 // Save BSP's Control registers for APs.
1983 //
1984 SaveVolatileRegisters (&VolatileRegisters);
1985
1986 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
1987 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
1988 BufferSize += ApResetVectorSize;
1989 BufferSize = ALIGN_VALUE (BufferSize, 8);
1990 BufferSize += VolatileRegisters.Idtr.Limit + 1;
1991 BufferSize += sizeof (CPU_MP_DATA);
1992 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
1993 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
1994 ASSERT (MpBuffer != NULL);
1995 ZeroMem (MpBuffer, BufferSize);
1996 Buffer = (UINTN) MpBuffer;
1997
1998 //
1999 // The layout of the Buffer is as below:
2000 //
2001 // +--------------------+ <-- Buffer
2002 // AP Stacks (N)
2003 // +--------------------+ <-- MonitorBuffer
2004 // AP Monitor Filters (N)
2005 // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
2006 // Backup Buffer
2007 // +--------------------+
2008 // Padding
2009 // +--------------------+ <-- ApIdtBase (8-byte boundary)
2010 // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
2011 // +--------------------+ <-- CpuMpData
2012 // CPU_MP_DATA
2013 // +--------------------+ <-- CpuMpData->CpuData
2014 // CPU_AP_DATA (N)
2015 // +--------------------+ <-- CpuMpData->CpuInfoInHob
2016 // CPU_INFO_IN_HOB (N)
2017 // +--------------------+
2018 //
2019 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
2020 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
2021 ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);
2022 CpuMpData = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
2023 CpuMpData->Buffer = Buffer;
2024 CpuMpData->CpuApStackSize = ApStackSize;
2025 CpuMpData->BackupBuffer = BackupBufferAddr;
2026 CpuMpData->BackupBufferSize = ApResetVectorSize;
2027 CpuMpData->WakeupBuffer = (UINTN) -1;
2028 CpuMpData->CpuCount = 1;
2029 CpuMpData->BspNumber = 0;
2030 CpuMpData->WaitEvent = NULL;
2031 CpuMpData->SwitchBspFlag = FALSE;
2032 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
2033 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
2034 InitializeSpinLock(&CpuMpData->MpLock);
2035 CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
2036 CpuMpData->SevEsAPBuffer = (UINTN) -1;
2037 CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
2038
2039 //
2040 // Make sure no memory usage outside of the allocated buffer.
2041 //
2042 ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
2043 Buffer + BufferSize);
2044
2045 //
2046 // Duplicate BSP's IDT to APs.
2047 // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
2048 //
2049 CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);
2050 VolatileRegisters.Idtr.Base = ApIdtBase;
2051 //
2052 // Don't pass BSP's TR to APs to avoid AP init failure.
2053 //
2054 VolatileRegisters.Tr = 0;
2055 CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));
2056 //
2057 // Set BSP basic information
2058 //
2059 InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);
2060 //
2061 // Save assembly code information
2062 //
2063 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
2064 //
2065 // Finally set AP loop mode
2066 //
2067 CpuMpData->ApLoopMode = ApLoopMode;
2068 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
2069
2070 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
2071
2072 //
2073 // Set up APs wakeup signal buffer
2074 //
2075 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
2076 CpuMpData->CpuData[Index].StartupApSignal =
2077 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
2078 }
2079 //
2080 // Enable the local APIC for Virtual Wire Mode.
2081 //
2082 ProgramVirtualWireMode ();
2083
2084 if (OldCpuMpData == NULL) {
2085 if (MaxLogicalProcessorNumber > 1) {
2086 //
2087 // Wakeup all APs and calculate the processor count in system
2088 //
2089 CollectProcessorCount (CpuMpData);
2090 }
2091 } else {
2092 //
2093 // APs have been wakeup before, just get the CPU Information
2094 // from HOB
2095 //
2096 OldCpuMpData->NewCpuMpData = CpuMpData;
2097 CpuMpData->CpuCount = OldCpuMpData->CpuCount;
2098 CpuMpData->BspNumber = OldCpuMpData->BspNumber;
2099 CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;
2100 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
2101 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2102 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
2103 CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;
2104 CpuMpData->CpuData[Index].ApFunction = 0;
2105 }
2106 }
2107
2108 if (!GetMicrocodePatchInfoFromHob (
2109 &CpuMpData->MicrocodePatchAddress,
2110 &CpuMpData->MicrocodePatchRegionSize
2111 )) {
2112 //
2113 // The microcode patch information cache HOB does not exist, which means
2114 // the microcode patches data has not been loaded into memory yet
2115 //
2116 ShadowMicrocodeUpdatePatch (CpuMpData);
2117 }
2118
2119 //
2120 // Detect and apply Microcode on BSP
2121 //
2122 MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);
2123 //
2124 // Store BSP's MTRR setting
2125 //
2126 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
2127
2128 //
2129 // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
2130 //
2131 if (CpuMpData->CpuCount > 1) {
2132 if (OldCpuMpData != NULL) {
2133 //
2134 // Only needs to use this flag for DXE phase to update the wake up
2135 // buffer. Wakeup buffer allocated in PEI phase is no longer valid
2136 // in DXE.
2137 //
2138 CpuMpData->InitFlag = ApInitReconfig;
2139 }
2140 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);
2141 //
2142 // Wait for all APs finished initialization
2143 //
2144 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
2145 CpuPause ();
2146 }
2147 if (OldCpuMpData != NULL) {
2148 CpuMpData->InitFlag = ApInitDone;
2149 }
2150 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2151 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
2152 }
2153 }
2154
2155 //
2156 // Dump the microcode revision for each core.
2157 //
2158 DEBUG_CODE (
2159 UINT32 ThreadId;
2160 UINT32 ExpectedMicrocodeRevision;
2161 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
2162 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2163 GetProcessorLocationByApicId (CpuInfoInHob[Index].InitialApicId, NULL, NULL, &ThreadId);
2164 if (ThreadId == 0) {
2165 //
2166 // MicrocodeDetect() loads microcode in first thread of each core, so,
2167 // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.
2168 //
2169 ExpectedMicrocodeRevision = 0;
2170 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
2171 ExpectedMicrocodeRevision = ((CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->CpuData[Index].MicrocodeEntryAddr)->UpdateRevision;
2172 }
2173 DEBUG ((
2174 DEBUG_INFO, "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",
2175 Index, CpuMpData->CpuData[Index].MicrocodeRevision, ExpectedMicrocodeRevision
2176 ));
2177 }
2178 }
2179 );
2180 //
2181 // Initialize global data for MP support
2182 //
2183 InitMpGlobalData (CpuMpData);
2184
2185 return EFI_SUCCESS;
2186 }
2187
2188 /**
2189 Gets detailed MP-related information on the requested processor at the
2190 instant this call is made. This service may only be called from the BSP.
2191
2192 @param[in] ProcessorNumber The handle number of processor.
2193 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
2194 the requested processor is deposited.
2195 @param[out] HealthData Return processor health data.
2196
2197 @retval EFI_SUCCESS Processor information was returned.
2198 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2199 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
2200 @retval EFI_NOT_FOUND The processor with the handle specified by
2201 ProcessorNumber does not exist in the platform.
2202 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2203
2204 **/
2205 EFI_STATUS
2206 EFIAPI
2207 MpInitLibGetProcessorInfo (
2208 IN UINTN ProcessorNumber,
2209 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
2210 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
2211 )
2212 {
2213 CPU_MP_DATA *CpuMpData;
2214 UINTN CallerNumber;
2215 CPU_INFO_IN_HOB *CpuInfoInHob;
2216 UINTN OriginalProcessorNumber;
2217
2218 CpuMpData = GetCpuMpData ();
2219 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
2220
2221 //
2222 // Lower 24 bits contains the actual processor number.
2223 //
2224 OriginalProcessorNumber = ProcessorNumber;
2225 ProcessorNumber &= BIT24 - 1;
2226
2227 //
2228 // Check whether caller processor is BSP
2229 //
2230 MpInitLibWhoAmI (&CallerNumber);
2231 if (CallerNumber != CpuMpData->BspNumber) {
2232 return EFI_DEVICE_ERROR;
2233 }
2234
2235 if (ProcessorInfoBuffer == NULL) {
2236 return EFI_INVALID_PARAMETER;
2237 }
2238
2239 if (ProcessorNumber >= CpuMpData->CpuCount) {
2240 return EFI_NOT_FOUND;
2241 }
2242
2243 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuInfoInHob[ProcessorNumber].ApicId;
2244 ProcessorInfoBuffer->StatusFlag = 0;
2245 if (ProcessorNumber == CpuMpData->BspNumber) {
2246 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
2247 }
2248 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
2249 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
2250 }
2251 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
2252 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
2253 } else {
2254 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
2255 }
2256
2257 //
2258 // Get processor location information
2259 //
2260 GetProcessorLocationByApicId (
2261 CpuInfoInHob[ProcessorNumber].ApicId,
2262 &ProcessorInfoBuffer->Location.Package,
2263 &ProcessorInfoBuffer->Location.Core,
2264 &ProcessorInfoBuffer->Location.Thread
2265 );
2266
2267 if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {
2268 GetProcessorLocation2ByApicId (
2269 CpuInfoInHob[ProcessorNumber].ApicId,
2270 &ProcessorInfoBuffer->ExtendedInformation.Location2.Package,
2271 &ProcessorInfoBuffer->ExtendedInformation.Location2.Die,
2272 &ProcessorInfoBuffer->ExtendedInformation.Location2.Tile,
2273 &ProcessorInfoBuffer->ExtendedInformation.Location2.Module,
2274 &ProcessorInfoBuffer->ExtendedInformation.Location2.Core,
2275 &ProcessorInfoBuffer->ExtendedInformation.Location2.Thread
2276 );
2277 }
2278
2279 if (HealthData != NULL) {
2280 HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
2281 }
2282
2283 return EFI_SUCCESS;
2284 }
2285
2286 /**
2287 Worker function to switch the requested AP to be the BSP from that point onward.
2288
2289 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
2290 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
2291 enabled AP. Otherwise, it will be disabled.
2292
2293 @retval EFI_SUCCESS BSP successfully switched.
2294 @retval others Failed to switch BSP.
2295
2296 **/
2297 EFI_STATUS
2298 SwitchBSPWorker (
2299 IN UINTN ProcessorNumber,
2300 IN BOOLEAN EnableOldBSP
2301 )
2302 {
2303 CPU_MP_DATA *CpuMpData;
2304 UINTN CallerNumber;
2305 CPU_STATE State;
2306 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
2307 BOOLEAN OldInterruptState;
2308 BOOLEAN OldTimerInterruptState;
2309
2310 //
2311 // Save and Disable Local APIC timer interrupt
2312 //
2313 OldTimerInterruptState = GetApicTimerInterruptState ();
2314 DisableApicTimerInterrupt ();
2315 //
2316 // Before send both BSP and AP to a procedure to exchange their roles,
2317 // interrupt must be disabled. This is because during the exchange role
2318 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
2319 // be corrupted, since interrupt return address will be pushed to stack
2320 // by hardware.
2321 //
2322 OldInterruptState = SaveAndDisableInterrupts ();
2323
2324 //
2325 // Mask LINT0 & LINT1 for the old BSP
2326 //
2327 DisableLvtInterrupts ();
2328
2329 CpuMpData = GetCpuMpData ();
2330
2331 //
2332 // Check whether caller processor is BSP
2333 //
2334 MpInitLibWhoAmI (&CallerNumber);
2335 if (CallerNumber != CpuMpData->BspNumber) {
2336 return EFI_DEVICE_ERROR;
2337 }
2338
2339 if (ProcessorNumber >= CpuMpData->CpuCount) {
2340 return EFI_NOT_FOUND;
2341 }
2342
2343 //
2344 // Check whether specified AP is disabled
2345 //
2346 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
2347 if (State == CpuStateDisabled) {
2348 return EFI_INVALID_PARAMETER;
2349 }
2350
2351 //
2352 // Check whether ProcessorNumber specifies the current BSP
2353 //
2354 if (ProcessorNumber == CpuMpData->BspNumber) {
2355 return EFI_INVALID_PARAMETER;
2356 }
2357
2358 //
2359 // Check whether specified AP is busy
2360 //
2361 if (State == CpuStateBusy) {
2362 return EFI_NOT_READY;
2363 }
2364
2365 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
2366 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
2367 CpuMpData->SwitchBspFlag = TRUE;
2368 CpuMpData->NewBspNumber = ProcessorNumber;
2369
2370 //
2371 // Clear the BSP bit of MSR_IA32_APIC_BASE
2372 //
2373 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2374 ApicBaseMsr.Bits.BSP = 0;
2375 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2376
2377 //
2378 // Need to wakeUp AP (future BSP).
2379 //
2380 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);
2381
2382 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
2383
2384 //
2385 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
2386 //
2387 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2388 ApicBaseMsr.Bits.BSP = 1;
2389 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2390 ProgramVirtualWireMode ();
2391
2392 //
2393 // Wait for old BSP finished AP task
2394 //
2395 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
2396 CpuPause ();
2397 }
2398
2399 CpuMpData->SwitchBspFlag = FALSE;
2400 //
2401 // Set old BSP enable state
2402 //
2403 if (!EnableOldBSP) {
2404 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
2405 } else {
2406 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);
2407 }
2408 //
2409 // Save new BSP number
2410 //
2411 CpuMpData->BspNumber = (UINT32) ProcessorNumber;
2412
2413 //
2414 // Restore interrupt state.
2415 //
2416 SetInterruptState (OldInterruptState);
2417
2418 if (OldTimerInterruptState) {
2419 EnableApicTimerInterrupt ();
2420 }
2421
2422 return EFI_SUCCESS;
2423 }
2424
2425 /**
2426 Worker function to let the caller enable or disable an AP from this point onward.
2427 This service may only be called from the BSP.
2428
2429 @param[in] ProcessorNumber The handle number of AP.
2430 @param[in] EnableAP Specifies the new state for the processor for
2431 enabled, FALSE for disabled.
2432 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
2433 the new health status of the AP.
2434
2435 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
2436 @retval others Failed to Enable/Disable AP.
2437
2438 **/
2439 EFI_STATUS
2440 EnableDisableApWorker (
2441 IN UINTN ProcessorNumber,
2442 IN BOOLEAN EnableAP,
2443 IN UINT32 *HealthFlag OPTIONAL
2444 )
2445 {
2446 CPU_MP_DATA *CpuMpData;
2447 UINTN CallerNumber;
2448
2449 CpuMpData = GetCpuMpData ();
2450
2451 //
2452 // Check whether caller processor is BSP
2453 //
2454 MpInitLibWhoAmI (&CallerNumber);
2455 if (CallerNumber != CpuMpData->BspNumber) {
2456 return EFI_DEVICE_ERROR;
2457 }
2458
2459 if (ProcessorNumber == CpuMpData->BspNumber) {
2460 return EFI_INVALID_PARAMETER;
2461 }
2462
2463 if (ProcessorNumber >= CpuMpData->CpuCount) {
2464 return EFI_NOT_FOUND;
2465 }
2466
2467 if (!EnableAP) {
2468 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
2469 } else {
2470 ResetProcessorToIdleState (ProcessorNumber);
2471 }
2472
2473 if (HealthFlag != NULL) {
2474 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
2475 (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
2476 }
2477
2478 return EFI_SUCCESS;
2479 }
2480
2481 /**
2482 This return the handle number for the calling processor. This service may be
2483 called from the BSP and APs.
2484
2485 @param[out] ProcessorNumber Pointer to the handle number of AP.
2486 The range is from 0 to the total number of
2487 logical processors minus 1. The total number of
2488 logical processors can be retrieved by
2489 MpInitLibGetNumberOfProcessors().
2490
2491 @retval EFI_SUCCESS The current processor handle number was returned
2492 in ProcessorNumber.
2493 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
2494 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2495
2496 **/
2497 EFI_STATUS
2498 EFIAPI
2499 MpInitLibWhoAmI (
2500 OUT UINTN *ProcessorNumber
2501 )
2502 {
2503 CPU_MP_DATA *CpuMpData;
2504
2505 if (ProcessorNumber == NULL) {
2506 return EFI_INVALID_PARAMETER;
2507 }
2508
2509 CpuMpData = GetCpuMpData ();
2510
2511 return GetProcessorNumber (CpuMpData, ProcessorNumber);
2512 }
2513
2514 /**
2515 Retrieves the number of logical processor in the platform and the number of
2516 those logical processors that are enabled on this boot. This service may only
2517 be called from the BSP.
2518
2519 @param[out] NumberOfProcessors Pointer to the total number of logical
2520 processors in the system, including the BSP
2521 and disabled APs.
2522 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
2523 processors that exist in system, including
2524 the BSP.
2525
2526 @retval EFI_SUCCESS The number of logical processors and enabled
2527 logical processors was retrieved.
2528 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2529 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
2530 is NULL.
2531 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2532
2533 **/
2534 EFI_STATUS
2535 EFIAPI
2536 MpInitLibGetNumberOfProcessors (
2537 OUT UINTN *NumberOfProcessors OPTIONAL,
2538 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
2539 )
2540 {
2541 CPU_MP_DATA *CpuMpData;
2542 UINTN CallerNumber;
2543 UINTN ProcessorNumber;
2544 UINTN EnabledProcessorNumber;
2545 UINTN Index;
2546
2547 CpuMpData = GetCpuMpData ();
2548
2549 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
2550 return EFI_INVALID_PARAMETER;
2551 }
2552
2553 //
2554 // Check whether caller processor is BSP
2555 //
2556 MpInitLibWhoAmI (&CallerNumber);
2557 if (CallerNumber != CpuMpData->BspNumber) {
2558 return EFI_DEVICE_ERROR;
2559 }
2560
2561 ProcessorNumber = CpuMpData->CpuCount;
2562 EnabledProcessorNumber = 0;
2563 for (Index = 0; Index < ProcessorNumber; Index++) {
2564 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
2565 EnabledProcessorNumber ++;
2566 }
2567 }
2568
2569 if (NumberOfProcessors != NULL) {
2570 *NumberOfProcessors = ProcessorNumber;
2571 }
2572 if (NumberOfEnabledProcessors != NULL) {
2573 *NumberOfEnabledProcessors = EnabledProcessorNumber;
2574 }
2575
2576 return EFI_SUCCESS;
2577 }
2578
2579
2580 /**
2581 Worker function to execute a caller provided function on all enabled APs.
2582
2583 @param[in] Procedure A pointer to the function to be run on
2584 enabled APs of the system.
2585 @param[in] SingleThread If TRUE, then all the enabled APs execute
2586 the function specified by Procedure one by
2587 one, in ascending order of processor handle
2588 number. If FALSE, then all the enabled APs
2589 execute the function specified by Procedure
2590 simultaneously.
2591 @param[in] ExcludeBsp Whether let BSP also trig this task.
2592 @param[in] WaitEvent The event created by the caller with CreateEvent()
2593 service.
2594 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2595 APs to return from Procedure, either for
2596 blocking or non-blocking mode.
2597 @param[in] ProcedureArgument The parameter passed into Procedure for
2598 all APs.
2599 @param[out] FailedCpuList If all APs finish successfully, then its
2600 content is set to NULL. If not all APs
2601 finish before timeout expires, then its
2602 content is set to address of the buffer
2603 holding handle numbers of the failed APs.
2604
2605 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2606 the timeout expired.
2607 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2608 to all enabled APs.
2609 @retval others Failed to Startup all APs.
2610
2611 **/
2612 EFI_STATUS
2613 StartupAllCPUsWorker (
2614 IN EFI_AP_PROCEDURE Procedure,
2615 IN BOOLEAN SingleThread,
2616 IN BOOLEAN ExcludeBsp,
2617 IN EFI_EVENT WaitEvent OPTIONAL,
2618 IN UINTN TimeoutInMicroseconds,
2619 IN VOID *ProcedureArgument OPTIONAL,
2620 OUT UINTN **FailedCpuList OPTIONAL
2621 )
2622 {
2623 EFI_STATUS Status;
2624 CPU_MP_DATA *CpuMpData;
2625 UINTN ProcessorCount;
2626 UINTN ProcessorNumber;
2627 UINTN CallerNumber;
2628 CPU_AP_DATA *CpuData;
2629 BOOLEAN HasEnabledAp;
2630 CPU_STATE ApState;
2631
2632 CpuMpData = GetCpuMpData ();
2633
2634 if (FailedCpuList != NULL) {
2635 *FailedCpuList = NULL;
2636 }
2637
2638 if (CpuMpData->CpuCount == 1 && ExcludeBsp) {
2639 return EFI_NOT_STARTED;
2640 }
2641
2642 if (Procedure == NULL) {
2643 return EFI_INVALID_PARAMETER;
2644 }
2645
2646 //
2647 // Check whether caller processor is BSP
2648 //
2649 MpInitLibWhoAmI (&CallerNumber);
2650 if (CallerNumber != CpuMpData->BspNumber) {
2651 return EFI_DEVICE_ERROR;
2652 }
2653
2654 //
2655 // Update AP state
2656 //
2657 CheckAndUpdateApsStatus ();
2658
2659 ProcessorCount = CpuMpData->CpuCount;
2660 HasEnabledAp = FALSE;
2661 //
2662 // Check whether all enabled APs are idle.
2663 // If any enabled AP is not idle, return EFI_NOT_READY.
2664 //
2665 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2666 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2667 if (ProcessorNumber != CpuMpData->BspNumber) {
2668 ApState = GetApState (CpuData);
2669 if (ApState != CpuStateDisabled) {
2670 HasEnabledAp = TRUE;
2671 if (ApState != CpuStateIdle) {
2672 //
2673 // If any enabled APs are busy, return EFI_NOT_READY.
2674 //
2675 return EFI_NOT_READY;
2676 }
2677 }
2678 }
2679 }
2680
2681 if (!HasEnabledAp && ExcludeBsp) {
2682 //
2683 // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
2684 //
2685 return EFI_NOT_STARTED;
2686 }
2687
2688 CpuMpData->RunningCount = 0;
2689 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2690 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2691 CpuData->Waiting = FALSE;
2692 if (ProcessorNumber != CpuMpData->BspNumber) {
2693 if (CpuData->State == CpuStateIdle) {
2694 //
2695 // Mark this processor as responsible for current calling.
2696 //
2697 CpuData->Waiting = TRUE;
2698 CpuMpData->RunningCount++;
2699 }
2700 }
2701 }
2702
2703 CpuMpData->Procedure = Procedure;
2704 CpuMpData->ProcArguments = ProcedureArgument;
2705 CpuMpData->SingleThread = SingleThread;
2706 CpuMpData->FinishedCount = 0;
2707 CpuMpData->FailedCpuList = FailedCpuList;
2708 CpuMpData->ExpectedTime = CalculateTimeout (
2709 TimeoutInMicroseconds,
2710 &CpuMpData->CurrentTime
2711 );
2712 CpuMpData->TotalTime = 0;
2713 CpuMpData->WaitEvent = WaitEvent;
2714
2715 if (!SingleThread) {
2716 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
2717 } else {
2718 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
2719 if (ProcessorNumber == CallerNumber) {
2720 continue;
2721 }
2722 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
2723 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
2724 break;
2725 }
2726 }
2727 }
2728
2729 if (!ExcludeBsp) {
2730 //
2731 // Start BSP.
2732 //
2733 Procedure (ProcedureArgument);
2734 }
2735
2736 Status = EFI_SUCCESS;
2737 if (WaitEvent == NULL) {
2738 do {
2739 Status = CheckAllAPs ();
2740 } while (Status == EFI_NOT_READY);
2741 }
2742
2743 return Status;
2744 }
2745
2746 /**
2747 Worker function to let the caller get one enabled AP to execute a caller-provided
2748 function.
2749
2750 @param[in] Procedure A pointer to the function to be run on
2751 enabled APs of the system.
2752 @param[in] ProcessorNumber The handle number of the AP.
2753 @param[in] WaitEvent The event created by the caller with CreateEvent()
2754 service.
2755 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2756 APs to return from Procedure, either for
2757 blocking or non-blocking mode.
2758 @param[in] ProcedureArgument The parameter passed into Procedure for
2759 all APs.
2760 @param[out] Finished If AP returns from Procedure before the
2761 timeout expires, its content is set to TRUE.
2762 Otherwise, the value is set to FALSE.
2763
2764 @retval EFI_SUCCESS In blocking mode, specified AP finished before
2765 the timeout expires.
2766 @retval others Failed to Startup AP.
2767
2768 **/
2769 EFI_STATUS
2770 StartupThisAPWorker (
2771 IN EFI_AP_PROCEDURE Procedure,
2772 IN UINTN ProcessorNumber,
2773 IN EFI_EVENT WaitEvent OPTIONAL,
2774 IN UINTN TimeoutInMicroseconds,
2775 IN VOID *ProcedureArgument OPTIONAL,
2776 OUT BOOLEAN *Finished OPTIONAL
2777 )
2778 {
2779 EFI_STATUS Status;
2780 CPU_MP_DATA *CpuMpData;
2781 CPU_AP_DATA *CpuData;
2782 UINTN CallerNumber;
2783
2784 CpuMpData = GetCpuMpData ();
2785
2786 if (Finished != NULL) {
2787 *Finished = FALSE;
2788 }
2789
2790 //
2791 // Check whether caller processor is BSP
2792 //
2793 MpInitLibWhoAmI (&CallerNumber);
2794 if (CallerNumber != CpuMpData->BspNumber) {
2795 return EFI_DEVICE_ERROR;
2796 }
2797
2798 //
2799 // Check whether processor with the handle specified by ProcessorNumber exists
2800 //
2801 if (ProcessorNumber >= CpuMpData->CpuCount) {
2802 return EFI_NOT_FOUND;
2803 }
2804
2805 //
2806 // Check whether specified processor is BSP
2807 //
2808 if (ProcessorNumber == CpuMpData->BspNumber) {
2809 return EFI_INVALID_PARAMETER;
2810 }
2811
2812 //
2813 // Check parameter Procedure
2814 //
2815 if (Procedure == NULL) {
2816 return EFI_INVALID_PARAMETER;
2817 }
2818
2819 //
2820 // Update AP state
2821 //
2822 CheckAndUpdateApsStatus ();
2823
2824 //
2825 // Check whether specified AP is disabled
2826 //
2827 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
2828 return EFI_INVALID_PARAMETER;
2829 }
2830
2831 //
2832 // If WaitEvent is not NULL, execute in non-blocking mode.
2833 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
2834 // CheckAPsStatus() will check completion and timeout periodically.
2835 //
2836 CpuData = &CpuMpData->CpuData[ProcessorNumber];
2837 CpuData->WaitEvent = WaitEvent;
2838 CpuData->Finished = Finished;
2839 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
2840 CpuData->TotalTime = 0;
2841
2842 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
2843
2844 //
2845 // If WaitEvent is NULL, execute in blocking mode.
2846 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
2847 //
2848 Status = EFI_SUCCESS;
2849 if (WaitEvent == NULL) {
2850 do {
2851 Status = CheckThisAP (ProcessorNumber);
2852 } while (Status == EFI_NOT_READY);
2853 }
2854
2855 return Status;
2856 }
2857
2858 /**
2859 Get pointer to CPU MP Data structure from GUIDed HOB.
2860
2861 @return The pointer to CPU MP Data structure.
2862 **/
2863 CPU_MP_DATA *
2864 GetCpuMpDataFromGuidedHob (
2865 VOID
2866 )
2867 {
2868 EFI_HOB_GUID_TYPE *GuidHob;
2869 VOID *DataInHob;
2870 CPU_MP_DATA *CpuMpData;
2871
2872 CpuMpData = NULL;
2873 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
2874 if (GuidHob != NULL) {
2875 DataInHob = GET_GUID_HOB_DATA (GuidHob);
2876 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
2877 }
2878 return CpuMpData;
2879 }
2880
2881 /**
2882 This service executes a caller provided function on all enabled CPUs.
2883
2884 @param[in] Procedure A pointer to the function to be run on
2885 enabled APs of the system. See type
2886 EFI_AP_PROCEDURE.
2887 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2888 APs to return from Procedure, either for
2889 blocking or non-blocking mode. Zero means
2890 infinity. TimeoutInMicroseconds is ignored
2891 for BSP.
2892 @param[in] ProcedureArgument The parameter passed into Procedure for
2893 all APs.
2894
2895 @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
2896 the timeout expired.
2897 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2898 to all enabled CPUs.
2899 @retval EFI_DEVICE_ERROR Caller processor is AP.
2900 @retval EFI_NOT_READY Any enabled APs are busy.
2901 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2902 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
2903 all enabled APs have finished.
2904 @retval EFI_INVALID_PARAMETER Procedure is NULL.
2905
2906 **/
2907 EFI_STATUS
2908 EFIAPI
2909 MpInitLibStartupAllCPUs (
2910 IN EFI_AP_PROCEDURE Procedure,
2911 IN UINTN TimeoutInMicroseconds,
2912 IN VOID *ProcedureArgument OPTIONAL
2913 )
2914 {
2915 return StartupAllCPUsWorker (
2916 Procedure,
2917 FALSE,
2918 FALSE,
2919 NULL,
2920 TimeoutInMicroseconds,
2921 ProcedureArgument,
2922 NULL
2923 );
2924 }