]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Allocate AP reset vector buffer under 1MB
[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
03a1a925
JF
19/**\r
20 Get the Application Processors state.\r
21\r
22 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
23\r
24 @return The AP status\r
25**/\r
26CPU_STATE\r
27GetApState (\r
28 IN CPU_AP_DATA *CpuData\r
29 )\r
30{\r
31 return CpuData->State;\r
32}\r
33\r
34/**\r
35 Set the Application Processors state.\r
36\r
37 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
38 @param[in] State The AP status\r
39**/\r
40VOID\r
41SetApState (\r
42 IN CPU_AP_DATA *CpuData,\r
43 IN CPU_STATE State\r
44 )\r
45{\r
46 AcquireSpinLock (&CpuData->ApLock);\r
47 CpuData->State = State;\r
48 ReleaseSpinLock (&CpuData->ApLock);\r
49}\r
3e8ad6bd 50\r
68cb9330
JF
51/**\r
52 Save the volatile registers required to be restored following INIT IPI.\r
53\r
54 @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
55**/\r
56VOID\r
57SaveVolatileRegisters (\r
58 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
59 )\r
60{\r
61 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
62\r
63 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
64 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
65 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
66\r
67 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
68 if (VersionInfoEdx.Bits.DE != 0) {\r
69 //\r
70 // If processor supports Debugging Extensions feature\r
71 // by CPUID.[EAX=01H]:EDX.BIT2\r
72 //\r
73 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
74 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
75 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
76 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
77 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
78 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
79 }\r
80}\r
81\r
82/**\r
83 Restore the volatile registers following INIT IPI.\r
84\r
85 @param[in] VolatileRegisters Pointer to volatile resisters\r
86 @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
87 FALSE: Do not restore DRx\r
88**/\r
89VOID\r
90RestoreVolatileRegisters (\r
91 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
92 IN BOOLEAN IsRestoreDr\r
93 )\r
94{\r
95 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
96\r
97 AsmWriteCr0 (VolatileRegisters->Cr0);\r
98 AsmWriteCr3 (VolatileRegisters->Cr3);\r
99 AsmWriteCr4 (VolatileRegisters->Cr4);\r
100\r
101 if (IsRestoreDr) {\r
102 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
103 if (VersionInfoEdx.Bits.DE != 0) {\r
104 //\r
105 // If processor supports Debugging Extensions feature\r
106 // by CPUID.[EAX=01H]:EDX.BIT2\r
107 //\r
108 AsmWriteDr0 (VolatileRegisters->Dr0);\r
109 AsmWriteDr1 (VolatileRegisters->Dr1);\r
110 AsmWriteDr2 (VolatileRegisters->Dr2);\r
111 AsmWriteDr3 (VolatileRegisters->Dr3);\r
112 AsmWriteDr6 (VolatileRegisters->Dr6);\r
113 AsmWriteDr7 (VolatileRegisters->Dr7);\r
114 }\r
115 }\r
116}\r
117\r
9ebcf0f4
JF
118/**\r
119 Detect whether Mwait-monitor feature is supported.\r
120\r
121 @retval TRUE Mwait-monitor feature is supported.\r
122 @retval FALSE Mwait-monitor feature is not supported.\r
123**/\r
124BOOLEAN\r
125IsMwaitSupport (\r
126 VOID\r
127 )\r
128{\r
129 CPUID_VERSION_INFO_ECX VersionInfoEcx;\r
130\r
131 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);\r
132 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;\r
133}\r
134\r
135/**\r
136 Get AP loop mode.\r
137\r
138 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.\r
139\r
140 @return The AP loop mode.\r
141**/\r
142UINT8\r
143GetApLoopMode (\r
144 OUT UINT32 *MonitorFilterSize\r
145 )\r
146{\r
147 UINT8 ApLoopMode;\r
148 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;\r
149\r
150 ASSERT (MonitorFilterSize != NULL);\r
151\r
152 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
153 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
154 if (ApLoopMode == ApInMwaitLoop) {\r
155 if (!IsMwaitSupport ()) {\r
156 //\r
157 // If processor does not support MONITOR/MWAIT feature,\r
158 // force AP in Hlt-loop mode\r
159 //\r
160 ApLoopMode = ApInHltLoop;\r
161 }\r
162 }\r
163\r
164 if (ApLoopMode != ApInMwaitLoop) {\r
165 *MonitorFilterSize = sizeof (UINT32);\r
166 } else {\r
167 //\r
168 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
169 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
170 //\r
171 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
172 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
173 }\r
174\r
175 return ApLoopMode;\r
176}\r
03a1a925
JF
177/*\r
178 Initialize CPU AP Data when AP is wakeup at the first time.\r
179\r
180 @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
181 @param[in] ProcessorNumber The handle number of processor\r
182 @param[in] BistData Processor BIST data\r
183\r
184**/\r
185VOID\r
186InitializeApData (\r
187 IN OUT CPU_MP_DATA *CpuMpData,\r
188 IN UINTN ProcessorNumber,\r
189 IN UINT32 BistData\r
190 )\r
191{\r
192 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
193 CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
194 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
195 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
196 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
197 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
198 //\r
199 // Set x2APIC mode if there are any logical processor reporting\r
200 // an Initial APIC ID of 255 or greater.\r
201 //\r
202 AcquireSpinLock(&CpuMpData->MpLock);\r
203 CpuMpData->X2ApicEnable = TRUE;\r
204 ReleaseSpinLock(&CpuMpData->MpLock);\r
205 }\r
206\r
207 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
208 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
209}\r
210\r
3e8ad6bd
JF
211/**\r
212 MP Initialize Library initialization.\r
213\r
214 This service will allocate AP reset vector and wakeup all APs to do APs\r
215 initialization.\r
216\r
217 This service must be invoked before all other MP Initialize Library\r
218 service are invoked.\r
219\r
220 @retval EFI_SUCCESS MP initialization succeeds.\r
221 @retval Others MP initialization fails.\r
222\r
223**/\r
224EFI_STATUS\r
225EFIAPI\r
226MpInitLibInitialize (\r
227 VOID\r
228 )\r
229{\r
e59f8f6b
JF
230 UINT32 MaxLogicalProcessorNumber;\r
231 UINT32 ApStackSize;\r
f7f85d83 232 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e59f8f6b 233 UINTN BufferSize;\r
9ebcf0f4 234 UINT32 MonitorFilterSize;\r
e59f8f6b
JF
235 VOID *MpBuffer;\r
236 UINTN Buffer;\r
237 CPU_MP_DATA *CpuMpData;\r
9ebcf0f4 238 UINT8 ApLoopMode;\r
e59f8f6b 239 UINT8 *MonitorBuffer;\r
03a1a925 240 UINTN Index;\r
f7f85d83 241 UINTN ApResetVectorSize;\r
e59f8f6b
JF
242 UINTN BackupBufferAddr;\r
243 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
f7f85d83
JF
244\r
245 AsmGetAddressMap (&AddressMap);\r
246 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
e59f8f6b 247 ApStackSize = PcdGet32(PcdCpuApStackSize);\r
9ebcf0f4
JF
248 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
249\r
e59f8f6b
JF
250 BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
251 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
252 BufferSize += sizeof (CPU_MP_DATA);\r
253 BufferSize += ApResetVectorSize;\r
254 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
255 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
256 ASSERT (MpBuffer != NULL);\r
257 ZeroMem (MpBuffer, BufferSize);\r
258 Buffer = (UINTN) MpBuffer;\r
259\r
260 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
261 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
262 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
263 CpuMpData->Buffer = Buffer;\r
264 CpuMpData->CpuApStackSize = ApStackSize;\r
265 CpuMpData->BackupBuffer = BackupBufferAddr;\r
266 CpuMpData->BackupBufferSize = ApResetVectorSize;\r
267 CpuMpData->EndOfPeiFlag = FALSE;\r
268 CpuMpData->WakeupBuffer = (UINTN) -1;\r
269 CpuMpData->CpuCount = 1;\r
270 CpuMpData->BspNumber = 0;\r
271 CpuMpData->WaitEvent = NULL;\r
272 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
273 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
274 InitializeSpinLock(&CpuMpData->MpLock);\r
275 //\r
68cb9330
JF
276 // Save BSP's Control registers to APs\r
277 //\r
278 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
279 //\r
03a1a925
JF
280 // Set BSP basic information\r
281 //\r
282 InitializeApData (CpuMpData, 0, 0);\r
283 //\r
e59f8f6b
JF
284 // Save assembly code information\r
285 //\r
286 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
287 //\r
288 // Finally set AP loop mode\r
289 //\r
290 CpuMpData->ApLoopMode = ApLoopMode;\r
291 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
292 //\r
03a1a925
JF
293 // Set up APs wakeup signal buffer\r
294 //\r
295 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
296 CpuMpData->CpuData[Index].StartupApSignal =\r
297 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
298 }\r
94f63c76
JF
299 //\r
300 // Load Microcode on BSP\r
301 //\r
302 MicrocodeDetect (CpuMpData);\r
303 //\r
e59f8f6b
JF
304 // Store BSP's MTRR setting\r
305 //\r
306 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
307\r
93ca4c0f
JF
308\r
309 //\r
310 // Initialize global data for MP support\r
311 //\r
312 InitMpGlobalData (CpuMpData);\r
313\r
f7f85d83 314 return EFI_SUCCESS;\r
3e8ad6bd
JF
315}\r
316\r
317/**\r
318 Gets detailed MP-related information on the requested processor at the\r
319 instant this call is made. This service may only be called from the BSP.\r
320\r
321 @param[in] ProcessorNumber The handle number of processor.\r
322 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
323 the requested processor is deposited.\r
324 @param[out] HealthData Return processor health data.\r
325\r
326 @retval EFI_SUCCESS Processor information was returned.\r
327 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
328 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
329 @retval EFI_NOT_FOUND The processor with the handle specified by\r
330 ProcessorNumber does not exist in the platform.\r
331 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
332\r
333**/\r
334EFI_STATUS\r
335EFIAPI\r
336MpInitLibGetProcessorInfo (\r
337 IN UINTN ProcessorNumber,\r
338 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,\r
339 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL\r
340 )\r
341{\r
342 return EFI_UNSUPPORTED;\r
343}\r
344/**\r
345 This return the handle number for the calling processor. This service may be\r
346 called from the BSP and APs.\r
347\r
348 @param[out] ProcessorNumber Pointer to the handle number of AP.\r
349 The range is from 0 to the total number of\r
350 logical processors minus 1. The total number of\r
351 logical processors can be retrieved by\r
352 MpInitLibGetNumberOfProcessors().\r
353\r
354 @retval EFI_SUCCESS The current processor handle number was returned\r
355 in ProcessorNumber.\r
356 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
357 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
358\r
359**/\r
360EFI_STATUS\r
361EFIAPI\r
362MpInitLibWhoAmI (\r
363 OUT UINTN *ProcessorNumber\r
364 )\r
365{\r
366 return EFI_UNSUPPORTED;\r
367}\r
368/**\r
369 Retrieves the number of logical processor in the platform and the number of\r
370 those logical processors that are enabled on this boot. This service may only\r
371 be called from the BSP.\r
372\r
373 @param[out] NumberOfProcessors Pointer to the total number of logical\r
374 processors in the system, including the BSP\r
375 and disabled APs.\r
376 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
377 processors that exist in system, including\r
378 the BSP.\r
379\r
380 @retval EFI_SUCCESS The number of logical processors and enabled\r
381 logical processors was retrieved.\r
382 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
383 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors\r
384 is NULL.\r
385 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
386\r
387**/\r
388EFI_STATUS\r
389EFIAPI\r
390MpInitLibGetNumberOfProcessors (\r
391 OUT UINTN *NumberOfProcessors, OPTIONAL\r
392 OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
393 )\r
394{\r
395 return EFI_UNSUPPORTED;\r
396}\r
93ca4c0f
JF
397/**\r
398 Get pointer to CPU MP Data structure from GUIDed HOB.\r
399\r
400 @return The pointer to CPU MP Data structure.\r
401**/\r
402CPU_MP_DATA *\r
403GetCpuMpDataFromGuidedHob (\r
404 VOID\r
405 )\r
406{\r
407 EFI_HOB_GUID_TYPE *GuidHob;\r
408 VOID *DataInHob;\r
409 CPU_MP_DATA *CpuMpData;\r
410\r
411 CpuMpData = NULL;\r
412 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
413 if (GuidHob != NULL) {\r
414 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
415 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
416 }\r
417 return CpuMpData;\r
418}\r