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