]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Implementation of MpInitLibGetProcessorInfo()
[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
03a1a925
JF
186/**\r
187 Get the Application Processors state.\r
188\r
189 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
190\r
191 @return The AP status\r
192**/\r
193CPU_STATE\r
194GetApState (\r
195 IN CPU_AP_DATA *CpuData\r
196 )\r
197{\r
198 return CpuData->State;\r
199}\r
200\r
201/**\r
202 Set the Application Processors state.\r
203\r
204 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
205 @param[in] State The AP status\r
206**/\r
207VOID\r
208SetApState (\r
209 IN CPU_AP_DATA *CpuData,\r
210 IN CPU_STATE State\r
211 )\r
212{\r
213 AcquireSpinLock (&CpuData->ApLock);\r
214 CpuData->State = State;\r
215 ReleaseSpinLock (&CpuData->ApLock);\r
216}\r
3e8ad6bd 217\r
68cb9330
JF
218/**\r
219 Save the volatile registers required to be restored following INIT IPI.\r
220\r
221 @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
222**/\r
223VOID\r
224SaveVolatileRegisters (\r
225 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
226 )\r
227{\r
228 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
229\r
230 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
231 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
232 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
233\r
234 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
235 if (VersionInfoEdx.Bits.DE != 0) {\r
236 //\r
237 // If processor supports Debugging Extensions feature\r
238 // by CPUID.[EAX=01H]:EDX.BIT2\r
239 //\r
240 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
241 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
242 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
243 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
244 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
245 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
246 }\r
247}\r
248\r
249/**\r
250 Restore the volatile registers following INIT IPI.\r
251\r
252 @param[in] VolatileRegisters Pointer to volatile resisters\r
253 @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
254 FALSE: Do not restore DRx\r
255**/\r
256VOID\r
257RestoreVolatileRegisters (\r
258 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
259 IN BOOLEAN IsRestoreDr\r
260 )\r
261{\r
262 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
263\r
264 AsmWriteCr0 (VolatileRegisters->Cr0);\r
265 AsmWriteCr3 (VolatileRegisters->Cr3);\r
266 AsmWriteCr4 (VolatileRegisters->Cr4);\r
267\r
268 if (IsRestoreDr) {\r
269 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
270 if (VersionInfoEdx.Bits.DE != 0) {\r
271 //\r
272 // If processor supports Debugging Extensions feature\r
273 // by CPUID.[EAX=01H]:EDX.BIT2\r
274 //\r
275 AsmWriteDr0 (VolatileRegisters->Dr0);\r
276 AsmWriteDr1 (VolatileRegisters->Dr1);\r
277 AsmWriteDr2 (VolatileRegisters->Dr2);\r
278 AsmWriteDr3 (VolatileRegisters->Dr3);\r
279 AsmWriteDr6 (VolatileRegisters->Dr6);\r
280 AsmWriteDr7 (VolatileRegisters->Dr7);\r
281 }\r
282 }\r
283}\r
284\r
9ebcf0f4
JF
285/**\r
286 Detect whether Mwait-monitor feature is supported.\r
287\r
288 @retval TRUE Mwait-monitor feature is supported.\r
289 @retval FALSE Mwait-monitor feature is not supported.\r
290**/\r
291BOOLEAN\r
292IsMwaitSupport (\r
293 VOID\r
294 )\r
295{\r
296 CPUID_VERSION_INFO_ECX VersionInfoEcx;\r
297\r
298 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);\r
299 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;\r
300}\r
301\r
302/**\r
303 Get AP loop mode.\r
304\r
305 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.\r
306\r
307 @return The AP loop mode.\r
308**/\r
309UINT8\r
310GetApLoopMode (\r
311 OUT UINT32 *MonitorFilterSize\r
312 )\r
313{\r
314 UINT8 ApLoopMode;\r
315 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;\r
316\r
317 ASSERT (MonitorFilterSize != NULL);\r
318\r
319 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
320 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
321 if (ApLoopMode == ApInMwaitLoop) {\r
322 if (!IsMwaitSupport ()) {\r
323 //\r
324 // If processor does not support MONITOR/MWAIT feature,\r
325 // force AP in Hlt-loop mode\r
326 //\r
327 ApLoopMode = ApInHltLoop;\r
328 }\r
329 }\r
330\r
331 if (ApLoopMode != ApInMwaitLoop) {\r
332 *MonitorFilterSize = sizeof (UINT32);\r
333 } else {\r
334 //\r
335 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
336 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
337 //\r
338 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
339 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
340 }\r
341\r
342 return ApLoopMode;\r
343}\r
b8b04307 344\r
8a2d564b
JF
345/**\r
346 Sort the APIC ID of all processors.\r
347\r
348 This function sorts the APIC ID of all processors so that processor number is\r
349 assigned in the ascending order of APIC ID which eases MP debugging.\r
350\r
351 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
352**/\r
353VOID\r
354SortApicId (\r
355 IN CPU_MP_DATA *CpuMpData\r
356 )\r
357{\r
358 UINTN Index1;\r
359 UINTN Index2;\r
360 UINTN Index3;\r
361 UINT32 ApicId;\r
362 CPU_AP_DATA CpuData;\r
363 UINT32 ApCount;\r
364 CPU_INFO_IN_HOB *CpuInfoInHob;\r
365\r
366 ApCount = CpuMpData->CpuCount - 1;\r
367\r
368 if (ApCount != 0) {\r
369 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
370 Index3 = Index1;\r
371 //\r
372 // Sort key is the hardware default APIC ID\r
373 //\r
374 ApicId = CpuMpData->CpuData[Index1].ApicId;\r
375 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
376 if (ApicId > CpuMpData->CpuData[Index2].ApicId) {\r
377 Index3 = Index2;\r
378 ApicId = CpuMpData->CpuData[Index2].ApicId;\r
379 }\r
380 }\r
381 if (Index3 != Index1) {\r
382 CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));\r
383 CopyMem (\r
384 &CpuMpData->CpuData[Index3],\r
385 &CpuMpData->CpuData[Index1],\r
386 sizeof (CPU_AP_DATA)\r
387 );\r
388 CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));\r
389 }\r
390 }\r
391\r
392 //\r
393 // Get the processor number for the BSP\r
394 //\r
395 ApicId = GetInitialApicId ();\r
396 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
397 if (CpuMpData->CpuData[Index1].ApicId == ApicId) {\r
398 CpuMpData->BspNumber = (UINT32) Index1;\r
399 break;\r
400 }\r
401 }\r
402\r
403 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
404 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
405 CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;\r
406 CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;\r
407 CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;\r
408 }\r
409 }\r
410}\r
411\r
fe627769
JF
412/**\r
413 Enable x2APIC mode on APs.\r
414\r
415 @param[in, out] Buffer Pointer to private data buffer.\r
416**/\r
417VOID\r
418EFIAPI\r
419ApFuncEnableX2Apic (\r
420 IN OUT VOID *Buffer\r
421 )\r
422{\r
423 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
424}\r
425\r
b8b04307
JF
426/**\r
427 Do sync on APs.\r
428\r
429 @param[in, out] Buffer Pointer to private data buffer.\r
430**/\r
431VOID\r
432EFIAPI\r
433ApInitializeSync (\r
434 IN OUT VOID *Buffer\r
435 )\r
436{\r
437 CPU_MP_DATA *CpuMpData;\r
438\r
439 CpuMpData = (CPU_MP_DATA *) Buffer;\r
440 //\r
441 // Sync BSP's MTRR table to AP\r
442 //\r
443 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
444 //\r
445 // Load microcode on AP\r
446 //\r
447 MicrocodeDetect (CpuMpData);\r
448}\r
449\r
450/**\r
451 Find the current Processor number by APIC ID.\r
452\r
453 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
454 @param[in] ProcessorNumber Return the pocessor number found\r
455\r
456 @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
457 @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
458**/\r
459EFI_STATUS\r
460GetProcessorNumber (\r
461 IN CPU_MP_DATA *CpuMpData,\r
462 OUT UINTN *ProcessorNumber\r
463 )\r
464{\r
465 UINTN TotalProcessorNumber;\r
466 UINTN Index;\r
467\r
468 TotalProcessorNumber = CpuMpData->CpuCount;\r
469 for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
470 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {\r
471 *ProcessorNumber = Index;\r
472 return EFI_SUCCESS;\r
473 }\r
474 }\r
475 return EFI_NOT_FOUND;\r
476}\r
477\r
03434dff
JF
478/**\r
479 This function will get CPU count in the system.\r
480\r
481 @param[in] CpuMpData Pointer to PEI CPU MP Data\r
482\r
483 @return CPU count detected\r
484**/\r
485UINTN\r
486CollectProcessorCount (\r
487 IN CPU_MP_DATA *CpuMpData\r
488 )\r
489{\r
490 //\r
491 // Send 1st broadcast IPI to APs to wakeup APs\r
492 //\r
493 CpuMpData->InitFlag = ApInitConfig;\r
494 CpuMpData->X2ApicEnable = FALSE;\r
495 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
496 //\r
497 // Wait for AP task to complete and then exit.\r
498 //\r
499 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));\r
500 CpuMpData->InitFlag = ApInitDone;\r
501 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
502 //\r
503 // Wait for all APs finished the initialization\r
504 //\r
505 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
506 CpuPause ();\r
507 }\r
508\r
fe627769
JF
509 if (CpuMpData->X2ApicEnable) {\r
510 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
511 //\r
512 // Wakeup all APs to enable x2APIC mode\r
513 //\r
514 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
515 //\r
516 // Wait for all known APs finished\r
517 //\r
518 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
519 CpuPause ();\r
520 }\r
521 //\r
522 // Enable x2APIC on BSP\r
523 //\r
524 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
525 }\r
526 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
8a2d564b
JF
527 //\r
528 // Sort BSP/Aps by CPU APIC ID in ascending order\r
529 //\r
530 SortApicId (CpuMpData);\r
531\r
03434dff
JF
532 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
533\r
534 return CpuMpData->CpuCount;\r
535}\r
536\r
03a1a925
JF
537/*\r
538 Initialize CPU AP Data when AP is wakeup at the first time.\r
539\r
540 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
541 @param[in] ProcessorNumber The handle number of processor\r
542 @param[in] BistData Processor BIST data\r
543\r
544**/\r
545VOID\r
546InitializeApData (\r
547 IN OUT CPU_MP_DATA *CpuMpData,\r
548 IN UINTN ProcessorNumber,\r
549 IN UINT32 BistData\r
550 )\r
551{\r
552 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
553 CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
554 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
555 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
556 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
557 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
558 //\r
559 // Set x2APIC mode if there are any logical processor reporting\r
560 // an Initial APIC ID of 255 or greater.\r
561 //\r
562 AcquireSpinLock(&CpuMpData->MpLock);\r
563 CpuMpData->X2ApicEnable = TRUE;\r
564 ReleaseSpinLock(&CpuMpData->MpLock);\r
565 }\r
566\r
567 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
568 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
569}\r
570\r
b8b04307
JF
571/**\r
572 This function will be called from AP reset code if BSP uses WakeUpAP.\r
573\r
574 @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
575 @param[in] NumApsExecuting Number of current executing AP\r
576**/\r
577VOID\r
578EFIAPI\r
579ApWakeupFunction (\r
580 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
581 IN UINTN NumApsExecuting\r
582 )\r
583{\r
584 CPU_MP_DATA *CpuMpData;\r
585 UINTN ProcessorNumber;\r
586 EFI_AP_PROCEDURE Procedure;\r
587 VOID *Parameter;\r
588 UINT32 BistData;\r
589 volatile UINT32 *ApStartupSignalBuffer;\r
590\r
591 //\r
592 // AP finished assembly code and begin to execute C code\r
593 //\r
594 CpuMpData = ExchangeInfo->CpuMpData;\r
595\r
596 ProgramVirtualWireMode (); \r
597\r
598 while (TRUE) {\r
599 if (CpuMpData->InitFlag == ApInitConfig) {\r
600 //\r
601 // Add CPU number\r
602 //\r
603 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
604 ProcessorNumber = NumApsExecuting;\r
605 //\r
606 // This is first time AP wakeup, get BIST information from AP stack\r
607 //\r
608 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
609 //\r
610 // Do some AP initialize sync\r
611 //\r
612 ApInitializeSync (CpuMpData);\r
613 //\r
614 // Sync BSP's Control registers to APs\r
615 //\r
616 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
617 InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
618 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
619 } else {\r
620 //\r
621 // Execute AP function if AP is ready\r
622 //\r
623 GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
624 //\r
625 // Clear AP start-up signal when AP waken up\r
626 //\r
627 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
628 InterlockedCompareExchange32 (\r
629 (UINT32 *) ApStartupSignalBuffer,\r
630 WAKEUP_AP_SIGNAL,\r
631 0\r
632 );\r
633 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
634 //\r
635 // Restore AP's volatile registers saved\r
636 //\r
637 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
638 }\r
639\r
640 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
641 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
642 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
643 if (Procedure != NULL) {\r
644 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
645 //\r
646 // Invoke AP function here\r
647 //\r
648 Procedure (Parameter);\r
649 //\r
650 // Re-get the CPU APICID and Initial APICID\r
651 //\r
652 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
653 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
654 }\r
655 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
656 }\r
657 }\r
658\r
659 //\r
660 // AP finished executing C code\r
661 //\r
662 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
663\r
664 //\r
665 // Place AP is specified loop mode\r
666 //\r
667 if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
668 //\r
669 // Save AP volatile registers\r
670 //\r
671 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
672 //\r
673 // Place AP in HLT-loop\r
674 //\r
675 while (TRUE) {\r
676 DisableInterrupts ();\r
677 CpuSleep ();\r
678 CpuPause ();\r
679 }\r
680 }\r
681 while (TRUE) {\r
682 DisableInterrupts ();\r
683 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
684 //\r
685 // Place AP in MWAIT-loop\r
686 //\r
687 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
688 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
689 //\r
690 // Check AP start-up signal again.\r
691 // If AP start-up signal is not set, place AP into\r
692 // the specified C-state\r
693 //\r
694 AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
695 }\r
696 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
697 //\r
698 // Place AP in Run-loop\r
699 //\r
700 CpuPause ();\r
701 } else {\r
702 ASSERT (FALSE);\r
703 }\r
704\r
705 //\r
706 // If AP start-up signal is written, AP is waken up\r
707 // otherwise place AP in loop again\r
708 //\r
709 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
710 break;\r
711 }\r
712 }\r
713 }\r
714}\r
715\r
96f5920d
JF
716/**\r
717 Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
718\r
719 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
720**/\r
721VOID\r
722WaitApWakeup (\r
723 IN volatile UINT32 *ApStartupSignalBuffer\r
724 )\r
725{\r
726 //\r
727 // If AP is waken up, StartupApSignal should be cleared.\r
728 // Otherwise, write StartupApSignal again till AP waken up.\r
729 //\r
730 while (InterlockedCompareExchange32 (\r
731 (UINT32 *) ApStartupSignalBuffer,\r
732 WAKEUP_AP_SIGNAL,\r
733 WAKEUP_AP_SIGNAL\r
734 ) != 0) {\r
735 CpuPause ();\r
736 }\r
737}\r
738\r
7c3f2a12
JF
739/**\r
740 This function will fill the exchange info structure.\r
741\r
742 @param[in] CpuMpData Pointer to CPU MP Data\r
743\r
744**/\r
745VOID\r
746FillExchangeInfoData (\r
747 IN CPU_MP_DATA *CpuMpData\r
748 )\r
749{\r
750 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
751\r
752 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
753 ExchangeInfo->Lock = 0;\r
754 ExchangeInfo->StackStart = CpuMpData->Buffer;\r
755 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
756 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
757 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
758\r
759 ExchangeInfo->CodeSegment = AsmReadCs ();\r
760 ExchangeInfo->DataSegment = AsmReadDs ();\r
761\r
762 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
763\r
764 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
765 ExchangeInfo->NumApsExecuting = 0;\r
766 ExchangeInfo->CpuMpData = CpuMpData;\r
767\r
768 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
769\r
770 //\r
771 // Get the BSP's data of GDT and IDT\r
772 //\r
773 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
774 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
775}\r
776\r
96f5920d
JF
777/**\r
778 This function will be called by BSP to wakeup AP.\r
779\r
780 @param[in] CpuMpData Pointer to CPU MP Data\r
781 @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
782 FALSE: Send IPI to AP by ApicId\r
783 @param[in] ProcessorNumber The handle number of specified processor\r
784 @param[in] Procedure The function to be invoked by AP\r
785 @param[in] ProcedureArgument The argument to be passed into AP function\r
786**/\r
787VOID\r
788WakeUpAP (\r
789 IN CPU_MP_DATA *CpuMpData,\r
790 IN BOOLEAN Broadcast,\r
791 IN UINTN ProcessorNumber,\r
792 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
793 IN VOID *ProcedureArgument OPTIONAL\r
794 )\r
795{\r
796 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
797 UINTN Index;\r
798 CPU_AP_DATA *CpuData;\r
799 BOOLEAN ResetVectorRequired;\r
800\r
801 CpuMpData->FinishedCount = 0;\r
802 ResetVectorRequired = FALSE;\r
803\r
804 if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
805 CpuMpData->InitFlag != ApInitDone) {\r
806 ResetVectorRequired = TRUE;\r
807 AllocateResetVector (CpuMpData);\r
808 FillExchangeInfoData (CpuMpData);\r
809 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
810 //\r
811 // Get AP target C-state each time when waking up AP,\r
812 // for it maybe updated by platform again\r
813 //\r
814 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
815 }\r
816\r
817 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
818\r
819 if (Broadcast) {\r
820 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
821 if (Index != CpuMpData->BspNumber) {\r
822 CpuData = &CpuMpData->CpuData[Index];\r
823 CpuData->ApFunction = (UINTN) Procedure;\r
824 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
825 SetApState (CpuData, CpuStateReady);\r
826 if (CpuMpData->InitFlag != ApInitConfig) {\r
827 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
828 }\r
829 }\r
830 }\r
831 if (ResetVectorRequired) {\r
832 //\r
833 // Wakeup all APs\r
834 //\r
835 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
836 }\r
837 if (CpuMpData->InitFlag != ApInitConfig) {\r
838 //\r
839 // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
840 //\r
841 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
842 CpuData = &CpuMpData->CpuData[Index];\r
843 if (Index != CpuMpData->BspNumber) {\r
844 WaitApWakeup (CpuData->StartupApSignal);\r
845 }\r
846 }\r
847 }\r
848 } else {\r
849 CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
850 CpuData->ApFunction = (UINTN) Procedure;\r
851 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
852 SetApState (CpuData, CpuStateReady);\r
853 //\r
854 // Wakeup specified AP\r
855 //\r
856 ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
857 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
858 if (ResetVectorRequired) {\r
859 SendInitSipiSipi (\r
860 CpuData->ApicId,\r
861 (UINT32) ExchangeInfo->BufferStart\r
862 );\r
863 }\r
864 //\r
865 // Wait specified AP waken up\r
866 //\r
867 WaitApWakeup (CpuData->StartupApSignal);\r
868 }\r
869\r
870 if (ResetVectorRequired) {\r
871 FreeResetVector (CpuMpData);\r
872 }\r
873}\r
874\r
3e8ad6bd
JF
875/**\r
876 MP Initialize Library initialization.\r
877\r
878 This service will allocate AP reset vector and wakeup all APs to do APs\r
879 initialization.\r
880\r
881 This service must be invoked before all other MP Initialize Library\r
882 service are invoked.\r
883\r
884 @retval EFI_SUCCESS MP initialization succeeds.\r
885 @retval Others MP initialization fails.\r
886\r
887**/\r
888EFI_STATUS\r
889EFIAPI\r
890MpInitLibInitialize (\r
891 VOID\r
892 )\r
893{\r
6a2ee2bb
JF
894 CPU_MP_DATA *OldCpuMpData;\r
895 CPU_INFO_IN_HOB *CpuInfoInHob;\r
e59f8f6b
JF
896 UINT32 MaxLogicalProcessorNumber;\r
897 UINT32 ApStackSize;\r
f7f85d83 898 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e59f8f6b 899 UINTN BufferSize;\r
9ebcf0f4 900 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
901 VOID *MpBuffer;\r
902 UINTN Buffer;\r
903 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 904 UINT8 ApLoopMode;\r
e59f8f6b 905 UINT8 *MonitorBuffer;\r
03a1a925 906 UINTN Index;\r
f7f85d83 907 UINTN ApResetVectorSize;\r
e59f8f6b 908 UINTN BackupBufferAddr;\r
6a2ee2bb
JF
909\r
910 OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
911 if (OldCpuMpData == NULL) {\r
912 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
913 } else {\r
914 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
915 }\r
f7f85d83
JF
916\r
917 AsmGetAddressMap (&AddressMap);\r
918 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
e59f8f6b 919 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
9ebcf0f4
JF
920 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
921\r
e59f8f6b
JF
922 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
923 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
924 BufferSize += sizeof (CPU_MP_DATA);\r
925 BufferSize += ApResetVectorSize;\r
926 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
927 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
928 ASSERT (MpBuffer != NULL);\r
929 ZeroMem (MpBuffer, BufferSize);\r
930 Buffer = (UINTN) MpBuffer;\r
931\r
932 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
933 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
934 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
935 CpuMpData->Buffer = Buffer;\r
936 CpuMpData->CpuApStackSize = ApStackSize;\r
937 CpuMpData->BackupBuffer = BackupBufferAddr;\r
938 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
939 CpuMpData->EndOfPeiFlag = FALSE;\r
940 CpuMpData->WakeupBuffer = (UINTN) -1;\r
941 CpuMpData->CpuCount = 1;\r
942 CpuMpData->BspNumber = 0;\r
943 CpuMpData->WaitEvent = NULL;\r
944 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
945 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
946 InitializeSpinLock(&CpuMpData->MpLock);\r
947 //\r
68cb9330
JF
948 // Save BSP's Control registers to APs\r
949 //\r
950 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
951 //\r
03a1a925
JF
952 // Set BSP basic information\r
953 //\r
954 InitializeApData (CpuMpData, 0, 0);\r
955 //\r
e59f8f6b
JF
956 // Save assembly code information\r
957 //\r
958 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
959 //\r
960 // Finally set AP loop mode\r
961 //\r
962 CpuMpData->ApLoopMode = ApLoopMode;\r
963 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
964 //\r
03a1a925
JF
965 // Set up APs wakeup signal buffer\r
966 //\r
967 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
968 CpuMpData->CpuData[Index].StartupApSignal =\r
969 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
970 }\r
94f63c76
JF
971 //\r
972 // Load Microcode on BSP\r
973 //\r
974 MicrocodeDetect (CpuMpData);\r
975 //\r
e59f8f6b
JF
976 // Store BSP's MTRR setting\r
977 //\r
978 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
979\r
6a2ee2bb
JF
980 if (OldCpuMpData == NULL) {\r
981 //\r
982 // Wakeup all APs and calculate the processor count in system\r
983 //\r
984 CollectProcessorCount (CpuMpData);\r
985 } else {\r
986 //\r
987 // APs have been wakeup before, just get the CPU Information\r
988 // from HOB\r
989 //\r
990 CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
991 CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
992 CpuMpData->InitFlag = ApInitReconfig;\r
993 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;\r
994 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
995 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
996 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;\r
997 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;\r
998 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {\r
999 CpuMpData->X2ApicEnable = TRUE;\r
1000 }\r
1001 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;\r
1002 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;\r
1003 CpuMpData->CpuData[Index].ApFunction = 0;\r
1004 CopyMem (\r
1005 &CpuMpData->CpuData[Index].VolatileRegisters,\r
1006 &CpuMpData->CpuData[0].VolatileRegisters,\r
1007 sizeof (CPU_VOLATILE_REGISTERS)\r
1008 );\r
1009 }\r
1010 //\r
1011 // Wakeup APs to do some AP initialize sync\r
1012 //\r
1013 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
1014 //\r
1015 // Wait for all APs finished initialization\r
1016 //\r
1017 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
1018 CpuPause ();\r
1019 }\r
1020 CpuMpData->InitFlag = ApInitDone;\r
1021 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
1022 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
1023 }\r
1024 }\r
93ca4c0f
JF
1025\r
1026 //\r
1027 // Initialize global data for MP support\r
1028 //\r
1029 InitMpGlobalData (CpuMpData);\r
1030\r
f7f85d83 1031 return EFI_SUCCESS;\r
3e8ad6bd
JF
1032}\r
1033\r
1034/**\r
1035 Gets detailed MP-related information on the requested processor at the\r
1036 instant this call is made. This service may only be called from the BSP.\r
1037\r
1038 @param[in] ProcessorNumber The handle number of processor.\r
1039 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
1040 the requested processor is deposited.\r
1041 @param[out] HealthData Return processor health data.\r
1042\r
1043 @retval EFI_SUCCESS Processor information was returned.\r
1044 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1045 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
1046 @retval EFI_NOT_FOUND The processor with the handle specified by\r
1047 ProcessorNumber does not exist in the platform.\r
1048 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1049\r
1050**/\r
1051EFI_STATUS\r
1052EFIAPI\r
1053MpInitLibGetProcessorInfo (\r
1054 IN UINTN ProcessorNumber,\r
1055 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
1056 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
1057 )\r
1058{\r
ad52f25e
JF
1059 CPU_MP_DATA *CpuMpData;\r
1060 UINTN CallerNumber;\r
1061\r
1062 CpuMpData = GetCpuMpData ();\r
1063\r
1064 //\r
1065 // Check whether caller processor is BSP\r
1066 //\r
1067 MpInitLibWhoAmI (&CallerNumber);\r
1068 if (CallerNumber != CpuMpData->BspNumber) {\r
1069 return EFI_DEVICE_ERROR;\r
1070 }\r
1071\r
1072 if (ProcessorInfoBuffer == NULL) {\r
1073 return EFI_INVALID_PARAMETER;\r
1074 }\r
1075\r
1076 if (ProcessorNumber >= CpuMpData->CpuCount) {\r
1077 return EFI_NOT_FOUND;\r
1078 }\r
1079\r
1080 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;\r
1081 ProcessorInfoBuffer->StatusFlag = 0;\r
1082 if (ProcessorNumber == CpuMpData->BspNumber) {\r
1083 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
1084 }\r
1085 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {\r
1086 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
1087 }\r
1088 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {\r
1089 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;\r
1090 } else {\r
1091 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
1092 }\r
1093\r
1094 //\r
1095 // Get processor location information\r
1096 //\r
1097 ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);\r
1098\r
1099 if (HealthData != NULL) {\r
1100 HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;\r
1101 }\r
1102\r
1103 return EFI_SUCCESS;\r
3e8ad6bd 1104}\r
ad52f25e
JF
1105\r
1106\r
3e8ad6bd
JF
1107/**\r
1108 This return the handle number for the calling processor. This service may be\r
1109 called from the BSP and APs.\r
1110\r
1111 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
1112 The range is from 0 to the total number of\r
1113 logical processors minus 1. The total number of\r
1114 logical processors can be retrieved by\r
1115 MpInitLibGetNumberOfProcessors().\r
1116\r
1117 @retval EFI_SUCCESS The current processor handle number was returned\r
1118 in ProcessorNumber.\r
1119 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
1120 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1121\r
1122**/\r
1123EFI_STATUS\r
1124EFIAPI\r
1125MpInitLibWhoAmI (\r
1126 OUT UINTN *ProcessorNumber\r
1127 )\r
1128{\r
1129 return EFI_UNSUPPORTED;\r
1130}\r
809213a6 1131\r
3e8ad6bd
JF
1132/**\r
1133 Retrieves the number of logical processor in the platform and the number of\r
1134 those logical processors that are enabled on this boot. This service may only\r
1135 be called from the BSP.\r
1136\r
1137 @param[out] NumberOfProcessors Pointer to the total number of logical\r
1138 processors in the system, including the BSP\r
1139 and disabled APs.\r
1140 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
1141 processors that exist in system, including\r
1142 the BSP.\r
1143\r
1144 @retval EFI_SUCCESS The number of logical processors and enabled\r
1145 logical processors was retrieved.\r
1146 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1147 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
1148 is NULL.\r
1149 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
1150\r
1151**/\r
1152EFI_STATUS\r
1153EFIAPI\r
1154MpInitLibGetNumberOfProcessors (\r
1155 OUT UINTN *NumberOfProcessors, OPTIONAL\r
1156 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
1157 )\r
1158{\r
809213a6
JF
1159 CPU_MP_DATA *CpuMpData;\r
1160 UINTN CallerNumber;\r
1161 UINTN ProcessorNumber;\r
1162 UINTN EnabledProcessorNumber;\r
1163 UINTN Index;\r
1164\r
1165 CpuMpData = GetCpuMpData ();\r
1166\r
1167 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {\r
1168 return EFI_INVALID_PARAMETER;\r
1169 }\r
1170\r
1171 //\r
1172 // Check whether caller processor is BSP\r
1173 //\r
1174 MpInitLibWhoAmI (&CallerNumber);\r
1175 if (CallerNumber != CpuMpData->BspNumber) {\r
1176 return EFI_DEVICE_ERROR;\r
1177 }\r
1178\r
1179 ProcessorNumber = CpuMpData->CpuCount;\r
1180 EnabledProcessorNumber = 0;\r
1181 for (Index = 0; Index < ProcessorNumber; Index++) {\r
1182 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {\r
1183 EnabledProcessorNumber ++;\r
1184 }\r
1185 }\r
1186\r
1187 if (NumberOfProcessors != NULL) {\r
1188 *NumberOfProcessors = ProcessorNumber;\r
1189 }\r
1190 if (NumberOfEnabledProcessors != NULL) {\r
1191 *NumberOfEnabledProcessors = EnabledProcessorNumber;\r
1192 }\r
1193\r
1194 return EFI_SUCCESS;\r
3e8ad6bd 1195}\r
6a2ee2bb 1196\r
809213a6 1197\r
93ca4c0f
JF
1198/**\r
1199 Get pointer to CPU MP Data structure from GUIDed HOB.\r
1200\r
1201 @return The pointer to CPU MP Data structure.\r
1202**/\r
1203CPU_MP_DATA *\r
1204GetCpuMpDataFromGuidedHob (\r
1205 VOID\r
1206 )\r
1207{\r
1208 EFI_HOB_GUID_TYPE *GuidHob;\r
1209 VOID *DataInHob;\r
1210 CPU_MP_DATA *CpuMpData;\r
1211\r
1212 CpuMpData = NULL;\r
1213 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
1214 if (GuidHob != NULL) {\r
1215 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
1216 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
1217 }\r
1218 return CpuMpData;\r
1219}\r