]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/CpuS3.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add EFIAPI to CheckFeatureSupported()
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / CpuS3.c
1 /** @file
2 Code for Processor S3 restoration
3
4 Copyright (c) 2006 - 2015, 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 "PiSmmCpuDxeSmm.h"
16
17 typedef struct {
18 UINTN Lock;
19 VOID *StackStart;
20 UINTN StackSize;
21 VOID *ApFunction;
22 IA32_DESCRIPTOR GdtrProfile;
23 IA32_DESCRIPTOR IdtrProfile;
24 UINT32 BufferStart;
25 UINT32 Cr3;
26 } MP_CPU_EXCHANGE_INFO;
27
28 typedef struct {
29 UINT8 *RendezvousFunnelAddress;
30 UINTN PModeEntryOffset;
31 UINTN FlatJumpOffset;
32 UINTN Size;
33 UINTN LModeEntryOffset;
34 UINTN LongJumpOffset;
35 } MP_ASSEMBLY_ADDRESS_MAP;
36
37 /**
38 Get starting address and size of the rendezvous entry for APs.
39 Information for fixing a jump instruction in the code is also returned.
40
41 @param AddressMap Output buffer for address map information.
42 **/
43 VOID *
44 EFIAPI
45 AsmGetAddressMap (
46 MP_ASSEMBLY_ADDRESS_MAP *AddressMap
47 );
48
49 #define LEGACY_REGION_SIZE (2 * 0x1000)
50 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
51 #define MSR_SPIN_LOCK_INIT_NUM 15
52
53 ACPI_CPU_DATA mAcpiCpuData;
54 UINT32 mNumberToFinish;
55 MP_CPU_EXCHANGE_INFO *mExchangeInfo;
56 BOOLEAN mRestoreSmmConfigurationInS3 = FALSE;
57 VOID *mGdtForAp = NULL;
58 VOID *mIdtForAp = NULL;
59 VOID *mMachineCheckHandlerForAp = NULL;
60 MP_MSR_LOCK *mMsrSpinLocks = NULL;
61 UINTN mMsrSpinLockCount = MSR_SPIN_LOCK_INIT_NUM;
62 UINTN mMsrCount = 0;
63
64 /**
65 Get MSR spin lock by MSR index.
66
67 @param MsrIndex MSR index value.
68
69 @return Pointer to MSR spin lock.
70
71 **/
72 SPIN_LOCK *
73 GetMsrSpinLockByIndex (
74 IN UINT32 MsrIndex
75 )
76 {
77 UINTN Index;
78 for (Index = 0; Index < mMsrCount; Index++) {
79 if (MsrIndex == mMsrSpinLocks[Index].MsrIndex) {
80 return &mMsrSpinLocks[Index].SpinLock;
81 }
82 }
83 return NULL;
84 }
85
86 /**
87 Initialize MSR spin lock by MSR index.
88
89 @param MsrIndex MSR index value.
90
91 **/
92 VOID
93 InitMsrSpinLockByIndex (
94 IN UINT32 MsrIndex
95 )
96 {
97 UINTN NewMsrSpinLockCount;
98
99 if (mMsrSpinLocks == NULL) {
100 mMsrSpinLocks = (MP_MSR_LOCK *) AllocatePool (sizeof (MP_MSR_LOCK) * mMsrSpinLockCount);
101 ASSERT (mMsrSpinLocks != NULL);
102 }
103 if (GetMsrSpinLockByIndex (MsrIndex) == NULL) {
104 //
105 // Initialize spin lock for MSR programming
106 //
107 mMsrSpinLocks[mMsrCount].MsrIndex = MsrIndex;
108 InitializeSpinLock (&mMsrSpinLocks[mMsrCount].SpinLock);
109 mMsrCount ++;
110 if (mMsrCount == mMsrSpinLockCount) {
111 //
112 // If MSR spin lock buffer is full, enlarge it
113 //
114 NewMsrSpinLockCount = mMsrSpinLockCount + MSR_SPIN_LOCK_INIT_NUM;
115 mMsrSpinLocks = ReallocatePool (
116 sizeof (MP_MSR_LOCK) * mMsrSpinLockCount,
117 sizeof (MP_MSR_LOCK) * NewMsrSpinLockCount,
118 mMsrSpinLocks
119 );
120 mMsrSpinLockCount = NewMsrSpinLockCount;
121 }
122 }
123 }
124
125 /**
126 Sync up the MTRR values for all processors.
127
128 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
129 **/
130 VOID
131 EFIAPI
132 LoadMtrrData (
133 EFI_PHYSICAL_ADDRESS MtrrTable
134 )
135 /*++
136
137 Routine Description:
138
139 Sync up the MTRR values for all processors.
140
141 Arguments:
142
143 Returns:
144 None
145
146 --*/
147 {
148 MTRR_SETTINGS *MtrrSettings;
149
150 MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable;
151 MtrrSetAllMtrrs (MtrrSettings);
152 }
153
154 /**
155 Programs registers for the calling processor.
156
157 This function programs registers for the calling processor.
158
159 @param RegisterTable Pointer to register table of the running processor.
160
161 **/
162 VOID
163 SetProcessorRegister (
164 IN CPU_REGISTER_TABLE *RegisterTable
165 )
166 {
167 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
168 UINTN Index;
169 UINTN Value;
170 SPIN_LOCK *MsrSpinLock;
171
172 //
173 // Traverse Register Table of this logical processor
174 //
175 RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
176 for (Index = 0; Index < RegisterTable->TableLength; Index++, RegisterTableEntry++) {
177 //
178 // Check the type of specified register
179 //
180 switch (RegisterTableEntry->RegisterType) {
181 //
182 // The specified register is Control Register
183 //
184 case ControlRegister:
185 switch (RegisterTableEntry->Index) {
186 case 0:
187 Value = AsmReadCr0 ();
188 Value = (UINTN) BitFieldWrite64 (
189 Value,
190 RegisterTableEntry->ValidBitStart,
191 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
192 (UINTN) RegisterTableEntry->Value
193 );
194 AsmWriteCr0 (Value);
195 break;
196 case 2:
197 Value = AsmReadCr2 ();
198 Value = (UINTN) BitFieldWrite64 (
199 Value,
200 RegisterTableEntry->ValidBitStart,
201 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
202 (UINTN) RegisterTableEntry->Value
203 );
204 AsmWriteCr2 (Value);
205 break;
206 case 3:
207 Value = AsmReadCr3 ();
208 Value = (UINTN) BitFieldWrite64 (
209 Value,
210 RegisterTableEntry->ValidBitStart,
211 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
212 (UINTN) RegisterTableEntry->Value
213 );
214 AsmWriteCr3 (Value);
215 break;
216 case 4:
217 Value = AsmReadCr4 ();
218 Value = (UINTN) BitFieldWrite64 (
219 Value,
220 RegisterTableEntry->ValidBitStart,
221 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
222 (UINTN) RegisterTableEntry->Value
223 );
224 AsmWriteCr4 (Value);
225 break;
226 default:
227 break;
228 }
229 break;
230 //
231 // The specified register is Model Specific Register
232 //
233 case Msr:
234 //
235 // If this function is called to restore register setting after INIT signal,
236 // there is no need to restore MSRs in register table.
237 //
238 if (RegisterTableEntry->ValidBitLength >= 64) {
239 //
240 // If length is not less than 64 bits, then directly write without reading
241 //
242 AsmWriteMsr64 (
243 RegisterTableEntry->Index,
244 RegisterTableEntry->Value
245 );
246 } else {
247 //
248 // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
249 // to make sure MSR read/write operation is atomic.
250 //
251 MsrSpinLock = GetMsrSpinLockByIndex (RegisterTableEntry->Index);
252 AcquireSpinLock (MsrSpinLock);
253 //
254 // Set the bit section according to bit start and length
255 //
256 AsmMsrBitFieldWrite64 (
257 RegisterTableEntry->Index,
258 RegisterTableEntry->ValidBitStart,
259 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
260 RegisterTableEntry->Value
261 );
262 ReleaseSpinLock (MsrSpinLock);
263 }
264 break;
265 //
266 // Enable or disable cache
267 //
268 case CacheControl:
269 //
270 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
271 //
272 if (RegisterTableEntry->Value == 0) {
273 AsmDisableCache ();
274 } else {
275 AsmEnableCache ();
276 }
277 break;
278
279 default:
280 break;
281 }
282 }
283 }
284
285 /**
286 AP initialization before SMBASE relocation in the S3 boot path.
287 **/
288 VOID
289 EarlyMPRendezvousProcedure (
290 VOID
291 )
292 {
293 CPU_REGISTER_TABLE *RegisterTableList;
294 UINT32 InitApicId;
295 UINTN Index;
296
297 LoadMtrrData (mAcpiCpuData.MtrrTable);
298
299 //
300 // Find processor number for this CPU.
301 //
302 RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
303 InitApicId = GetInitialApicId ();
304 for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
305 if (RegisterTableList[Index].InitialApicId == InitApicId) {
306 SetProcessorRegister (&RegisterTableList[Index]);
307 break;
308 }
309 }
310
311 //
312 // Count down the number with lock mechanism.
313 //
314 InterlockedDecrement (&mNumberToFinish);
315 }
316
317 /**
318 AP initialization after SMBASE relocation in the S3 boot path.
319 **/
320 VOID
321 MPRendezvousProcedure (
322 VOID
323 )
324 {
325 CPU_REGISTER_TABLE *RegisterTableList;
326 UINT32 InitApicId;
327 UINTN Index;
328
329 ProgramVirtualWireMode ();
330 DisableLvtInterrupts ();
331
332 RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
333 InitApicId = GetInitialApicId ();
334 for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
335 if (RegisterTableList[Index].InitialApicId == InitApicId) {
336 SetProcessorRegister (&RegisterTableList[Index]);
337 break;
338 }
339 }
340
341 //
342 // Count down the number with lock mechanism.
343 //
344 InterlockedDecrement (&mNumberToFinish);
345 }
346
347 /**
348 Prepares startup vector for APs.
349
350 This function prepares startup vector for APs.
351
352 @param WorkingBuffer The address of the work buffer.
353 **/
354 VOID
355 PrepareApStartupVector (
356 EFI_PHYSICAL_ADDRESS WorkingBuffer
357 )
358 {
359 EFI_PHYSICAL_ADDRESS StartupVector;
360 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
361
362 //
363 // Get the address map of startup code for AP,
364 // including code size, and offset of long jump instructions to redirect.
365 //
366 ZeroMem (&AddressMap, sizeof (AddressMap));
367 AsmGetAddressMap (&AddressMap);
368
369 StartupVector = WorkingBuffer;
370
371 //
372 // Copy AP startup code to startup vector, and then redirect the long jump
373 // instructions for mode switching.
374 //
375 CopyMem ((VOID *) (UINTN) StartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
376 *(UINT32 *) (UINTN) (StartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (StartupVector + AddressMap.PModeEntryOffset);
377 if (AddressMap.LongJumpOffset != 0) {
378 *(UINT32 *) (UINTN) (StartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (StartupVector + AddressMap.LModeEntryOffset);
379 }
380
381 //
382 // Get the start address of exchange data between BSP and AP.
383 //
384 mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (StartupVector + AddressMap.Size);
385 ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));
386
387 CopyMem ((VOID *) (UINTN) &mExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData.GdtrProfile, sizeof (IA32_DESCRIPTOR));
388 CopyMem ((VOID *) (UINTN) &mExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData.IdtrProfile, sizeof (IA32_DESCRIPTOR));
389
390 //
391 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
392 //
393 CopyMem ((VOID *) mExchangeInfo->GdtrProfile.Base, mGdtForAp, mExchangeInfo->GdtrProfile.Limit + 1);
394 CopyMem ((VOID *) mExchangeInfo->IdtrProfile.Base, mIdtForAp, mExchangeInfo->IdtrProfile.Limit + 1);
395 CopyMem ((VOID *)(UINTN) mAcpiCpuData.ApMachineCheckHandlerBase, mMachineCheckHandlerForAp, mAcpiCpuData.ApMachineCheckHandlerSize);
396
397 mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
398 mExchangeInfo->StackSize = mAcpiCpuData.StackSize;
399 mExchangeInfo->BufferStart = (UINT32) StartupVector;
400 mExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ());
401 }
402
403 /**
404 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
405
406 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
407 and restores MTRRs for both BSP and APs.
408
409 **/
410 VOID
411 EarlyInitializeCpu (
412 VOID
413 )
414 {
415 CPU_REGISTER_TABLE *RegisterTableList;
416 UINT32 InitApicId;
417 UINTN Index;
418
419 LoadMtrrData (mAcpiCpuData.MtrrTable);
420
421 //
422 // Find processor number for this CPU.
423 //
424 RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
425 InitApicId = GetInitialApicId ();
426 for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
427 if (RegisterTableList[Index].InitialApicId == InitApicId) {
428 SetProcessorRegister (&RegisterTableList[Index]);
429 break;
430 }
431 }
432
433 ProgramVirtualWireMode ();
434
435 PrepareApStartupVector (mAcpiCpuData.StartupVector);
436
437 mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
438 mExchangeInfo->ApFunction = (VOID *) (UINTN) EarlyMPRendezvousProcedure;
439
440 //
441 // Send INIT IPI - SIPI to all APs
442 //
443 SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
444
445 while (mNumberToFinish > 0) {
446 CpuPause ();
447 }
448 }
449
450 /**
451 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
452
453 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
454 data saved by normal boot path for both BSP and APs.
455
456 **/
457 VOID
458 InitializeCpu (
459 VOID
460 )
461 {
462 CPU_REGISTER_TABLE *RegisterTableList;
463 UINT32 InitApicId;
464 UINTN Index;
465
466 RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
467 InitApicId = GetInitialApicId ();
468 for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
469 if (RegisterTableList[Index].InitialApicId == InitApicId) {
470 SetProcessorRegister (&RegisterTableList[Index]);
471 break;
472 }
473 }
474
475 mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
476 //
477 // StackStart was updated when APs were waken up in EarlyInitializeCpu.
478 // Re-initialize StackAddress to original beginning address.
479 //
480 mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
481 mExchangeInfo->ApFunction = (VOID *) (UINTN) MPRendezvousProcedure;
482
483 //
484 // Send INIT IPI - SIPI to all APs
485 //
486 SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
487
488 while (mNumberToFinish > 0) {
489 CpuPause ();
490 }
491 }