]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Move timeout delay to WakupAp()
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
1 /** @file
2 CPU MP Initialize Library common functions.
3
4 Copyright (c) 2016, 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 DxeIpl may have enabled Execute Disable for BSP,
22 APs need to get the status and sync up the settings.
23
24 @retval TRUE BSP Execute Disable is enabled.
25 @retval FALSE BSP Execute Disable is not enabled.
26 **/
27 BOOLEAN
28 IsBspExecuteDisableEnabled (
29 VOID
30 )
31 {
32 UINT32 Eax;
33 CPUID_EXTENDED_CPU_SIG_EDX Edx;
34 MSR_IA32_EFER_REGISTER EferMsr;
35 BOOLEAN Enabled;
36
37 Enabled = FALSE;
38 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
39 if (Eax >= CPUID_EXTENDED_CPU_SIG) {
40 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
41 //
42 // CPUID 0x80000001
43 // Bit 20: Execute Disable Bit available.
44 //
45 if (Edx.Bits.NX != 0) {
46 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
47 //
48 // MSR 0xC0000080
49 // Bit 11: Execute Disable Bit enable.
50 //
51 if (EferMsr.Bits.NXE != 0) {
52 Enabled = TRUE;
53 }
54 }
55 }
56
57 return Enabled;
58 }
59
60 /**
61 Get CPU Package/Core/Thread location information.
62
63 @param[in] InitialApicId CPU APIC ID
64 @param[out] Location Pointer to CPU location information
65 **/
66 VOID
67 ExtractProcessorLocation (
68 IN UINT32 InitialApicId,
69 OUT EFI_CPU_PHYSICAL_LOCATION *Location
70 )
71 {
72 BOOLEAN TopologyLeafSupported;
73 UINTN ThreadBits;
74 UINTN CoreBits;
75 CPUID_VERSION_INFO_EBX VersionInfoEbx;
76 CPUID_VERSION_INFO_EDX VersionInfoEdx;
77 CPUID_CACHE_PARAMS_EAX CacheParamsEax;
78 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
79 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
80 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
81 UINT32 MaxCpuIdIndex;
82 UINT32 SubIndex;
83 UINTN LevelType;
84 UINT32 MaxLogicProcessorsPerPackage;
85 UINT32 MaxCoresPerPackage;
86
87 //
88 // Check if the processor is capable of supporting more than one logical processor.
89 //
90 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
91 if (VersionInfoEdx.Bits.HTT == 0) {
92 Location->Thread = 0;
93 Location->Core = 0;
94 Location->Package = 0;
95 return;
96 }
97
98 ThreadBits = 0;
99 CoreBits = 0;
100
101 //
102 // Assume three-level mapping of APIC ID: Package:Core:SMT.
103 //
104
105 TopologyLeafSupported = FALSE;
106 //
107 // Get the max index of basic CPUID
108 //
109 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
110
111 //
112 // If the extended topology enumeration leaf is available, it
113 // is the preferred mechanism for enumerating topology.
114 //
115 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
116 AsmCpuidEx (
117 CPUID_EXTENDED_TOPOLOGY,
118 0,
119 &ExtendedTopologyEax.Uint32,
120 &ExtendedTopologyEbx.Uint32,
121 &ExtendedTopologyEcx.Uint32,
122 NULL
123 );
124 //
125 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
126 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
127 // supported on that processor.
128 //
129 if (ExtendedTopologyEbx.Uint32 != 0) {
130 TopologyLeafSupported = TRUE;
131
132 //
133 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
134 // the SMT sub-field of x2APIC ID.
135 //
136 LevelType = ExtendedTopologyEcx.Bits.LevelType;
137 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
138 ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
139
140 //
141 // Software must not assume any "level type" encoding
142 // value to be related to any sub-leaf index, except sub-leaf 0.
143 //
144 SubIndex = 1;
145 do {
146 AsmCpuidEx (
147 CPUID_EXTENDED_TOPOLOGY,
148 SubIndex,
149 &ExtendedTopologyEax.Uint32,
150 NULL,
151 &ExtendedTopologyEcx.Uint32,
152 NULL
153 );
154 LevelType = ExtendedTopologyEcx.Bits.LevelType;
155 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
156 CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
157 break;
158 }
159 SubIndex++;
160 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
161 }
162 }
163
164 if (!TopologyLeafSupported) {
165 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
166 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
167 if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
168 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
169 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
170 } else {
171 //
172 // Must be a single-core processor.
173 //
174 MaxCoresPerPackage = 1;
175 }
176
177 ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
178 CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
179 }
180
181 Location->Thread = InitialApicId & ((1 << ThreadBits) - 1);
182 Location->Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
183 Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
184 }
185
186 /**
187 Worker function for SwitchBSP().
188
189 Worker function for SwitchBSP(), assigned to the AP which is intended
190 to become BSP.
191
192 @param[in] Buffer Pointer to CPU MP Data
193 **/
194 VOID
195 EFIAPI
196 FutureBSPProc (
197 IN VOID *Buffer
198 )
199 {
200 CPU_MP_DATA *DataInHob;
201
202 DataInHob = (CPU_MP_DATA *) Buffer;
203 AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
204 }
205
206 /**
207 Get the Application Processors state.
208
209 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
210
211 @return The AP status
212 **/
213 CPU_STATE
214 GetApState (
215 IN CPU_AP_DATA *CpuData
216 )
217 {
218 return CpuData->State;
219 }
220
221 /**
222 Set the Application Processors state.
223
224 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
225 @param[in] State The AP status
226 **/
227 VOID
228 SetApState (
229 IN CPU_AP_DATA *CpuData,
230 IN CPU_STATE State
231 )
232 {
233 AcquireSpinLock (&CpuData->ApLock);
234 CpuData->State = State;
235 ReleaseSpinLock (&CpuData->ApLock);
236 }
237
238 /**
239 Save the volatile registers required to be restored following INIT IPI.
240
241 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
242 **/
243 VOID
244 SaveVolatileRegisters (
245 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
246 )
247 {
248 CPUID_VERSION_INFO_EDX VersionInfoEdx;
249
250 VolatileRegisters->Cr0 = AsmReadCr0 ();
251 VolatileRegisters->Cr3 = AsmReadCr3 ();
252 VolatileRegisters->Cr4 = AsmReadCr4 ();
253
254 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
255 if (VersionInfoEdx.Bits.DE != 0) {
256 //
257 // If processor supports Debugging Extensions feature
258 // by CPUID.[EAX=01H]:EDX.BIT2
259 //
260 VolatileRegisters->Dr0 = AsmReadDr0 ();
261 VolatileRegisters->Dr1 = AsmReadDr1 ();
262 VolatileRegisters->Dr2 = AsmReadDr2 ();
263 VolatileRegisters->Dr3 = AsmReadDr3 ();
264 VolatileRegisters->Dr6 = AsmReadDr6 ();
265 VolatileRegisters->Dr7 = AsmReadDr7 ();
266 }
267 }
268
269 /**
270 Restore the volatile registers following INIT IPI.
271
272 @param[in] VolatileRegisters Pointer to volatile resisters
273 @param[in] IsRestoreDr TRUE: Restore DRx if supported
274 FALSE: Do not restore DRx
275 **/
276 VOID
277 RestoreVolatileRegisters (
278 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
279 IN BOOLEAN IsRestoreDr
280 )
281 {
282 CPUID_VERSION_INFO_EDX VersionInfoEdx;
283
284 AsmWriteCr0 (VolatileRegisters->Cr0);
285 AsmWriteCr3 (VolatileRegisters->Cr3);
286 AsmWriteCr4 (VolatileRegisters->Cr4);
287
288 if (IsRestoreDr) {
289 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
290 if (VersionInfoEdx.Bits.DE != 0) {
291 //
292 // If processor supports Debugging Extensions feature
293 // by CPUID.[EAX=01H]:EDX.BIT2
294 //
295 AsmWriteDr0 (VolatileRegisters->Dr0);
296 AsmWriteDr1 (VolatileRegisters->Dr1);
297 AsmWriteDr2 (VolatileRegisters->Dr2);
298 AsmWriteDr3 (VolatileRegisters->Dr3);
299 AsmWriteDr6 (VolatileRegisters->Dr6);
300 AsmWriteDr7 (VolatileRegisters->Dr7);
301 }
302 }
303 }
304
305 /**
306 Detect whether Mwait-monitor feature is supported.
307
308 @retval TRUE Mwait-monitor feature is supported.
309 @retval FALSE Mwait-monitor feature is not supported.
310 **/
311 BOOLEAN
312 IsMwaitSupport (
313 VOID
314 )
315 {
316 CPUID_VERSION_INFO_ECX VersionInfoEcx;
317
318 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
319 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
320 }
321
322 /**
323 Get AP loop mode.
324
325 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
326
327 @return The AP loop mode.
328 **/
329 UINT8
330 GetApLoopMode (
331 OUT UINT32 *MonitorFilterSize
332 )
333 {
334 UINT8 ApLoopMode;
335 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
336
337 ASSERT (MonitorFilterSize != NULL);
338
339 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
340 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
341 if (ApLoopMode == ApInMwaitLoop) {
342 if (!IsMwaitSupport ()) {
343 //
344 // If processor does not support MONITOR/MWAIT feature,
345 // force AP in Hlt-loop mode
346 //
347 ApLoopMode = ApInHltLoop;
348 }
349 }
350
351 if (ApLoopMode != ApInMwaitLoop) {
352 *MonitorFilterSize = sizeof (UINT32);
353 } else {
354 //
355 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
356 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
357 //
358 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
359 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
360 }
361
362 return ApLoopMode;
363 }
364
365 /**
366 Sort the APIC ID of all processors.
367
368 This function sorts the APIC ID of all processors so that processor number is
369 assigned in the ascending order of APIC ID which eases MP debugging.
370
371 @param[in] CpuMpData Pointer to PEI CPU MP Data
372 **/
373 VOID
374 SortApicId (
375 IN CPU_MP_DATA *CpuMpData
376 )
377 {
378 UINTN Index1;
379 UINTN Index2;
380 UINTN Index3;
381 UINT32 ApicId;
382 CPU_AP_DATA CpuData;
383 UINT32 ApCount;
384 CPU_INFO_IN_HOB *CpuInfoInHob;
385
386 ApCount = CpuMpData->CpuCount - 1;
387
388 if (ApCount != 0) {
389 for (Index1 = 0; Index1 < ApCount; Index1++) {
390 Index3 = Index1;
391 //
392 // Sort key is the hardware default APIC ID
393 //
394 ApicId = CpuMpData->CpuData[Index1].ApicId;
395 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
396 if (ApicId > CpuMpData->CpuData[Index2].ApicId) {
397 Index3 = Index2;
398 ApicId = CpuMpData->CpuData[Index2].ApicId;
399 }
400 }
401 if (Index3 != Index1) {
402 CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));
403 CopyMem (
404 &CpuMpData->CpuData[Index3],
405 &CpuMpData->CpuData[Index1],
406 sizeof (CPU_AP_DATA)
407 );
408 CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));
409 }
410 }
411
412 //
413 // Get the processor number for the BSP
414 //
415 ApicId = GetInitialApicId ();
416 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
417 if (CpuMpData->CpuData[Index1].ApicId == ApicId) {
418 CpuMpData->BspNumber = (UINT32) Index1;
419 break;
420 }
421 }
422
423 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
424 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
425 CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;
426 CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;
427 CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;
428 }
429 }
430 }
431
432 /**
433 Enable x2APIC mode on APs.
434
435 @param[in, out] Buffer Pointer to private data buffer.
436 **/
437 VOID
438 EFIAPI
439 ApFuncEnableX2Apic (
440 IN OUT VOID *Buffer
441 )
442 {
443 SetApicMode (LOCAL_APIC_MODE_X2APIC);
444 }
445
446 /**
447 Do sync on APs.
448
449 @param[in, out] Buffer Pointer to private data buffer.
450 **/
451 VOID
452 EFIAPI
453 ApInitializeSync (
454 IN OUT VOID *Buffer
455 )
456 {
457 CPU_MP_DATA *CpuMpData;
458
459 CpuMpData = (CPU_MP_DATA *) Buffer;
460 //
461 // Sync BSP's MTRR table to AP
462 //
463 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
464 //
465 // Load microcode on AP
466 //
467 MicrocodeDetect (CpuMpData);
468 }
469
470 /**
471 Find the current Processor number by APIC ID.
472
473 @param[in] CpuMpData Pointer to PEI CPU MP Data
474 @param[in] ProcessorNumber Return the pocessor number found
475
476 @retval EFI_SUCCESS ProcessorNumber is found and returned.
477 @retval EFI_NOT_FOUND ProcessorNumber is not found.
478 **/
479 EFI_STATUS
480 GetProcessorNumber (
481 IN CPU_MP_DATA *CpuMpData,
482 OUT UINTN *ProcessorNumber
483 )
484 {
485 UINTN TotalProcessorNumber;
486 UINTN Index;
487
488 TotalProcessorNumber = CpuMpData->CpuCount;
489 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
490 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
491 *ProcessorNumber = Index;
492 return EFI_SUCCESS;
493 }
494 }
495 return EFI_NOT_FOUND;
496 }
497
498 /**
499 This function will get CPU count in the system.
500
501 @param[in] CpuMpData Pointer to PEI CPU MP Data
502
503 @return CPU count detected
504 **/
505 UINTN
506 CollectProcessorCount (
507 IN CPU_MP_DATA *CpuMpData
508 )
509 {
510 //
511 // Send 1st broadcast IPI to APs to wakeup APs
512 //
513 CpuMpData->InitFlag = ApInitConfig;
514 CpuMpData->X2ApicEnable = FALSE;
515 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
516 CpuMpData->InitFlag = ApInitDone;
517 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
518 //
519 // Wait for all APs finished the initialization
520 //
521 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
522 CpuPause ();
523 }
524
525 if (CpuMpData->X2ApicEnable) {
526 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
527 //
528 // Wakeup all APs to enable x2APIC mode
529 //
530 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
531 //
532 // Wait for all known APs finished
533 //
534 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
535 CpuPause ();
536 }
537 //
538 // Enable x2APIC on BSP
539 //
540 SetApicMode (LOCAL_APIC_MODE_X2APIC);
541 }
542 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
543 //
544 // Sort BSP/Aps by CPU APIC ID in ascending order
545 //
546 SortApicId (CpuMpData);
547
548 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
549
550 return CpuMpData->CpuCount;
551 }
552
553 /*
554 Initialize CPU AP Data when AP is wakeup at the first time.
555
556 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
557 @param[in] ProcessorNumber The handle number of processor
558 @param[in] BistData Processor BIST data
559
560 **/
561 VOID
562 InitializeApData (
563 IN OUT CPU_MP_DATA *CpuMpData,
564 IN UINTN ProcessorNumber,
565 IN UINT32 BistData
566 )
567 {
568 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
569 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
570 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
571 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
572 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
573 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
574 //
575 // Set x2APIC mode if there are any logical processor reporting
576 // an Initial APIC ID of 255 or greater.
577 //
578 AcquireSpinLock(&CpuMpData->MpLock);
579 CpuMpData->X2ApicEnable = TRUE;
580 ReleaseSpinLock(&CpuMpData->MpLock);
581 }
582
583 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
584 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
585 }
586
587 /**
588 This function will be called from AP reset code if BSP uses WakeUpAP.
589
590 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
591 @param[in] NumApsExecuting Number of current executing AP
592 **/
593 VOID
594 EFIAPI
595 ApWakeupFunction (
596 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
597 IN UINTN NumApsExecuting
598 )
599 {
600 CPU_MP_DATA *CpuMpData;
601 UINTN ProcessorNumber;
602 EFI_AP_PROCEDURE Procedure;
603 VOID *Parameter;
604 UINT32 BistData;
605 volatile UINT32 *ApStartupSignalBuffer;
606
607 //
608 // AP finished assembly code and begin to execute C code
609 //
610 CpuMpData = ExchangeInfo->CpuMpData;
611
612 ProgramVirtualWireMode ();
613
614 while (TRUE) {
615 if (CpuMpData->InitFlag == ApInitConfig) {
616 //
617 // Add CPU number
618 //
619 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
620 ProcessorNumber = NumApsExecuting;
621 //
622 // This is first time AP wakeup, get BIST information from AP stack
623 //
624 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
625 //
626 // Do some AP initialize sync
627 //
628 ApInitializeSync (CpuMpData);
629 //
630 // Sync BSP's Control registers to APs
631 //
632 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
633 InitializeApData (CpuMpData, ProcessorNumber, BistData);
634 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
635 } else {
636 //
637 // Execute AP function if AP is ready
638 //
639 GetProcessorNumber (CpuMpData, &ProcessorNumber);
640 //
641 // Clear AP start-up signal when AP waken up
642 //
643 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
644 InterlockedCompareExchange32 (
645 (UINT32 *) ApStartupSignalBuffer,
646 WAKEUP_AP_SIGNAL,
647 0
648 );
649 if (CpuMpData->ApLoopMode == ApInHltLoop) {
650 //
651 // Restore AP's volatile registers saved
652 //
653 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
654 }
655
656 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
657 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
658 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
659 if (Procedure != NULL) {
660 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
661 //
662 // Invoke AP function here
663 //
664 Procedure (Parameter);
665 if (CpuMpData->SwitchBspFlag) {
666 //
667 // Re-get the processor number due to BSP/AP maybe exchange in AP function
668 //
669 GetProcessorNumber (CpuMpData, &ProcessorNumber);
670 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
671 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
672 } else {
673 //
674 // Re-get the CPU APICID and Initial APICID
675 //
676 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
677 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
678 }
679 }
680 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
681 }
682 }
683
684 //
685 // AP finished executing C code
686 //
687 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
688
689 //
690 // Place AP is specified loop mode
691 //
692 if (CpuMpData->ApLoopMode == ApInHltLoop) {
693 //
694 // Save AP volatile registers
695 //
696 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
697 //
698 // Place AP in HLT-loop
699 //
700 while (TRUE) {
701 DisableInterrupts ();
702 CpuSleep ();
703 CpuPause ();
704 }
705 }
706 while (TRUE) {
707 DisableInterrupts ();
708 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
709 //
710 // Place AP in MWAIT-loop
711 //
712 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
713 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
714 //
715 // Check AP start-up signal again.
716 // If AP start-up signal is not set, place AP into
717 // the specified C-state
718 //
719 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
720 }
721 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
722 //
723 // Place AP in Run-loop
724 //
725 CpuPause ();
726 } else {
727 ASSERT (FALSE);
728 }
729
730 //
731 // If AP start-up signal is written, AP is waken up
732 // otherwise place AP in loop again
733 //
734 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
735 break;
736 }
737 }
738 }
739 }
740
741 /**
742 Wait for AP wakeup and write AP start-up signal till AP is waken up.
743
744 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
745 **/
746 VOID
747 WaitApWakeup (
748 IN volatile UINT32 *ApStartupSignalBuffer
749 )
750 {
751 //
752 // If AP is waken up, StartupApSignal should be cleared.
753 // Otherwise, write StartupApSignal again till AP waken up.
754 //
755 while (InterlockedCompareExchange32 (
756 (UINT32 *) ApStartupSignalBuffer,
757 WAKEUP_AP_SIGNAL,
758 WAKEUP_AP_SIGNAL
759 ) != 0) {
760 CpuPause ();
761 }
762 }
763
764 /**
765 This function will fill the exchange info structure.
766
767 @param[in] CpuMpData Pointer to CPU MP Data
768
769 **/
770 VOID
771 FillExchangeInfoData (
772 IN CPU_MP_DATA *CpuMpData
773 )
774 {
775 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
776
777 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
778 ExchangeInfo->Lock = 0;
779 ExchangeInfo->StackStart = CpuMpData->Buffer;
780 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
781 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
782 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
783
784 ExchangeInfo->CodeSegment = AsmReadCs ();
785 ExchangeInfo->DataSegment = AsmReadDs ();
786
787 ExchangeInfo->Cr3 = AsmReadCr3 ();
788
789 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
790 ExchangeInfo->NumApsExecuting = 0;
791 ExchangeInfo->CpuMpData = CpuMpData;
792
793 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
794
795 //
796 // Get the BSP's data of GDT and IDT
797 //
798 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
799 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
800 }
801
802 /**
803 This function will be called by BSP to wakeup AP.
804
805 @param[in] CpuMpData Pointer to CPU MP Data
806 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
807 FALSE: Send IPI to AP by ApicId
808 @param[in] ProcessorNumber The handle number of specified processor
809 @param[in] Procedure The function to be invoked by AP
810 @param[in] ProcedureArgument The argument to be passed into AP function
811 **/
812 VOID
813 WakeUpAP (
814 IN CPU_MP_DATA *CpuMpData,
815 IN BOOLEAN Broadcast,
816 IN UINTN ProcessorNumber,
817 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
818 IN VOID *ProcedureArgument OPTIONAL
819 )
820 {
821 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
822 UINTN Index;
823 CPU_AP_DATA *CpuData;
824 BOOLEAN ResetVectorRequired;
825
826 CpuMpData->FinishedCount = 0;
827 ResetVectorRequired = FALSE;
828
829 if (CpuMpData->ApLoopMode == ApInHltLoop ||
830 CpuMpData->InitFlag != ApInitDone) {
831 ResetVectorRequired = TRUE;
832 AllocateResetVector (CpuMpData);
833 FillExchangeInfoData (CpuMpData);
834 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
835 //
836 // Get AP target C-state each time when waking up AP,
837 // for it maybe updated by platform again
838 //
839 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
840 }
841
842 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
843
844 if (Broadcast) {
845 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
846 if (Index != CpuMpData->BspNumber) {
847 CpuData = &CpuMpData->CpuData[Index];
848 CpuData->ApFunction = (UINTN) Procedure;
849 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
850 SetApState (CpuData, CpuStateReady);
851 if (CpuMpData->InitFlag != ApInitConfig) {
852 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
853 }
854 }
855 }
856 if (ResetVectorRequired) {
857 //
858 // Wakeup all APs
859 //
860 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
861 }
862 if (CpuMpData->InitFlag == ApInitConfig) {
863 //
864 // Wait for all potential APs waken up in one specified period
865 //
866 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
867 } else {
868 //
869 // Wait all APs waken up if this is not the 1st broadcast of SIPI
870 //
871 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
872 CpuData = &CpuMpData->CpuData[Index];
873 if (Index != CpuMpData->BspNumber) {
874 WaitApWakeup (CpuData->StartupApSignal);
875 }
876 }
877 }
878 } else {
879 CpuData = &CpuMpData->CpuData[ProcessorNumber];
880 CpuData->ApFunction = (UINTN) Procedure;
881 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
882 SetApState (CpuData, CpuStateReady);
883 //
884 // Wakeup specified AP
885 //
886 ASSERT (CpuMpData->InitFlag != ApInitConfig);
887 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
888 if (ResetVectorRequired) {
889 SendInitSipiSipi (
890 CpuData->ApicId,
891 (UINT32) ExchangeInfo->BufferStart
892 );
893 }
894 //
895 // Wait specified AP waken up
896 //
897 WaitApWakeup (CpuData->StartupApSignal);
898 }
899
900 if (ResetVectorRequired) {
901 FreeResetVector (CpuMpData);
902 }
903 }
904
905 /**
906 Calculate timeout value and return the current performance counter value.
907
908 Calculate the number of performance counter ticks required for a timeout.
909 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
910 as infinity.
911
912 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
913 @param[out] CurrentTime Returns the current value of the performance counter.
914
915 @return Expected time stamp counter for timeout.
916 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
917 as infinity.
918
919 **/
920 UINT64
921 CalculateTimeout (
922 IN UINTN TimeoutInMicroseconds,
923 OUT UINT64 *CurrentTime
924 )
925 {
926 //
927 // Read the current value of the performance counter
928 //
929 *CurrentTime = GetPerformanceCounter ();
930
931 //
932 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
933 // as infinity.
934 //
935 if (TimeoutInMicroseconds == 0) {
936 return 0;
937 }
938
939 //
940 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
941 // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide
942 // it by 1,000,000, to get the number of ticks for the timeout value.
943 //
944 return DivU64x32 (
945 MultU64x64 (
946 GetPerformanceCounterProperties (NULL, NULL),
947 TimeoutInMicroseconds
948 ),
949 1000000
950 );
951 }
952
953 /**
954 Checks whether timeout expires.
955
956 Check whether the number of elapsed performance counter ticks required for
957 a timeout condition has been reached.
958 If Timeout is zero, which means infinity, return value is always FALSE.
959
960 @param[in, out] PreviousTime On input, the value of the performance counter
961 when it was last read.
962 On output, the current value of the performance
963 counter
964 @param[in] TotalTime The total amount of elapsed time in performance
965 counter ticks.
966 @param[in] Timeout The number of performance counter ticks required
967 to reach a timeout condition.
968
969 @retval TRUE A timeout condition has been reached.
970 @retval FALSE A timeout condition has not been reached.
971
972 **/
973 BOOLEAN
974 CheckTimeout (
975 IN OUT UINT64 *PreviousTime,
976 IN UINT64 *TotalTime,
977 IN UINT64 Timeout
978 )
979 {
980 UINT64 Start;
981 UINT64 End;
982 UINT64 CurrentTime;
983 INT64 Delta;
984 INT64 Cycle;
985
986 if (Timeout == 0) {
987 return FALSE;
988 }
989 GetPerformanceCounterProperties (&Start, &End);
990 Cycle = End - Start;
991 if (Cycle < 0) {
992 Cycle = -Cycle;
993 }
994 Cycle++;
995 CurrentTime = GetPerformanceCounter();
996 Delta = (INT64) (CurrentTime - *PreviousTime);
997 if (Start > End) {
998 Delta = -Delta;
999 }
1000 if (Delta < 0) {
1001 Delta += Cycle;
1002 }
1003 *TotalTime += Delta;
1004 *PreviousTime = CurrentTime;
1005 if (*TotalTime > Timeout) {
1006 return TRUE;
1007 }
1008 return FALSE;
1009 }
1010
1011 /**
1012 Reset an AP to Idle state.
1013
1014 Any task being executed by the AP will be aborted and the AP
1015 will be waiting for a new task in Wait-For-SIPI state.
1016
1017 @param[in] ProcessorNumber The handle number of processor.
1018 **/
1019 VOID
1020 ResetProcessorToIdleState (
1021 IN UINTN ProcessorNumber
1022 )
1023 {
1024 CPU_MP_DATA *CpuMpData;
1025
1026 CpuMpData = GetCpuMpData ();
1027
1028 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);
1029
1030 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1031 }
1032
1033 /**
1034 Searches for the next waiting AP.
1035
1036 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1037
1038 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1039
1040 @retval EFI_SUCCESS The next waiting AP has been found.
1041 @retval EFI_NOT_FOUND No waiting AP exists.
1042
1043 **/
1044 EFI_STATUS
1045 GetNextWaitingProcessorNumber (
1046 OUT UINTN *NextProcessorNumber
1047 )
1048 {
1049 UINTN ProcessorNumber;
1050 CPU_MP_DATA *CpuMpData;
1051
1052 CpuMpData = GetCpuMpData ();
1053
1054 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1055 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1056 *NextProcessorNumber = ProcessorNumber;
1057 return EFI_SUCCESS;
1058 }
1059 }
1060
1061 return EFI_NOT_FOUND;
1062 }
1063
1064 /** Checks status of specified AP.
1065
1066 This function checks whether the specified AP has finished the task assigned
1067 by StartupThisAP(), and whether timeout expires.
1068
1069 @param[in] ProcessorNumber The handle number of processor.
1070
1071 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1072 @retval EFI_TIMEOUT The timeout expires.
1073 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1074 **/
1075 EFI_STATUS
1076 CheckThisAP (
1077 IN UINTN ProcessorNumber
1078 )
1079 {
1080 CPU_MP_DATA *CpuMpData;
1081 CPU_AP_DATA *CpuData;
1082
1083 CpuMpData = GetCpuMpData ();
1084 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1085
1086 //
1087 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1088 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1089 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1090 //
1091 //
1092 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1093 //
1094 if (GetApState(CpuData) == CpuStateFinished) {
1095 if (CpuData->Finished != NULL) {
1096 *(CpuData->Finished) = TRUE;
1097 }
1098 SetApState (CpuData, CpuStateIdle);
1099 return EFI_SUCCESS;
1100 } else {
1101 //
1102 // If timeout expires for StartupThisAP(), report timeout.
1103 //
1104 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
1105 if (CpuData->Finished != NULL) {
1106 *(CpuData->Finished) = FALSE;
1107 }
1108 //
1109 // Reset failed AP to idle state
1110 //
1111 ResetProcessorToIdleState (ProcessorNumber);
1112
1113 return EFI_TIMEOUT;
1114 }
1115 }
1116 return EFI_NOT_READY;
1117 }
1118
1119 /**
1120 Checks status of all APs.
1121
1122 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1123 and whether timeout expires.
1124
1125 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1126 @retval EFI_TIMEOUT The timeout expires.
1127 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1128 **/
1129 EFI_STATUS
1130 CheckAllAPs (
1131 VOID
1132 )
1133 {
1134 UINTN ProcessorNumber;
1135 UINTN NextProcessorNumber;
1136 UINTN ListIndex;
1137 EFI_STATUS Status;
1138 CPU_MP_DATA *CpuMpData;
1139 CPU_AP_DATA *CpuData;
1140
1141 CpuMpData = GetCpuMpData ();
1142
1143 NextProcessorNumber = 0;
1144
1145 //
1146 // Go through all APs that are responsible for the StartupAllAPs().
1147 //
1148 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1149 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
1150 continue;
1151 }
1152
1153 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1154 //
1155 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
1156 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1157 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
1158 //
1159 if (GetApState(CpuData) == CpuStateFinished) {
1160 CpuMpData->RunningCount ++;
1161 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1162 SetApState(CpuData, CpuStateIdle);
1163
1164 //
1165 // If in Single Thread mode, then search for the next waiting AP for execution.
1166 //
1167 if (CpuMpData->SingleThread) {
1168 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
1169
1170 if (!EFI_ERROR (Status)) {
1171 WakeUpAP (
1172 CpuMpData,
1173 FALSE,
1174 (UINT32) NextProcessorNumber,
1175 CpuMpData->Procedure,
1176 CpuMpData->ProcArguments
1177 );
1178 }
1179 }
1180 }
1181 }
1182
1183 //
1184 // If all APs finish, return EFI_SUCCESS.
1185 //
1186 if (CpuMpData->RunningCount == CpuMpData->StartCount) {
1187 return EFI_SUCCESS;
1188 }
1189
1190 //
1191 // If timeout expires, report timeout.
1192 //
1193 if (CheckTimeout (
1194 &CpuMpData->CurrentTime,
1195 &CpuMpData->TotalTime,
1196 CpuMpData->ExpectedTime)
1197 ) {
1198 //
1199 // If FailedCpuList is not NULL, record all failed APs in it.
1200 //
1201 if (CpuMpData->FailedCpuList != NULL) {
1202 *CpuMpData->FailedCpuList =
1203 AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));
1204 ASSERT (*CpuMpData->FailedCpuList != NULL);
1205 }
1206 ListIndex = 0;
1207
1208 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1209 //
1210 // Check whether this processor is responsible for StartupAllAPs().
1211 //
1212 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1213 //
1214 // Reset failed APs to idle state
1215 //
1216 ResetProcessorToIdleState (ProcessorNumber);
1217 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1218 if (CpuMpData->FailedCpuList != NULL) {
1219 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
1220 }
1221 }
1222 }
1223 if (CpuMpData->FailedCpuList != NULL) {
1224 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
1225 }
1226 return EFI_TIMEOUT;
1227 }
1228 return EFI_NOT_READY;
1229 }
1230
1231 /**
1232 MP Initialize Library initialization.
1233
1234 This service will allocate AP reset vector and wakeup all APs to do APs
1235 initialization.
1236
1237 This service must be invoked before all other MP Initialize Library
1238 service are invoked.
1239
1240 @retval EFI_SUCCESS MP initialization succeeds.
1241 @retval Others MP initialization fails.
1242
1243 **/
1244 EFI_STATUS
1245 EFIAPI
1246 MpInitLibInitialize (
1247 VOID
1248 )
1249 {
1250 CPU_MP_DATA *OldCpuMpData;
1251 CPU_INFO_IN_HOB *CpuInfoInHob;
1252 UINT32 MaxLogicalProcessorNumber;
1253 UINT32 ApStackSize;
1254 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
1255 UINTN BufferSize;
1256 UINT32 MonitorFilterSize;
1257 VOID *MpBuffer;
1258 UINTN Buffer;
1259 CPU_MP_DATA *CpuMpData;
1260 UINT8 ApLoopMode;
1261 UINT8 *MonitorBuffer;
1262 UINTN Index;
1263 UINTN ApResetVectorSize;
1264 UINTN BackupBufferAddr;
1265
1266 OldCpuMpData = GetCpuMpDataFromGuidedHob ();
1267 if (OldCpuMpData == NULL) {
1268 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
1269 } else {
1270 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
1271 }
1272
1273 AsmGetAddressMap (&AddressMap);
1274 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
1275 ApStackSize = PcdGet32(PcdCpuApStackSize);
1276 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
1277
1278 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
1279 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
1280 BufferSize += sizeof (CPU_MP_DATA);
1281 BufferSize += ApResetVectorSize;
1282 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
1283 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
1284 ASSERT (MpBuffer != NULL);
1285 ZeroMem (MpBuffer, BufferSize);
1286 Buffer = (UINTN) MpBuffer;
1287
1288 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
1289 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
1290 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
1291 CpuMpData->Buffer = Buffer;
1292 CpuMpData->CpuApStackSize = ApStackSize;
1293 CpuMpData->BackupBuffer = BackupBufferAddr;
1294 CpuMpData->BackupBufferSize = ApResetVectorSize;
1295 CpuMpData->EndOfPeiFlag = FALSE;
1296 CpuMpData->WakeupBuffer = (UINTN) -1;
1297 CpuMpData->CpuCount = 1;
1298 CpuMpData->BspNumber = 0;
1299 CpuMpData->WaitEvent = NULL;
1300 CpuMpData->SwitchBspFlag = FALSE;
1301 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
1302 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
1303 InitializeSpinLock(&CpuMpData->MpLock);
1304 //
1305 // Save BSP's Control registers to APs
1306 //
1307 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
1308 //
1309 // Set BSP basic information
1310 //
1311 InitializeApData (CpuMpData, 0, 0);
1312 //
1313 // Save assembly code information
1314 //
1315 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
1316 //
1317 // Finally set AP loop mode
1318 //
1319 CpuMpData->ApLoopMode = ApLoopMode;
1320 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
1321 //
1322 // Set up APs wakeup signal buffer
1323 //
1324 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
1325 CpuMpData->CpuData[Index].StartupApSignal =
1326 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
1327 }
1328 //
1329 // Load Microcode on BSP
1330 //
1331 MicrocodeDetect (CpuMpData);
1332 //
1333 // Store BSP's MTRR setting
1334 //
1335 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
1336
1337 if (OldCpuMpData == NULL) {
1338 //
1339 // Wakeup all APs and calculate the processor count in system
1340 //
1341 CollectProcessorCount (CpuMpData);
1342 } else {
1343 //
1344 // APs have been wakeup before, just get the CPU Information
1345 // from HOB
1346 //
1347 CpuMpData->CpuCount = OldCpuMpData->CpuCount;
1348 CpuMpData->BspNumber = OldCpuMpData->BspNumber;
1349 CpuMpData->InitFlag = ApInitReconfig;
1350 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;
1351 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1352 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
1353 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;
1354 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;
1355 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {
1356 CpuMpData->X2ApicEnable = TRUE;
1357 }
1358 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;
1359 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;
1360 CpuMpData->CpuData[Index].ApFunction = 0;
1361 CopyMem (
1362 &CpuMpData->CpuData[Index].VolatileRegisters,
1363 &CpuMpData->CpuData[0].VolatileRegisters,
1364 sizeof (CPU_VOLATILE_REGISTERS)
1365 );
1366 }
1367 //
1368 // Wakeup APs to do some AP initialize sync
1369 //
1370 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);
1371 //
1372 // Wait for all APs finished initialization
1373 //
1374 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
1375 CpuPause ();
1376 }
1377 CpuMpData->InitFlag = ApInitDone;
1378 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1379 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
1380 }
1381 }
1382
1383 //
1384 // Initialize global data for MP support
1385 //
1386 InitMpGlobalData (CpuMpData);
1387
1388 return EFI_SUCCESS;
1389 }
1390
1391 /**
1392 Gets detailed MP-related information on the requested processor at the
1393 instant this call is made. This service may only be called from the BSP.
1394
1395 @param[in] ProcessorNumber The handle number of processor.
1396 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1397 the requested processor is deposited.
1398 @param[out] HealthData Return processor health data.
1399
1400 @retval EFI_SUCCESS Processor information was returned.
1401 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1402 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1403 @retval EFI_NOT_FOUND The processor with the handle specified by
1404 ProcessorNumber does not exist in the platform.
1405 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1406
1407 **/
1408 EFI_STATUS
1409 EFIAPI
1410 MpInitLibGetProcessorInfo (
1411 IN UINTN ProcessorNumber,
1412 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
1413 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
1414 )
1415 {
1416 CPU_MP_DATA *CpuMpData;
1417 UINTN CallerNumber;
1418
1419 CpuMpData = GetCpuMpData ();
1420
1421 //
1422 // Check whether caller processor is BSP
1423 //
1424 MpInitLibWhoAmI (&CallerNumber);
1425 if (CallerNumber != CpuMpData->BspNumber) {
1426 return EFI_DEVICE_ERROR;
1427 }
1428
1429 if (ProcessorInfoBuffer == NULL) {
1430 return EFI_INVALID_PARAMETER;
1431 }
1432
1433 if (ProcessorNumber >= CpuMpData->CpuCount) {
1434 return EFI_NOT_FOUND;
1435 }
1436
1437 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;
1438 ProcessorInfoBuffer->StatusFlag = 0;
1439 if (ProcessorNumber == CpuMpData->BspNumber) {
1440 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
1441 }
1442 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
1443 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
1444 }
1445 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
1446 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
1447 } else {
1448 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
1449 }
1450
1451 //
1452 // Get processor location information
1453 //
1454 ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
1455
1456 if (HealthData != NULL) {
1457 HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;
1458 }
1459
1460 return EFI_SUCCESS;
1461 }
1462
1463 /**
1464 Worker function to switch the requested AP to be the BSP from that point onward.
1465
1466 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1467 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1468 enabled AP. Otherwise, it will be disabled.
1469
1470 @retval EFI_SUCCESS BSP successfully switched.
1471 @retval others Failed to switch BSP.
1472
1473 **/
1474 EFI_STATUS
1475 SwitchBSPWorker (
1476 IN UINTN ProcessorNumber,
1477 IN BOOLEAN EnableOldBSP
1478 )
1479 {
1480 CPU_MP_DATA *CpuMpData;
1481 UINTN CallerNumber;
1482 CPU_STATE State;
1483 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
1484
1485 CpuMpData = GetCpuMpData ();
1486
1487 //
1488 // Check whether caller processor is BSP
1489 //
1490 MpInitLibWhoAmI (&CallerNumber);
1491 if (CallerNumber != CpuMpData->BspNumber) {
1492 return EFI_SUCCESS;
1493 }
1494
1495 if (ProcessorNumber >= CpuMpData->CpuCount) {
1496 return EFI_NOT_FOUND;
1497 }
1498
1499 //
1500 // Check whether specified AP is disabled
1501 //
1502 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
1503 if (State == CpuStateDisabled) {
1504 return EFI_INVALID_PARAMETER;
1505 }
1506
1507 //
1508 // Check whether ProcessorNumber specifies the current BSP
1509 //
1510 if (ProcessorNumber == CpuMpData->BspNumber) {
1511 return EFI_INVALID_PARAMETER;
1512 }
1513
1514 //
1515 // Check whether specified AP is busy
1516 //
1517 if (State == CpuStateBusy) {
1518 return EFI_NOT_READY;
1519 }
1520
1521 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
1522 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
1523 CpuMpData->SwitchBspFlag = TRUE;
1524
1525 //
1526 // Clear the BSP bit of MSR_IA32_APIC_BASE
1527 //
1528 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
1529 ApicBaseMsr.Bits.BSP = 0;
1530 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
1531
1532 //
1533 // Need to wakeUp AP (future BSP).
1534 //
1535 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);
1536
1537 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
1538
1539 //
1540 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1541 //
1542 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
1543 ApicBaseMsr.Bits.BSP = 1;
1544 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
1545
1546 //
1547 // Wait for old BSP finished AP task
1548 //
1549 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
1550 CpuPause ();
1551 }
1552
1553 CpuMpData->SwitchBspFlag = FALSE;
1554 //
1555 // Set old BSP enable state
1556 //
1557 if (!EnableOldBSP) {
1558 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
1559 }
1560 //
1561 // Save new BSP number
1562 //
1563 CpuMpData->BspNumber = (UINT32) ProcessorNumber;
1564
1565 return EFI_SUCCESS;
1566 }
1567
1568 /**
1569 Worker function to let the caller enable or disable an AP from this point onward.
1570 This service may only be called from the BSP.
1571
1572 @param[in] ProcessorNumber The handle number of AP.
1573 @param[in] EnableAP Specifies the new state for the processor for
1574 enabled, FALSE for disabled.
1575 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1576 the new health status of the AP.
1577
1578 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1579 @retval others Failed to Enable/Disable AP.
1580
1581 **/
1582 EFI_STATUS
1583 EnableDisableApWorker (
1584 IN UINTN ProcessorNumber,
1585 IN BOOLEAN EnableAP,
1586 IN UINT32 *HealthFlag OPTIONAL
1587 )
1588 {
1589 CPU_MP_DATA *CpuMpData;
1590 UINTN CallerNumber;
1591
1592 CpuMpData = GetCpuMpData ();
1593
1594 //
1595 // Check whether caller processor is BSP
1596 //
1597 MpInitLibWhoAmI (&CallerNumber);
1598 if (CallerNumber != CpuMpData->BspNumber) {
1599 return EFI_DEVICE_ERROR;
1600 }
1601
1602 if (ProcessorNumber == CpuMpData->BspNumber) {
1603 return EFI_INVALID_PARAMETER;
1604 }
1605
1606 if (ProcessorNumber >= CpuMpData->CpuCount) {
1607 return EFI_NOT_FOUND;
1608 }
1609
1610 if (!EnableAP) {
1611 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
1612 } else {
1613 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1614 }
1615
1616 if (HealthFlag != NULL) {
1617 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
1618 (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
1619 }
1620
1621 return EFI_SUCCESS;
1622 }
1623
1624 /**
1625 This return the handle number for the calling processor. This service may be
1626 called from the BSP and APs.
1627
1628 @param[out] ProcessorNumber Pointer to the handle number of AP.
1629 The range is from 0 to the total number of
1630 logical processors minus 1. The total number of
1631 logical processors can be retrieved by
1632 MpInitLibGetNumberOfProcessors().
1633
1634 @retval EFI_SUCCESS The current processor handle number was returned
1635 in ProcessorNumber.
1636 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1637 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1638
1639 **/
1640 EFI_STATUS
1641 EFIAPI
1642 MpInitLibWhoAmI (
1643 OUT UINTN *ProcessorNumber
1644 )
1645 {
1646 CPU_MP_DATA *CpuMpData;
1647
1648 if (ProcessorNumber == NULL) {
1649 return EFI_INVALID_PARAMETER;
1650 }
1651
1652 CpuMpData = GetCpuMpData ();
1653
1654 return GetProcessorNumber (CpuMpData, ProcessorNumber);
1655 }
1656
1657 /**
1658 Retrieves the number of logical processor in the platform and the number of
1659 those logical processors that are enabled on this boot. This service may only
1660 be called from the BSP.
1661
1662 @param[out] NumberOfProcessors Pointer to the total number of logical
1663 processors in the system, including the BSP
1664 and disabled APs.
1665 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1666 processors that exist in system, including
1667 the BSP.
1668
1669 @retval EFI_SUCCESS The number of logical processors and enabled
1670 logical processors was retrieved.
1671 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1672 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1673 is NULL.
1674 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1675
1676 **/
1677 EFI_STATUS
1678 EFIAPI
1679 MpInitLibGetNumberOfProcessors (
1680 OUT UINTN *NumberOfProcessors, OPTIONAL
1681 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
1682 )
1683 {
1684 CPU_MP_DATA *CpuMpData;
1685 UINTN CallerNumber;
1686 UINTN ProcessorNumber;
1687 UINTN EnabledProcessorNumber;
1688 UINTN Index;
1689
1690 CpuMpData = GetCpuMpData ();
1691
1692 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
1693 return EFI_INVALID_PARAMETER;
1694 }
1695
1696 //
1697 // Check whether caller processor is BSP
1698 //
1699 MpInitLibWhoAmI (&CallerNumber);
1700 if (CallerNumber != CpuMpData->BspNumber) {
1701 return EFI_DEVICE_ERROR;
1702 }
1703
1704 ProcessorNumber = CpuMpData->CpuCount;
1705 EnabledProcessorNumber = 0;
1706 for (Index = 0; Index < ProcessorNumber; Index++) {
1707 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
1708 EnabledProcessorNumber ++;
1709 }
1710 }
1711
1712 if (NumberOfProcessors != NULL) {
1713 *NumberOfProcessors = ProcessorNumber;
1714 }
1715 if (NumberOfEnabledProcessors != NULL) {
1716 *NumberOfEnabledProcessors = EnabledProcessorNumber;
1717 }
1718
1719 return EFI_SUCCESS;
1720 }
1721
1722
1723 /**
1724 Worker function to execute a caller provided function on all enabled APs.
1725
1726 @param[in] Procedure A pointer to the function to be run on
1727 enabled APs of the system.
1728 @param[in] SingleThread If TRUE, then all the enabled APs execute
1729 the function specified by Procedure one by
1730 one, in ascending order of processor handle
1731 number. If FALSE, then all the enabled APs
1732 execute the function specified by Procedure
1733 simultaneously.
1734 @param[in] WaitEvent The event created by the caller with CreateEvent()
1735 service.
1736 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
1737 APs to return from Procedure, either for
1738 blocking or non-blocking mode.
1739 @param[in] ProcedureArgument The parameter passed into Procedure for
1740 all APs.
1741 @param[out] FailedCpuList If all APs finish successfully, then its
1742 content is set to NULL. If not all APs
1743 finish before timeout expires, then its
1744 content is set to address of the buffer
1745 holding handle numbers of the failed APs.
1746
1747 @retval EFI_SUCCESS In blocking mode, all APs have finished before
1748 the timeout expired.
1749 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
1750 to all enabled APs.
1751 @retval others Failed to Startup all APs.
1752
1753 **/
1754 EFI_STATUS
1755 StartupAllAPsWorker (
1756 IN EFI_AP_PROCEDURE Procedure,
1757 IN BOOLEAN SingleThread,
1758 IN EFI_EVENT WaitEvent OPTIONAL,
1759 IN UINTN TimeoutInMicroseconds,
1760 IN VOID *ProcedureArgument OPTIONAL,
1761 OUT UINTN **FailedCpuList OPTIONAL
1762 )
1763 {
1764 EFI_STATUS Status;
1765 CPU_MP_DATA *CpuMpData;
1766 UINTN ProcessorCount;
1767 UINTN ProcessorNumber;
1768 UINTN CallerNumber;
1769 CPU_AP_DATA *CpuData;
1770 BOOLEAN HasEnabledAp;
1771 CPU_STATE ApState;
1772
1773 CpuMpData = GetCpuMpData ();
1774
1775 if (FailedCpuList != NULL) {
1776 *FailedCpuList = NULL;
1777 }
1778
1779 if (CpuMpData->CpuCount == 1) {
1780 return EFI_NOT_STARTED;
1781 }
1782
1783 if (Procedure == NULL) {
1784 return EFI_INVALID_PARAMETER;
1785 }
1786
1787 //
1788 // Check whether caller processor is BSP
1789 //
1790 MpInitLibWhoAmI (&CallerNumber);
1791 if (CallerNumber != CpuMpData->BspNumber) {
1792 return EFI_DEVICE_ERROR;
1793 }
1794
1795 //
1796 // Update AP state
1797 //
1798 CheckAndUpdateApsStatus ();
1799
1800 ProcessorCount = CpuMpData->CpuCount;
1801 HasEnabledAp = FALSE;
1802 //
1803 // Check whether all enabled APs are idle.
1804 // If any enabled AP is not idle, return EFI_NOT_READY.
1805 //
1806 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
1807 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1808 if (ProcessorNumber != CpuMpData->BspNumber) {
1809 ApState = GetApState (CpuData);
1810 if (ApState != CpuStateDisabled) {
1811 HasEnabledAp = TRUE;
1812 if (ApState != CpuStateIdle) {
1813 //
1814 // If any enabled APs are busy, return EFI_NOT_READY.
1815 //
1816 return EFI_NOT_READY;
1817 }
1818 }
1819 }
1820 }
1821
1822 if (!HasEnabledAp) {
1823 //
1824 // If no enabled AP exists, return EFI_NOT_STARTED.
1825 //
1826 return EFI_NOT_STARTED;
1827 }
1828
1829 CpuMpData->StartCount = 0;
1830 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
1831 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1832 CpuData->Waiting = FALSE;
1833 if (ProcessorNumber != CpuMpData->BspNumber) {
1834 if (CpuData->State == CpuStateIdle) {
1835 //
1836 // Mark this processor as responsible for current calling.
1837 //
1838 CpuData->Waiting = TRUE;
1839 CpuMpData->StartCount++;
1840 }
1841 }
1842 }
1843
1844 CpuMpData->Procedure = Procedure;
1845 CpuMpData->ProcArguments = ProcedureArgument;
1846 CpuMpData->SingleThread = SingleThread;
1847 CpuMpData->FinishedCount = 0;
1848 CpuMpData->RunningCount = 0;
1849 CpuMpData->FailedCpuList = FailedCpuList;
1850 CpuMpData->ExpectedTime = CalculateTimeout (
1851 TimeoutInMicroseconds,
1852 &CpuMpData->CurrentTime
1853 );
1854 CpuMpData->TotalTime = 0;
1855 CpuMpData->WaitEvent = WaitEvent;
1856
1857 if (!SingleThread) {
1858 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument);
1859 } else {
1860 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
1861 if (ProcessorNumber == CallerNumber) {
1862 continue;
1863 }
1864 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1865 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);
1866 break;
1867 }
1868 }
1869 }
1870
1871 Status = EFI_SUCCESS;
1872 if (WaitEvent == NULL) {
1873 do {
1874 Status = CheckAllAPs ();
1875 } while (Status == EFI_NOT_READY);
1876 }
1877
1878 return Status;
1879 }
1880
1881 /**
1882 Worker function to let the caller get one enabled AP to execute a caller-provided
1883 function.
1884
1885 @param[in] Procedure A pointer to the function to be run on
1886 enabled APs of the system.
1887 @param[in] ProcessorNumber The handle number of the AP.
1888 @param[in] WaitEvent The event created by the caller with CreateEvent()
1889 service.
1890 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
1891 APs to return from Procedure, either for
1892 blocking or non-blocking mode.
1893 @param[in] ProcedureArgument The parameter passed into Procedure for
1894 all APs.
1895 @param[out] Finished If AP returns from Procedure before the
1896 timeout expires, its content is set to TRUE.
1897 Otherwise, the value is set to FALSE.
1898
1899 @retval EFI_SUCCESS In blocking mode, specified AP finished before
1900 the timeout expires.
1901 @retval others Failed to Startup AP.
1902
1903 **/
1904 EFI_STATUS
1905 StartupThisAPWorker (
1906 IN EFI_AP_PROCEDURE Procedure,
1907 IN UINTN ProcessorNumber,
1908 IN EFI_EVENT WaitEvent OPTIONAL,
1909 IN UINTN TimeoutInMicroseconds,
1910 IN VOID *ProcedureArgument OPTIONAL,
1911 OUT BOOLEAN *Finished OPTIONAL
1912 )
1913 {
1914 EFI_STATUS Status;
1915 CPU_MP_DATA *CpuMpData;
1916 CPU_AP_DATA *CpuData;
1917 UINTN CallerNumber;
1918
1919 CpuMpData = GetCpuMpData ();
1920
1921 if (Finished != NULL) {
1922 *Finished = FALSE;
1923 }
1924
1925 //
1926 // Check whether caller processor is BSP
1927 //
1928 MpInitLibWhoAmI (&CallerNumber);
1929 if (CallerNumber != CpuMpData->BspNumber) {
1930 return EFI_DEVICE_ERROR;
1931 }
1932
1933 //
1934 // Check whether processor with the handle specified by ProcessorNumber exists
1935 //
1936 if (ProcessorNumber >= CpuMpData->CpuCount) {
1937 return EFI_NOT_FOUND;
1938 }
1939
1940 //
1941 // Check whether specified processor is BSP
1942 //
1943 if (ProcessorNumber == CpuMpData->BspNumber) {
1944 return EFI_INVALID_PARAMETER;
1945 }
1946
1947 //
1948 // Check parameter Procedure
1949 //
1950 if (Procedure == NULL) {
1951 return EFI_INVALID_PARAMETER;
1952 }
1953
1954 //
1955 // Update AP state
1956 //
1957 CheckAndUpdateApsStatus ();
1958
1959 //
1960 // Check whether specified AP is disabled
1961 //
1962 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
1963 return EFI_INVALID_PARAMETER;
1964 }
1965
1966 //
1967 // If WaitEvent is not NULL, execute in non-blocking mode.
1968 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
1969 // CheckAPsStatus() will check completion and timeout periodically.
1970 //
1971 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1972 CpuData->WaitEvent = WaitEvent;
1973 CpuData->Finished = Finished;
1974 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
1975 CpuData->TotalTime = 0;
1976
1977 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);
1978
1979 //
1980 // If WaitEvent is NULL, execute in blocking mode.
1981 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
1982 //
1983 Status = EFI_SUCCESS;
1984 if (WaitEvent == NULL) {
1985 do {
1986 Status = CheckThisAP (ProcessorNumber);
1987 } while (Status == EFI_NOT_READY);
1988 }
1989
1990 return Status;
1991 }
1992
1993 /**
1994 Get pointer to CPU MP Data structure from GUIDed HOB.
1995
1996 @return The pointer to CPU MP Data structure.
1997 **/
1998 CPU_MP_DATA *
1999 GetCpuMpDataFromGuidedHob (
2000 VOID
2001 )
2002 {
2003 EFI_HOB_GUID_TYPE *GuidHob;
2004 VOID *DataInHob;
2005 CPU_MP_DATA *CpuMpData;
2006
2007 CpuMpData = NULL;
2008 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
2009 if (GuidHob != NULL) {
2010 DataInHob = GET_GUID_HOB_DATA (GuidHob);
2011 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
2012 }
2013 return CpuMpData;
2014 }