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