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