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