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