2 Code for Processor S3 restoration
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
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.
15 #include "PiSmmCpuDxeSmm.h"
22 IA32_DESCRIPTOR GdtrProfile
;
23 IA32_DESCRIPTOR IdtrProfile
;
26 } MP_CPU_EXCHANGE_INFO
;
29 UINT8
*RendezvousFunnelAddress
;
30 UINTN PModeEntryOffset
;
33 UINTN LModeEntryOffset
;
35 } MP_ASSEMBLY_ADDRESS_MAP
;
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.
41 @param AddressMap Output buffer for address map information.
46 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
49 #define LEGACY_REGION_SIZE (2 * 0x1000)
50 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
51 #define MSR_SPIN_LOCK_INIT_NUM 15
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
;
65 Get MSR spin lock by MSR index.
67 @param MsrIndex MSR index value.
69 @return Pointer to MSR spin lock.
73 GetMsrSpinLockByIndex (
78 for (Index
= 0; Index
< mMsrCount
; Index
++) {
79 if (MsrIndex
== mMsrSpinLocks
[Index
].MsrIndex
) {
80 return &mMsrSpinLocks
[Index
].SpinLock
;
87 Initialize MSR spin lock by MSR index.
89 @param MsrIndex MSR index value.
93 InitMsrSpinLockByIndex (
97 UINTN NewMsrSpinLockCount
;
99 if (mMsrSpinLocks
== NULL
) {
100 mMsrSpinLocks
= (MP_MSR_LOCK
*) AllocatePool (sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
);
101 ASSERT (mMsrSpinLocks
!= NULL
);
103 if (GetMsrSpinLockByIndex (MsrIndex
) == NULL
) {
105 // Initialize spin lock for MSR programming
107 mMsrSpinLocks
[mMsrCount
].MsrIndex
= MsrIndex
;
108 InitializeSpinLock (&mMsrSpinLocks
[mMsrCount
].SpinLock
);
110 if (mMsrCount
== mMsrSpinLockCount
) {
112 // If MSR spin lock buffer is full, enlarge it
114 NewMsrSpinLockCount
= mMsrSpinLockCount
+ MSR_SPIN_LOCK_INIT_NUM
;
115 mMsrSpinLocks
= ReallocatePool (
116 sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
,
117 sizeof (MP_MSR_LOCK
) * NewMsrSpinLockCount
,
120 mMsrSpinLockCount
= NewMsrSpinLockCount
;
126 Sync up the MTRR values for all processors.
128 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
133 EFI_PHYSICAL_ADDRESS MtrrTable
139 Sync up the MTRR values for all processors.
148 MTRR_SETTINGS
*MtrrSettings
;
150 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
151 MtrrSetAllMtrrs (MtrrSettings
);
155 Programs registers for the calling processor.
157 This function programs registers for the calling processor.
159 @param RegisterTable Pointer to register table of the running processor.
163 SetProcessorRegister (
164 IN CPU_REGISTER_TABLE
*RegisterTable
167 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
170 SPIN_LOCK
*MsrSpinLock
;
173 // Traverse Register Table of this logical processor
175 RegisterTableEntry
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
176 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++, RegisterTableEntry
++) {
178 // Check the type of specified register
180 switch (RegisterTableEntry
->RegisterType
) {
182 // The specified register is Control Register
184 case ControlRegister
:
185 switch (RegisterTableEntry
->Index
) {
187 Value
= AsmReadCr0 ();
188 Value
= (UINTN
) BitFieldWrite64 (
190 RegisterTableEntry
->ValidBitStart
,
191 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
192 (UINTN
) RegisterTableEntry
->Value
197 Value
= AsmReadCr2 ();
198 Value
= (UINTN
) BitFieldWrite64 (
200 RegisterTableEntry
->ValidBitStart
,
201 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
202 (UINTN
) RegisterTableEntry
->Value
207 Value
= AsmReadCr3 ();
208 Value
= (UINTN
) BitFieldWrite64 (
210 RegisterTableEntry
->ValidBitStart
,
211 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
212 (UINTN
) RegisterTableEntry
->Value
217 Value
= AsmReadCr4 ();
218 Value
= (UINTN
) BitFieldWrite64 (
220 RegisterTableEntry
->ValidBitStart
,
221 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
222 (UINTN
) RegisterTableEntry
->Value
231 // The specified register is Model Specific Register
235 // If this function is called to restore register setting after INIT signal,
236 // there is no need to restore MSRs in register table.
238 if (RegisterTableEntry
->ValidBitLength
>= 64) {
240 // If length is not less than 64 bits, then directly write without reading
243 RegisterTableEntry
->Index
,
244 RegisterTableEntry
->Value
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.
251 MsrSpinLock
= GetMsrSpinLockByIndex (RegisterTableEntry
->Index
);
252 AcquireSpinLock (MsrSpinLock
);
254 // Set the bit section according to bit start and length
256 AsmMsrBitFieldWrite64 (
257 RegisterTableEntry
->Index
,
258 RegisterTableEntry
->ValidBitStart
,
259 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
260 RegisterTableEntry
->Value
262 ReleaseSpinLock (MsrSpinLock
);
266 // Enable or disable cache
270 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
272 if (RegisterTableEntry
->Value
== 0) {
286 AP initialization before SMBASE relocation in the S3 boot path.
289 EarlyMPRendezvousProcedure (
293 CPU_REGISTER_TABLE
*RegisterTableList
;
297 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
300 // Find processor number for this CPU.
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
]);
312 // Count down the number with lock mechanism.
314 InterlockedDecrement (&mNumberToFinish
);
318 AP initialization after SMBASE relocation in the S3 boot path.
321 MPRendezvousProcedure (
325 CPU_REGISTER_TABLE
*RegisterTableList
;
329 ProgramVirtualWireMode ();
330 DisableLvtInterrupts ();
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
]);
342 // Count down the number with lock mechanism.
344 InterlockedDecrement (&mNumberToFinish
);
348 Prepares startup vector for APs.
350 This function prepares startup vector for APs.
352 @param WorkingBuffer The address of the work buffer.
355 PrepareApStartupVector (
356 EFI_PHYSICAL_ADDRESS WorkingBuffer
359 EFI_PHYSICAL_ADDRESS StartupVector
;
360 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
363 // Get the address map of startup code for AP,
364 // including code size, and offset of long jump instructions to redirect.
366 ZeroMem (&AddressMap
, sizeof (AddressMap
));
367 AsmGetAddressMap (&AddressMap
);
369 StartupVector
= WorkingBuffer
;
372 // Copy AP startup code to startup vector, and then redirect the long jump
373 // instructions for mode switching.
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
);
382 // Get the start address of exchange data between BSP and AP.
384 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
385 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
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
));
391 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
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
);
397 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
398 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
399 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
400 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
404 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
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.
415 CPU_REGISTER_TABLE
*RegisterTableList
;
419 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
422 // Find processor number for this CPU.
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
]);
433 ProgramVirtualWireMode ();
435 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
437 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
438 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) EarlyMPRendezvousProcedure
;
441 // Send INIT IPI - SIPI to all APs
443 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
445 while (mNumberToFinish
> 0) {
451 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
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.
462 CPU_REGISTER_TABLE
*RegisterTableList
;
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
]);
475 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
477 // StackStart was updated when APs were waken up in EarlyInitializeCpu.
478 // Re-initialize StackAddress to original beginning address.
480 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
481 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) MPRendezvousProcedure
;
484 // Send INIT IPI - SIPI to all APs
486 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
488 while (mNumberToFinish
> 0) {