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