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