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