]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Fix function header comments typo
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
CommitLineData
3e8ad6bd
JF
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
93ca4c0f
JF
17EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;\r
18\r
7c3f2a12
JF
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
ad52f25e
JF
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
41be0da5
JF
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
03a1a925
JF
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
3e8ad6bd 237\r
68cb9330
JF
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
9ebcf0f4
JF
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
b8b04307 364\r
8a2d564b
JF
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
fe627769
JF
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
b8b04307
JF
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
03434dff
JF
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
03434dff
JF
516 CpuMpData->InitFlag = ApInitDone;\r
517 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
518 //\r
519 // Wait for all APs finished the initialization\r
520 //\r
521 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
522 CpuPause ();\r
523 }\r
524\r
fe627769
JF
525 if (CpuMpData->X2ApicEnable) {\r
526 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
527 //\r
528 // Wakeup all APs to enable x2APIC mode\r
529 //\r
530 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
531 //\r
532 // Wait for all known APs finished\r
533 //\r
534 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
535 CpuPause ();\r
536 }\r
537 //\r
538 // Enable x2APIC on BSP\r
539 //\r
540 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
541 }\r
542 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
8a2d564b
JF
543 //\r
544 // Sort BSP/Aps by CPU APIC ID in ascending order\r
545 //\r
546 SortApicId (CpuMpData);\r
547\r
03434dff
JF
548 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
549\r
550 return CpuMpData->CpuCount;\r
551}\r
552\r
03a1a925
JF
553/*\r
554 Initialize CPU AP Data when AP is wakeup at the first time.\r
555\r
556 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
557 @param[in] ProcessorNumber The handle number of processor\r
558 @param[in] BistData Processor BIST data\r
559\r
560**/\r
561VOID\r
562InitializeApData (\r
563 IN OUT CPU_MP_DATA *CpuMpData,\r
564 IN UINTN ProcessorNumber,\r
565 IN UINT32 BistData\r
566 )\r
567{\r
568 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
569 CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
570 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
571 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
572 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
573 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
574 //\r
575 // Set x2APIC mode if there are any logical processor reporting\r
576 // an Initial APIC ID of 255 or greater.\r
577 //\r
578 AcquireSpinLock(&CpuMpData->MpLock);\r
579 CpuMpData->X2ApicEnable = TRUE;\r
580 ReleaseSpinLock(&CpuMpData->MpLock);\r
581 }\r
582\r
583 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
584 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
585}\r
586\r
b8b04307
JF
587/**\r
588 This function will be called from AP reset code if BSP uses WakeUpAP.\r
589\r
590 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
591 @param[in] NumApsExecuting Number of current executing AP\r
592**/\r
593VOID\r
594EFIAPI\r
595ApWakeupFunction (\r
596 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
597 IN UINTN NumApsExecuting\r
598 )\r
599{\r
600 CPU_MP_DATA *CpuMpData;\r
601 UINTN ProcessorNumber;\r
602 EFI_AP_PROCEDURE Procedure;\r
603 VOID *Parameter;\r
604 UINT32 BistData;\r
605 volatile UINT32 *ApStartupSignalBuffer;\r
606\r
607 //\r
608 // AP finished assembly code and begin to execute C code\r
609 //\r
610 CpuMpData = ExchangeInfo->CpuMpData;\r
611\r
612 ProgramVirtualWireMode (); \r
613\r
614 while (TRUE) {\r
615 if (CpuMpData->InitFlag == ApInitConfig) {\r
616 //\r
617 // Add CPU number\r
618 //\r
619 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
620 ProcessorNumber = NumApsExecuting;\r
621 //\r
622 // This is first time AP wakeup, get BIST information from AP stack\r
623 //\r
624 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
625 //\r
626 // Do some AP initialize sync\r
627 //\r
628 ApInitializeSync (CpuMpData);\r
629 //\r
630 // Sync BSP's Control registers to APs\r
631 //\r
632 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
633 InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
634 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
635 } else {\r
636 //\r
637 // Execute AP function if AP is ready\r
638 //\r
639 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
640 //\r
641 // Clear AP start-up signal when AP waken up\r
642 //\r
643 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
644 InterlockedCompareExchange32 (\r
645 (UINT32 *) ApStartupSignalBuffer,\r
646 WAKEUP_AP_SIGNAL,\r
647 0\r
648 );\r
649 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
650 //\r
651 // Restore AP's volatile registers saved\r
652 //\r
653 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
654 }\r
655\r
656 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
657 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
658 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
659 if (Procedure != NULL) {\r
660 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
661 //\r
662 // Invoke AP function here\r
663 //\r
664 Procedure (Parameter);\r
41be0da5
JF
665 if (CpuMpData->SwitchBspFlag) {\r
666 //\r
667 // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
668 //\r
669 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
670 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;\r
671 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;\r
672 } else {\r
673 //\r
674 // Re-get the CPU APICID and Initial APICID\r
675 //\r
676 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
677 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
678 }\r
b8b04307
JF
679 }\r
680 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
681 }\r
682 }\r
683\r
684 //\r
685 // AP finished executing C code\r
686 //\r
687 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
688\r
689 //\r
690 // Place AP is specified loop mode\r
691 //\r
692 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
693 //\r
694 // Save AP volatile registers\r
695 //\r
696 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
697 //\r
698 // Place AP in HLT-loop\r
699 //\r
700 while (TRUE) {\r
701 DisableInterrupts ();\r
702 CpuSleep ();\r
703 CpuPause ();\r
704 }\r
705 }\r
706 while (TRUE) {\r
707 DisableInterrupts ();\r
708 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
709 //\r
710 // Place AP in MWAIT-loop\r
711 //\r
712 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
713 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
714 //\r
715 // Check AP start-up signal again.\r
716 // If AP start-up signal is not set, place AP into\r
717 // the specified C-state\r
718 //\r
719 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
720 }\r
721 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
722 //\r
723 // Place AP in Run-loop\r
724 //\r
725 CpuPause ();\r
726 } else {\r
727 ASSERT (FALSE);\r
728 }\r
729\r
730 //\r
731 // If AP start-up signal is written, AP is waken up\r
732 // otherwise place AP in loop again\r
733 //\r
734 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
735 break;\r
736 }\r
737 }\r
738 }\r
739}\r
740\r
96f5920d
JF
741/**\r
742 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
743\r
744 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
745**/\r
746VOID\r
747WaitApWakeup (\r
748 IN volatile UINT32 *ApStartupSignalBuffer\r
749 )\r
750{\r
751 //\r
752 // If AP is waken up, StartupApSignal should be cleared.\r
753 // Otherwise, write StartupApSignal again till AP waken up.\r
754 //\r
755 while (InterlockedCompareExchange32 (\r
756 (UINT32 *) ApStartupSignalBuffer,\r
757 WAKEUP_AP_SIGNAL,\r
758 WAKEUP_AP_SIGNAL\r
759 ) != 0) {\r
760 CpuPause ();\r
761 }\r
762}\r
763\r
7c3f2a12
JF
764/**\r
765 This function will fill the exchange info structure.\r
766\r
767 @param[in] CpuMpData Pointer to CPU MP Data\r
768\r
769**/\r
770VOID\r
771FillExchangeInfoData (\r
772 IN CPU_MP_DATA *CpuMpData\r
773 )\r
774{\r
775 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
776\r
777 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
778 ExchangeInfo->Lock = 0;\r
779 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
780 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
781 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
782 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
783\r
784 ExchangeInfo->CodeSegment = AsmReadCs ();\r
785 ExchangeInfo->DataSegment = AsmReadDs ();\r
786\r
787 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
788\r
789 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
790 ExchangeInfo->NumApsExecuting = 0;\r
791 ExchangeInfo->CpuMpData = CpuMpData;\r
792\r
793 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
794\r
795 //\r
796 // Get the BSP's data of GDT and IDT\r
797 //\r
798 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
799 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
800}\r
801\r
96f5920d
JF
802/**\r
803 This function will be called by BSP to wakeup AP.\r
804\r
805 @param[in] CpuMpData Pointer to CPU MP Data\r
806 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
807 FALSE: Send IPI to AP by ApicId\r
808 @param[in] ProcessorNumber The handle number of specified processor\r
809 @param[in] Procedure The function to be invoked by AP\r
810 @param[in] ProcedureArgument The argument to be passed into AP function\r
811**/\r
812VOID\r
813WakeUpAP (\r
814 IN CPU_MP_DATA *CpuMpData,\r
815 IN BOOLEAN Broadcast,\r
816 IN UINTN ProcessorNumber,\r
817 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
818 IN VOID *ProcedureArgument OPTIONAL\r
819 )\r
820{\r
821 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
822 UINTN Index;\r
823 CPU_AP_DATA *CpuData;\r
824 BOOLEAN ResetVectorRequired;\r
825\r
826 CpuMpData->FinishedCount = 0;\r
827 ResetVectorRequired = FALSE;\r
828\r
829 if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
830 CpuMpData->InitFlag != ApInitDone) {\r
831 ResetVectorRequired = TRUE;\r
832 AllocateResetVector (CpuMpData);\r
833 FillExchangeInfoData (CpuMpData);\r
834 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
835 //\r
836 // Get AP target C-state each time when waking up AP,\r
837 // for it maybe updated by platform again\r
838 //\r
839 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
840 }\r
841\r
842 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
843\r
844 if (Broadcast) {\r
845 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
846 if (Index != CpuMpData->BspNumber) {\r
847 CpuData = &CpuMpData->CpuData[Index];\r
848 CpuData->ApFunction = (UINTN) Procedure;\r
849 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
850 SetApState (CpuData, CpuStateReady);\r
851 if (CpuMpData->InitFlag != ApInitConfig) {\r
852 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
853 }\r
854 }\r
855 }\r
856 if (ResetVectorRequired) {\r
857 //\r
858 // Wakeup all APs\r
859 //\r
860 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
861 }\r
c1192210
JF
862 if (CpuMpData->InitFlag == ApInitConfig) {\r
863 //\r
864 // Wait for all potential APs waken up in one specified period\r
865 //\r
866 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));\r
867 } else {\r
96f5920d
JF
868 //\r
869 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
870 //\r
871 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
872 CpuData = &CpuMpData->CpuData[Index];\r
873 if (Index != CpuMpData->BspNumber) {\r
874 WaitApWakeup (CpuData->StartupApSignal);\r
875 }\r
876 }\r
877 }\r
878 } else {\r
879 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
880 CpuData->ApFunction = (UINTN) Procedure;\r
881 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
882 SetApState (CpuData, CpuStateReady);\r
883 //\r
884 // Wakeup specified AP\r
885 //\r
886 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
887 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
888 if (ResetVectorRequired) {\r
889 SendInitSipiSipi (\r
890 CpuData->ApicId,\r
891 (UINT32) ExchangeInfo->BufferStart\r
892 );\r
893 }\r
894 //\r
895 // Wait specified AP waken up\r
896 //\r
897 WaitApWakeup (CpuData->StartupApSignal);\r
898 }\r
899\r
900 if (ResetVectorRequired) {\r
901 FreeResetVector (CpuMpData);\r
902 }\r
903}\r
904\r
08085f08
JF
905/**\r
906 Calculate timeout value and return the current performance counter value.\r
907\r
908 Calculate the number of performance counter ticks required for a timeout.\r
909 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
910 as infinity.\r
911\r
912 @param[in] TimeoutInMicroseconds Timeout value in microseconds.\r
913 @param[out] CurrentTime Returns the current value of the performance counter.\r
914\r
915 @return Expected time stamp counter for timeout.\r
916 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
917 as infinity.\r
918\r
919**/\r
920UINT64\r
921CalculateTimeout (\r
922 IN UINTN TimeoutInMicroseconds,\r
923 OUT UINT64 *CurrentTime\r
924 )\r
925{\r
926 //\r
927 // Read the current value of the performance counter\r
928 //\r
929 *CurrentTime = GetPerformanceCounter ();\r
930\r
931 //\r
932 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
933 // as infinity.\r
934 //\r
935 if (TimeoutInMicroseconds == 0) {\r
936 return 0;\r
937 }\r
938\r
939 //\r
940 // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
941 // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide\r
942 // it by 1,000,000, to get the number of ticks for the timeout value.\r
943 //\r
944 return DivU64x32 (\r
945 MultU64x64 (\r
946 GetPerformanceCounterProperties (NULL, NULL),\r
947 TimeoutInMicroseconds\r
948 ),\r
949 1000000\r
950 );\r
951}\r
952\r
953/**\r
954 Checks whether timeout expires.\r
955\r
956 Check whether the number of elapsed performance counter ticks required for\r
957 a timeout condition has been reached.\r
958 If Timeout is zero, which means infinity, return value is always FALSE.\r
959\r
960 @param[in, out] PreviousTime On input, the value of the performance counter\r
961 when it was last read.\r
962 On output, the current value of the performance\r
963 counter\r
964 @param[in] TotalTime The total amount of elapsed time in performance\r
965 counter ticks.\r
966 @param[in] Timeout The number of performance counter ticks required\r
967 to reach a timeout condition.\r
968\r
969 @retval TRUE A timeout condition has been reached.\r
970 @retval FALSE A timeout condition has not been reached.\r
971\r
972**/\r
973BOOLEAN\r
974CheckTimeout (\r
975 IN OUT UINT64 *PreviousTime,\r
976 IN UINT64 *TotalTime,\r
977 IN UINT64 Timeout\r
978 )\r
979{\r
980 UINT64 Start;\r
981 UINT64 End;\r
982 UINT64 CurrentTime;\r
983 INT64 Delta;\r
984 INT64 Cycle;\r
985\r
986 if (Timeout == 0) {\r
987 return FALSE;\r
988 }\r
989 GetPerformanceCounterProperties (&Start, &End);\r
990 Cycle = End - Start;\r
991 if (Cycle < 0) {\r
992 Cycle = -Cycle;\r
993 }\r
994 Cycle++;\r
995 CurrentTime = GetPerformanceCounter();\r
996 Delta = (INT64) (CurrentTime - *PreviousTime);\r
997 if (Start > End) {\r
998 Delta = -Delta;\r
999 }\r
1000 if (Delta < 0) {\r
1001 Delta += Cycle;\r
1002 }\r
1003 *TotalTime += Delta;\r
1004 *PreviousTime = CurrentTime;\r
1005 if (*TotalTime > Timeout) {\r
1006 return TRUE;\r
1007 }\r
1008 return FALSE;\r
1009}\r
1010\r
1011/**\r
1012 Reset an AP to Idle state.\r
1013\r
1014 Any task being executed by the AP will be aborted and the AP\r
1015 will be waiting for a new task in Wait-For-SIPI state.\r
1016\r
1017 @param[in] ProcessorNumber The handle number of processor.\r
1018**/\r
1019VOID\r
1020ResetProcessorToIdleState (\r
1021 IN UINTN ProcessorNumber\r
1022 )\r
1023{\r
1024 CPU_MP_DATA *CpuMpData;\r
1025\r
1026 CpuMpData = GetCpuMpData ();\r
1027\r
1028 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);\r
1029\r
1030 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
1031}\r
1032\r
1033/**\r
1034 Searches for the next waiting AP.\r
1035\r
1036 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
1037\r
1038 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.\r
1039\r
1040 @retval EFI_SUCCESS The next waiting AP has been found.\r
1041 @retval EFI_NOT_FOUND No waiting AP exists.\r
1042\r
1043**/\r
1044EFI_STATUS\r
1045GetNextWaitingProcessorNumber (\r
1046 OUT UINTN *NextProcessorNumber\r
1047 )\r
1048{\r
1049 UINTN ProcessorNumber;\r
1050 CPU_MP_DATA *CpuMpData;\r
1051\r
1052 CpuMpData = GetCpuMpData ();\r
1053\r
1054 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1055 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1056 *NextProcessorNumber = ProcessorNumber;\r
1057 return EFI_SUCCESS;\r
1058 }\r
1059 }\r
1060\r
1061 return EFI_NOT_FOUND;\r
1062}\r
1063\r
1064/** Checks status of specified AP.\r
1065\r
1066 This function checks whether the specified AP has finished the task assigned\r
1067 by StartupThisAP(), and whether timeout expires.\r
1068\r
1069 @param[in] ProcessorNumber The handle number of processor.\r
1070\r
1071 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
1072 @retval EFI_TIMEOUT The timeout expires.\r
1073 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
1074**/\r
1075EFI_STATUS\r
1076CheckThisAP (\r
1077 IN UINTN ProcessorNumber\r
1078 )\r
1079{\r
1080 CPU_MP_DATA *CpuMpData;\r
1081 CPU_AP_DATA *CpuData;\r
1082\r
1083 CpuMpData = GetCpuMpData ();\r
1084 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1085\r
1086 //\r
1087 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
1088 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
1089 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
1090 //\r
1091 //\r
1092 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
1093 //\r
1094 if (GetApState(CpuData) == CpuStateFinished) {\r
1095 if (CpuData->Finished != NULL) {\r
1096 *(CpuData->Finished) = TRUE;\r
1097 }\r
1098 SetApState (CpuData, CpuStateIdle);\r
1099 return EFI_SUCCESS;\r
1100 } else {\r
1101 //\r
1102 // If timeout expires for StartupThisAP(), report timeout.\r
1103 //\r
1104 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {\r
1105 if (CpuData->Finished != NULL) {\r
1106 *(CpuData->Finished) = FALSE;\r
1107 }\r
1108 //\r
1109 // Reset failed AP to idle state\r
1110 //\r
1111 ResetProcessorToIdleState (ProcessorNumber);\r
1112\r
1113 return EFI_TIMEOUT;\r
1114 }\r
1115 }\r
1116 return EFI_NOT_READY;\r
1117}\r
1118\r
1119/**\r
1120 Checks status of all APs.\r
1121\r
1122 This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
1123 and whether timeout expires.\r
1124\r
1125 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().\r
1126 @retval EFI_TIMEOUT The timeout expires.\r
1127 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.\r
1128**/\r
1129EFI_STATUS\r
1130CheckAllAPs (\r
1131 VOID\r
1132 )\r
1133{\r
1134 UINTN ProcessorNumber;\r
1135 UINTN NextProcessorNumber;\r
1136 UINTN ListIndex;\r
1137 EFI_STATUS Status;\r
1138 CPU_MP_DATA *CpuMpData;\r
1139 CPU_AP_DATA *CpuData;\r
1140\r
1141 CpuMpData = GetCpuMpData ();\r
1142\r
1143 NextProcessorNumber = 0;\r
1144\r
1145 //\r
1146 // Go through all APs that are responsible for the StartupAllAPs().\r
1147 //\r
1148 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1149 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1150 continue;\r
1151 }\r
1152\r
1153 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1154 //\r
1155 // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
1156 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
1157 // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
1158 //\r
1159 if (GetApState(CpuData) == CpuStateFinished) {\r
1160 CpuMpData->RunningCount ++;\r
1161 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
1162 SetApState(CpuData, CpuStateIdle);\r
1163\r
1164 //\r
1165 // If in Single Thread mode, then search for the next waiting AP for execution.\r
1166 //\r
1167 if (CpuMpData->SingleThread) {\r
1168 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);\r
1169\r
1170 if (!EFI_ERROR (Status)) {\r
1171 WakeUpAP (\r
1172 CpuMpData,\r
1173 FALSE,\r
1174 (UINT32) NextProcessorNumber,\r
1175 CpuMpData->Procedure,\r
1176 CpuMpData->ProcArguments\r
1177 );\r
1178 }\r
1179 }\r
1180 }\r
1181 }\r
1182\r
1183 //\r
1184 // If all APs finish, return EFI_SUCCESS.\r
1185 //\r
1186 if (CpuMpData->RunningCount == CpuMpData->StartCount) {\r
1187 return EFI_SUCCESS;\r
1188 }\r
1189\r
1190 //\r
1191 // If timeout expires, report timeout.\r
1192 //\r
1193 if (CheckTimeout (\r
1194 &CpuMpData->CurrentTime,\r
1195 &CpuMpData->TotalTime,\r
1196 CpuMpData->ExpectedTime)\r
1197 ) {\r
1198 //\r
1199 // If FailedCpuList is not NULL, record all failed APs in it.\r
1200 //\r
1201 if (CpuMpData->FailedCpuList != NULL) {\r
1202 *CpuMpData->FailedCpuList =\r
1203 AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));\r
1204 ASSERT (*CpuMpData->FailedCpuList != NULL);\r
1205 }\r
1206 ListIndex = 0;\r
1207\r
1208 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
1209 //\r
1210 // Check whether this processor is responsible for StartupAllAPs().\r
1211 //\r
1212 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1213 //\r
1214 // Reset failed APs to idle state\r
1215 //\r
1216 ResetProcessorToIdleState (ProcessorNumber);\r
1217 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
1218 if (CpuMpData->FailedCpuList != NULL) {\r
1219 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;\r
1220 }\r
1221 }\r
1222 }\r
1223 if (CpuMpData->FailedCpuList != NULL) {\r
1224 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;\r
1225 }\r
1226 return EFI_TIMEOUT;\r
1227 }\r
1228 return EFI_NOT_READY;\r
1229}\r
1230\r
3e8ad6bd
JF
1231/**\r
1232 MP Initialize Library initialization.\r
1233\r
1234 This service will allocate AP reset vector and wakeup all APs to do APs\r
1235 initialization.\r
1236\r
1237 This service must be invoked before all other MP Initialize Library\r
1238 service are invoked.\r
1239\r
1240 @retval EFI_SUCCESS MP initialization succeeds.\r
1241 @retval Others MP initialization fails.\r
1242\r
1243**/\r
1244EFI_STATUS\r
1245EFIAPI\r
1246MpInitLibInitialize (\r
1247 VOID\r
1248 )\r
1249{\r
6a2ee2bb
JF
1250 CPU_MP_DATA *OldCpuMpData;\r
1251 CPU_INFO_IN_HOB *CpuInfoInHob;\r
e59f8f6b
JF
1252 UINT32 MaxLogicalProcessorNumber;\r
1253 UINT32 ApStackSize;\r
f7f85d83 1254 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e59f8f6b 1255 UINTN BufferSize;\r
9ebcf0f4 1256 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
1257 VOID *MpBuffer;\r
1258 UINTN Buffer;\r
1259 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 1260 UINT8 ApLoopMode;\r
e59f8f6b 1261 UINT8 *MonitorBuffer;\r
03a1a925 1262 UINTN Index;\r
f7f85d83 1263 UINTN ApResetVectorSize;\r
e59f8f6b 1264 UINTN BackupBufferAddr;\r
6a2ee2bb
JF
1265\r
1266 OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
1267 if (OldCpuMpData == NULL) {\r
1268 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
1269 } else {\r
1270 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
1271 }\r
f7f85d83
JF
1272\r
1273 AsmGetAddressMap (&AddressMap);\r
1274 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
e59f8f6b 1275 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
9ebcf0f4
JF
1276 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
1277\r
e59f8f6b
JF
1278 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
1279 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
1280 BufferSize += sizeof (CPU_MP_DATA);\r
1281 BufferSize += ApResetVectorSize;\r
1282 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
1283 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
1284 ASSERT (MpBuffer != NULL);\r
1285 ZeroMem (MpBuffer, BufferSize);\r
1286 Buffer = (UINTN) MpBuffer;\r
1287\r
1288 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
1289 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
1290 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
1291 CpuMpData->Buffer = Buffer;\r
1292 CpuMpData->CpuApStackSize = ApStackSize;\r
1293 CpuMpData->BackupBuffer = BackupBufferAddr;\r
1294 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
d11f10d1 1295 CpuMpData->SaveRestoreFlag = FALSE;\r
e59f8f6b
JF
1296 CpuMpData->WakeupBuffer = (UINTN) -1;\r
1297 CpuMpData->CpuCount = 1;\r
1298 CpuMpData->BspNumber = 0;\r
1299 CpuMpData->WaitEvent = NULL;\r
41be0da5 1300 CpuMpData->SwitchBspFlag = FALSE;\r
e59f8f6b
JF
1301 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
1302 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
1303 InitializeSpinLock(&CpuMpData->MpLock);\r
1304 //\r
68cb9330
JF
1305 // Save BSP's Control registers to APs\r
1306 //\r
1307 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
1308 //\r
03a1a925
JF
1309 // Set BSP basic information\r
1310 //\r
1311 InitializeApData (CpuMpData, 0, 0);\r
1312 //\r
e59f8f6b
JF
1313 // Save assembly code information\r
1314 //\r
1315 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
1316 //\r
1317 // Finally set AP loop mode\r
1318 //\r
1319 CpuMpData->ApLoopMode = ApLoopMode;\r
1320 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
1321 //\r
03a1a925
JF
1322 // Set up APs wakeup signal buffer\r
1323 //\r
1324 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
1325 CpuMpData->CpuData[Index].StartupApSignal =\r
1326 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
1327 }\r
94f63c76
JF
1328 //\r
1329 // Load Microcode on BSP\r
1330 //\r
1331 MicrocodeDetect (CpuMpData);\r
1332 //\r
e59f8f6b
JF
1333 // Store BSP's MTRR setting\r
1334 //\r
1335 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
1336\r
6a2ee2bb
JF
1337 if (OldCpuMpData == NULL) {\r
1338 //\r
1339 // Wakeup all APs and calculate the processor count in system\r
1340 //\r
1341 CollectProcessorCount (CpuMpData);\r
1342 } else {\r
1343 //\r
1344 // APs have been wakeup before, just get the CPU Information\r
1345 // from HOB\r
1346 //\r
1347 CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
1348 CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
1349 CpuMpData->InitFlag = ApInitReconfig;\r
1350 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;\r
1351 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1352 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
1353 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;\r
1354 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;\r
1355 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {\r
1356 CpuMpData->X2ApicEnable = TRUE;\r
1357 }\r
1358 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;\r
1359 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;\r
1360 CpuMpData->CpuData[Index].ApFunction = 0;\r
1361 CopyMem (\r
1362 &CpuMpData->CpuData[Index].VolatileRegisters,\r
1363 &CpuMpData->CpuData[0].VolatileRegisters,\r
1364 sizeof (CPU_VOLATILE_REGISTERS)\r
1365 );\r
1366 }\r
1367 //\r
1368 // Wakeup APs to do some AP initialize sync\r
1369 //\r
1370 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
1371 //\r
1372 // Wait for all APs finished initialization\r
1373 //\r
1374 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
1375 CpuPause ();\r
1376 }\r
1377 CpuMpData->InitFlag = ApInitDone;\r
1378 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1379 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
1380 }\r
1381 }\r
93ca4c0f
JF
1382\r
1383 //\r
1384 // Initialize global data for MP support\r
1385 //\r
1386 InitMpGlobalData (CpuMpData);\r
1387\r
f7f85d83 1388 return EFI_SUCCESS;\r
3e8ad6bd
JF
1389}\r
1390\r
1391/**\r
1392 Gets detailed MP-related information on the requested processor at the\r
1393 instant this call is made. This service may only be called from the BSP.\r
1394\r
1395 @param[in] ProcessorNumber The handle number of processor.\r
1396 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
1397 the requested processor is deposited.\r
1398 @param[out] HealthData Return processor health data.\r
1399\r
1400 @retval EFI_SUCCESS Processor information was returned.\r
1401 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1402 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
1403 @retval EFI_NOT_FOUND The processor with the handle specified by\r
1404 ProcessorNumber does not exist in the platform.\r
1405 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1406\r
1407**/\r
1408EFI_STATUS\r
1409EFIAPI\r
1410MpInitLibGetProcessorInfo (\r
1411 IN UINTN ProcessorNumber,\r
1412 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
1413 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
1414 )\r
1415{\r
ad52f25e
JF
1416 CPU_MP_DATA *CpuMpData;\r
1417 UINTN CallerNumber;\r
1418\r
1419 CpuMpData = GetCpuMpData ();\r
1420\r
1421 //\r
1422 // Check whether caller processor is BSP\r
1423 //\r
1424 MpInitLibWhoAmI (&CallerNumber);\r
1425 if (CallerNumber != CpuMpData->BspNumber) {\r
1426 return EFI_DEVICE_ERROR;\r
1427 }\r
1428\r
1429 if (ProcessorInfoBuffer == NULL) {\r
1430 return EFI_INVALID_PARAMETER;\r
1431 }\r
1432\r
1433 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1434 return EFI_NOT_FOUND;\r
1435 }\r
1436\r
1437 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;\r
1438 ProcessorInfoBuffer->StatusFlag = 0;\r
1439 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1440 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
1441 }\r
1442 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {\r
1443 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
1444 }\r
1445 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
1446 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;\r
1447 } else {\r
1448 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
1449 }\r
1450\r
1451 //\r
1452 // Get processor location information\r
1453 //\r
1454 ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);\r
1455\r
1456 if (HealthData != NULL) {\r
1457 HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;\r
1458 }\r
1459\r
1460 return EFI_SUCCESS;\r
3e8ad6bd 1461}\r
ad52f25e 1462\r
41be0da5
JF
1463/**\r
1464 Worker function to switch the requested AP to be the BSP from that point onward.\r
1465\r
1466 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.\r
1467 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
1468 enabled AP. Otherwise, it will be disabled.\r
1469\r
1470 @retval EFI_SUCCESS BSP successfully switched.\r
1471 @retval others Failed to switch BSP. \r
1472\r
1473**/\r
1474EFI_STATUS\r
1475SwitchBSPWorker (\r
1476 IN UINTN ProcessorNumber,\r
1477 IN BOOLEAN EnableOldBSP\r
1478 )\r
1479{\r
1480 CPU_MP_DATA *CpuMpData;\r
1481 UINTN CallerNumber;\r
1482 CPU_STATE State;\r
1483 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
1484\r
1485 CpuMpData = GetCpuMpData ();\r
1486\r
1487 //\r
1488 // Check whether caller processor is BSP\r
1489 //\r
1490 MpInitLibWhoAmI (&CallerNumber);\r
1491 if (CallerNumber != CpuMpData->BspNumber) {\r
1492 return EFI_SUCCESS;\r
1493 }\r
1494\r
1495 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1496 return EFI_NOT_FOUND;\r
1497 }\r
1498\r
1499 //\r
1500 // Check whether specified AP is disabled\r
1501 //\r
1502 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);\r
1503 if (State == CpuStateDisabled) {\r
1504 return EFI_INVALID_PARAMETER;\r
1505 }\r
1506\r
1507 //\r
1508 // Check whether ProcessorNumber specifies the current BSP\r
1509 //\r
1510 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1511 return EFI_INVALID_PARAMETER;\r
1512 }\r
1513\r
1514 //\r
1515 // Check whether specified AP is busy\r
1516 //\r
1517 if (State == CpuStateBusy) {\r
1518 return EFI_NOT_READY;\r
1519 }\r
1520\r
1521 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;\r
1522 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;\r
1523 CpuMpData->SwitchBspFlag = TRUE;\r
1524\r
1525 //\r
1526 // Clear the BSP bit of MSR_IA32_APIC_BASE\r
1527 //\r
1528 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
1529 ApicBaseMsr.Bits.BSP = 0;\r
1530 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
1531\r
1532 //\r
1533 // Need to wakeUp AP (future BSP).\r
1534 //\r
1535 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);\r
1536\r
1537 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);\r
1538\r
1539 //\r
1540 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP\r
1541 //\r
1542 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
1543 ApicBaseMsr.Bits.BSP = 1;\r
1544 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
1545\r
1546 //\r
1547 // Wait for old BSP finished AP task\r
1548 //\r
1549 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
1550 CpuPause ();\r
1551 }\r
1552\r
1553 CpuMpData->SwitchBspFlag = FALSE;\r
1554 //\r
1555 // Set old BSP enable state\r
1556 //\r
1557 if (!EnableOldBSP) {\r
1558 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);\r
1559 }\r
1560 //\r
1561 // Save new BSP number\r
1562 //\r
1563 CpuMpData->BspNumber = (UINT32) ProcessorNumber;\r
1564\r
1565 return EFI_SUCCESS;\r
1566}\r
ad52f25e 1567\r
e37109bc
JF
1568/**\r
1569 Worker function to let the caller enable or disable an AP from this point onward.\r
1570 This service may only be called from the BSP.\r
1571\r
1572 @param[in] ProcessorNumber The handle number of AP.\r
1573 @param[in] EnableAP Specifies the new state for the processor for\r
1574 enabled, FALSE for disabled.\r
1575 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
1576 the new health status of the AP.\r
1577\r
1578 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
1579 @retval others Failed to Enable/Disable AP.\r
1580\r
1581**/\r
1582EFI_STATUS\r
1583EnableDisableApWorker (\r
1584 IN UINTN ProcessorNumber,\r
1585 IN BOOLEAN EnableAP,\r
1586 IN UINT32 *HealthFlag OPTIONAL\r
1587 )\r
1588{\r
1589 CPU_MP_DATA *CpuMpData;\r
1590 UINTN CallerNumber;\r
1591\r
1592 CpuMpData = GetCpuMpData ();\r
1593\r
1594 //\r
1595 // Check whether caller processor is BSP\r
1596 //\r
1597 MpInitLibWhoAmI (&CallerNumber);\r
1598 if (CallerNumber != CpuMpData->BspNumber) {\r
1599 return EFI_DEVICE_ERROR;\r
1600 }\r
1601\r
1602 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1603 return EFI_INVALID_PARAMETER;\r
1604 }\r
1605\r
1606 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1607 return EFI_NOT_FOUND;\r
1608 }\r
1609\r
1610 if (!EnableAP) {\r
1611 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);\r
1612 } else {\r
1613 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
1614 }\r
1615\r
1616 if (HealthFlag != NULL) {\r
1617 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =\r
1618 (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);\r
1619 }\r
1620\r
1621 return EFI_SUCCESS;\r
1622}\r
1623\r
3e8ad6bd
JF
1624/**\r
1625 This return the handle number for the calling processor. This service may be\r
1626 called from the BSP and APs.\r
1627\r
1628 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
1629 The range is from 0 to the total number of\r
1630 logical processors minus 1. The total number of\r
1631 logical processors can be retrieved by\r
1632 MpInitLibGetNumberOfProcessors().\r
1633\r
1634 @retval EFI_SUCCESS The current processor handle number was returned\r
1635 in ProcessorNumber.\r
1636 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
1637 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1638\r
1639**/\r
1640EFI_STATUS\r
1641EFIAPI\r
1642MpInitLibWhoAmI (\r
1643 OUT UINTN *ProcessorNumber\r
1644 )\r
1645{\r
5c9e0997
JF
1646 CPU_MP_DATA *CpuMpData;\r
1647\r
1648 if (ProcessorNumber == NULL) {\r
1649 return EFI_INVALID_PARAMETER;\r
1650 }\r
1651\r
1652 CpuMpData = GetCpuMpData ();\r
1653\r
1654 return GetProcessorNumber (CpuMpData, ProcessorNumber);\r
3e8ad6bd 1655}\r
809213a6 1656\r
3e8ad6bd
JF
1657/**\r
1658 Retrieves the number of logical processor in the platform and the number of\r
1659 those logical processors that are enabled on this boot. This service may only\r
1660 be called from the BSP.\r
1661\r
1662 @param[out] NumberOfProcessors Pointer to the total number of logical\r
1663 processors in the system, including the BSP\r
1664 and disabled APs.\r
1665 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
1666 processors that exist in system, including\r
1667 the BSP.\r
1668\r
1669 @retval EFI_SUCCESS The number of logical processors and enabled\r
1670 logical processors was retrieved.\r
1671 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1672 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
1673 is NULL.\r
1674 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1675\r
1676**/\r
1677EFI_STATUS\r
1678EFIAPI\r
1679MpInitLibGetNumberOfProcessors (\r
1680 OUT UINTN *NumberOfProcessors, OPTIONAL\r
1681 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
1682 )\r
1683{\r
809213a6
JF
1684 CPU_MP_DATA *CpuMpData;\r
1685 UINTN CallerNumber;\r
1686 UINTN ProcessorNumber;\r
1687 UINTN EnabledProcessorNumber;\r
1688 UINTN Index;\r
1689\r
1690 CpuMpData = GetCpuMpData ();\r
1691\r
1692 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {\r
1693 return EFI_INVALID_PARAMETER;\r
1694 }\r
1695\r
1696 //\r
1697 // Check whether caller processor is BSP\r
1698 //\r
1699 MpInitLibWhoAmI (&CallerNumber);\r
1700 if (CallerNumber != CpuMpData->BspNumber) {\r
1701 return EFI_DEVICE_ERROR;\r
1702 }\r
1703\r
1704 ProcessorNumber = CpuMpData->CpuCount;\r
1705 EnabledProcessorNumber = 0;\r
1706 for (Index = 0; Index < ProcessorNumber; Index++) {\r
1707 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {\r
1708 EnabledProcessorNumber ++;\r
1709 }\r
1710 }\r
1711\r
1712 if (NumberOfProcessors != NULL) {\r
1713 *NumberOfProcessors = ProcessorNumber;\r
1714 }\r
1715 if (NumberOfEnabledProcessors != NULL) {\r
1716 *NumberOfEnabledProcessors = EnabledProcessorNumber;\r
1717 }\r
1718\r
1719 return EFI_SUCCESS;\r
3e8ad6bd 1720}\r
6a2ee2bb 1721\r
809213a6 1722\r
86efe976
JF
1723/**\r
1724 Worker function to execute a caller provided function on all enabled APs.\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] SingleThread If TRUE, then all the enabled APs execute\r
1729 the function specified by Procedure one by\r
1730 one, in ascending order of processor handle\r
1731 number. If FALSE, then all the enabled APs\r
1732 execute the function specified by Procedure\r
1733 simultaneously.\r
1734 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
1735 service.\r
1736 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for\r
1737 APs to return from Procedure, either for\r
1738 blocking or non-blocking mode.\r
1739 @param[in] ProcedureArgument The parameter passed into Procedure for\r
1740 all APs.\r
1741 @param[out] FailedCpuList If all APs finish successfully, then its\r
1742 content is set to NULL. If not all APs\r
1743 finish before timeout expires, then its\r
1744 content is set to address of the buffer\r
1745 holding handle numbers of the failed APs.\r
1746\r
1747 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
1748 the timeout expired.\r
1749 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
1750 to all enabled APs.\r
1751 @retval others Failed to Startup all APs.\r
1752\r
1753**/\r
1754EFI_STATUS\r
1755StartupAllAPsWorker (\r
1756 IN EFI_AP_PROCEDURE Procedure,\r
1757 IN BOOLEAN SingleThread,\r
1758 IN EFI_EVENT WaitEvent OPTIONAL,\r
1759 IN UINTN TimeoutInMicroseconds,\r
1760 IN VOID *ProcedureArgument OPTIONAL,\r
1761 OUT UINTN **FailedCpuList OPTIONAL\r
1762 )\r
1763{\r
1764 EFI_STATUS Status;\r
1765 CPU_MP_DATA *CpuMpData;\r
1766 UINTN ProcessorCount;\r
1767 UINTN ProcessorNumber;\r
1768 UINTN CallerNumber;\r
1769 CPU_AP_DATA *CpuData;\r
1770 BOOLEAN HasEnabledAp;\r
1771 CPU_STATE ApState;\r
1772\r
1773 CpuMpData = GetCpuMpData ();\r
1774\r
1775 if (FailedCpuList != NULL) {\r
1776 *FailedCpuList = NULL;\r
1777 }\r
1778\r
1779 if (CpuMpData->CpuCount == 1) {\r
1780 return EFI_NOT_STARTED;\r
1781 }\r
1782\r
1783 if (Procedure == NULL) {\r
1784 return EFI_INVALID_PARAMETER;\r
1785 }\r
1786\r
1787 //\r
1788 // Check whether caller processor is BSP\r
1789 //\r
1790 MpInitLibWhoAmI (&CallerNumber);\r
1791 if (CallerNumber != CpuMpData->BspNumber) {\r
1792 return EFI_DEVICE_ERROR;\r
1793 }\r
1794\r
1795 //\r
1796 // Update AP state\r
1797 //\r
1798 CheckAndUpdateApsStatus ();\r
1799\r
1800 ProcessorCount = CpuMpData->CpuCount;\r
1801 HasEnabledAp = FALSE;\r
1802 //\r
1803 // Check whether all enabled APs are idle.\r
1804 // If any enabled AP is not idle, return EFI_NOT_READY.\r
1805 //\r
1806 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
1807 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1808 if (ProcessorNumber != CpuMpData->BspNumber) {\r
1809 ApState = GetApState (CpuData);\r
1810 if (ApState != CpuStateDisabled) {\r
1811 HasEnabledAp = TRUE;\r
1812 if (ApState != CpuStateIdle) {\r
1813 //\r
1814 // If any enabled APs are busy, return EFI_NOT_READY.\r
1815 //\r
1816 return EFI_NOT_READY;\r
1817 }\r
1818 }\r
1819 }\r
1820 }\r
1821\r
1822 if (!HasEnabledAp) {\r
1823 //\r
1824 // If no enabled AP exists, return EFI_NOT_STARTED.\r
1825 //\r
1826 return EFI_NOT_STARTED;\r
1827 }\r
1828\r
1829 CpuMpData->StartCount = 0;\r
1830 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
1831 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1832 CpuData->Waiting = FALSE;\r
1833 if (ProcessorNumber != CpuMpData->BspNumber) {\r
1834 if (CpuData->State == CpuStateIdle) {\r
1835 //\r
1836 // Mark this processor as responsible for current calling.\r
1837 //\r
1838 CpuData->Waiting = TRUE;\r
1839 CpuMpData->StartCount++;\r
1840 }\r
1841 }\r
1842 }\r
1843\r
1844 CpuMpData->Procedure = Procedure;\r
1845 CpuMpData->ProcArguments = ProcedureArgument;\r
1846 CpuMpData->SingleThread = SingleThread;\r
1847 CpuMpData->FinishedCount = 0;\r
1848 CpuMpData->RunningCount = 0;\r
1849 CpuMpData->FailedCpuList = FailedCpuList;\r
1850 CpuMpData->ExpectedTime = CalculateTimeout (\r
1851 TimeoutInMicroseconds,\r
1852 &CpuMpData->CurrentTime\r
1853 );\r
1854 CpuMpData->TotalTime = 0;\r
1855 CpuMpData->WaitEvent = WaitEvent;\r
1856\r
1857 if (!SingleThread) {\r
1858 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument);\r
1859 } else {\r
1860 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
1861 if (ProcessorNumber == CallerNumber) {\r
1862 continue;\r
1863 }\r
1864 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
1865 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
1866 break;\r
1867 }\r
1868 }\r
1869 }\r
1870\r
1871 Status = EFI_SUCCESS;\r
1872 if (WaitEvent == NULL) {\r
1873 do {\r
1874 Status = CheckAllAPs ();\r
1875 } while (Status == EFI_NOT_READY);\r
1876 }\r
1877\r
1878 return Status;\r
1879}\r
1880\r
20ae5774
JF
1881/**\r
1882 Worker function to let the caller get one enabled AP to execute a caller-provided\r
1883 function.\r
1884\r
1885 @param[in] Procedure A pointer to the function to be run on\r
1886 enabled APs of the system.\r
1887 @param[in] ProcessorNumber The handle number of the AP.\r
1888 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
1889 service.\r
1890 @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for\r
1891 APs to return from Procedure, either for\r
1892 blocking or non-blocking mode.\r
1893 @param[in] ProcedureArgument The parameter passed into Procedure for\r
1894 all APs.\r
1895 @param[out] Finished If AP returns from Procedure before the\r
1896 timeout expires, its content is set to TRUE.\r
1897 Otherwise, the value is set to FALSE.\r
1898\r
1899 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
1900 the timeout expires.\r
1901 @retval others Failed to Startup AP.\r
1902\r
1903**/\r
1904EFI_STATUS\r
1905StartupThisAPWorker (\r
1906 IN EFI_AP_PROCEDURE Procedure,\r
1907 IN UINTN ProcessorNumber,\r
1908 IN EFI_EVENT WaitEvent OPTIONAL,\r
1909 IN UINTN TimeoutInMicroseconds,\r
1910 IN VOID *ProcedureArgument OPTIONAL,\r
1911 OUT BOOLEAN *Finished OPTIONAL\r
1912 )\r
1913{\r
1914 EFI_STATUS Status;\r
1915 CPU_MP_DATA *CpuMpData;\r
1916 CPU_AP_DATA *CpuData;\r
1917 UINTN CallerNumber;\r
1918\r
1919 CpuMpData = GetCpuMpData ();\r
1920\r
1921 if (Finished != NULL) {\r
1922 *Finished = FALSE;\r
1923 }\r
1924\r
1925 //\r
1926 // Check whether caller processor is BSP\r
1927 //\r
1928 MpInitLibWhoAmI (&CallerNumber);\r
1929 if (CallerNumber != CpuMpData->BspNumber) {\r
1930 return EFI_DEVICE_ERROR;\r
1931 }\r
1932\r
1933 //\r
1934 // Check whether processor with the handle specified by ProcessorNumber exists\r
1935 //\r
1936 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1937 return EFI_NOT_FOUND;\r
1938 }\r
1939\r
1940 //\r
1941 // Check whether specified processor is BSP\r
1942 //\r
1943 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1944 return EFI_INVALID_PARAMETER;\r
1945 }\r
1946\r
1947 //\r
1948 // Check parameter Procedure\r
1949 //\r
1950 if (Procedure == NULL) {\r
1951 return EFI_INVALID_PARAMETER;\r
1952 }\r
1953\r
1954 //\r
1955 // Update AP state\r
1956 //\r
1957 CheckAndUpdateApsStatus ();\r
1958\r
1959 //\r
1960 // Check whether specified AP is disabled\r
1961 //\r
1962 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
1963 return EFI_INVALID_PARAMETER;\r
1964 }\r
1965\r
1966 //\r
1967 // If WaitEvent is not NULL, execute in non-blocking mode.\r
1968 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
1969 // CheckAPsStatus() will check completion and timeout periodically.\r
1970 //\r
1971 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
1972 CpuData->WaitEvent = WaitEvent;\r
1973 CpuData->Finished = Finished;\r
1974 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
1975 CpuData->TotalTime = 0;\r
1976\r
1977 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
1978\r
1979 //\r
1980 // If WaitEvent is NULL, execute in blocking mode.\r
1981 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.\r
1982 //\r
1983 Status = EFI_SUCCESS;\r
1984 if (WaitEvent == NULL) {\r
1985 do {\r
1986 Status = CheckThisAP (ProcessorNumber);\r
1987 } while (Status == EFI_NOT_READY);\r
1988 }\r
1989\r
1990 return Status;\r
1991}\r
1992\r
93ca4c0f
JF
1993/**\r
1994 Get pointer to CPU MP Data structure from GUIDed HOB.\r
1995\r
1996 @return The pointer to CPU MP Data structure.\r
1997**/\r
1998CPU_MP_DATA *\r
1999GetCpuMpDataFromGuidedHob (\r
2000 VOID\r
2001 )\r
2002{\r
2003 EFI_HOB_GUID_TYPE *GuidHob;\r
2004 VOID *DataInHob;\r
2005 CPU_MP_DATA *CpuMpData;\r
2006\r
2007 CpuMpData = NULL;\r
2008 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
2009 if (GuidHob != NULL) {\r
2010 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
2011 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
2012 }\r
2013 return CpuMpData;\r
2014}\r