2 Code for Processor S3 restoration
4 Copyright (c) 2006 - 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
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)
52 ACPI_CPU_DATA mAcpiCpuData
;
53 UINT32 mNumberToFinish
;
54 MP_CPU_EXCHANGE_INFO
*mExchangeInfo
;
55 BOOLEAN mRestoreSmmConfigurationInS3
= FALSE
;
56 VOID
*mGdtForAp
= NULL
;
57 VOID
*mIdtForAp
= NULL
;
58 VOID
*mMachineCheckHandlerForAp
= NULL
;
59 MP_MSR_LOCK
*mMsrSpinLocks
= NULL
;
60 UINTN mMsrSpinLockCount
;
64 Get MSR spin lock by MSR index.
66 @param MsrIndex MSR index value.
68 @return Pointer to MSR spin lock.
72 GetMsrSpinLockByIndex (
77 for (Index
= 0; Index
< mMsrCount
; Index
++) {
78 if (MsrIndex
== mMsrSpinLocks
[Index
].MsrIndex
) {
79 return mMsrSpinLocks
[Index
].SpinLock
;
86 Initialize MSR spin lock by MSR index.
88 @param MsrIndex MSR index value.
92 InitMsrSpinLockByIndex (
96 UINTN MsrSpinLockCount
;
97 UINTN NewMsrSpinLockCount
;
101 if (mMsrSpinLocks
== NULL
) {
102 MsrSpinLockCount
= mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
;
103 mMsrSpinLocks
= (MP_MSR_LOCK
*) AllocatePool (sizeof (MP_MSR_LOCK
) * MsrSpinLockCount
);
104 ASSERT (mMsrSpinLocks
!= NULL
);
105 for (Index
= 0; Index
< MsrSpinLockCount
; Index
++) {
106 mMsrSpinLocks
[Index
].SpinLock
=
107 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+ Index
* mSemaphoreSize
);
108 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
110 mMsrSpinLockCount
= MsrSpinLockCount
;
111 mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
= 0;
113 if (GetMsrSpinLockByIndex (MsrIndex
) == NULL
) {
115 // Initialize spin lock for MSR programming
117 mMsrSpinLocks
[mMsrCount
].MsrIndex
= MsrIndex
;
118 InitializeSpinLock (mMsrSpinLocks
[mMsrCount
].SpinLock
);
120 if (mMsrCount
== mMsrSpinLockCount
) {
122 // If MSR spin lock buffer is full, enlarge it
124 AddedSize
= SIZE_4KB
;
125 mSmmCpuSemaphores
.SemaphoreMsr
.Msr
=
126 AllocatePages (EFI_SIZE_TO_PAGES(AddedSize
));
127 ASSERT (mSmmCpuSemaphores
.SemaphoreMsr
.Msr
!= NULL
);
128 NewMsrSpinLockCount
= mMsrSpinLockCount
+ AddedSize
/ mSemaphoreSize
;
129 mMsrSpinLocks
= ReallocatePool (
130 sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
,
131 sizeof (MP_MSR_LOCK
) * NewMsrSpinLockCount
,
134 ASSERT (mMsrSpinLocks
!= NULL
);
135 mMsrSpinLockCount
= NewMsrSpinLockCount
;
136 for (Index
= mMsrCount
; Index
< mMsrSpinLockCount
; Index
++) {
137 mMsrSpinLocks
[Index
].SpinLock
=
138 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+
139 (Index
- mMsrCount
) * mSemaphoreSize
);
140 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
147 Sync up the MTRR values for all processors.
149 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
154 EFI_PHYSICAL_ADDRESS MtrrTable
160 Sync up the MTRR values for all processors.
169 MTRR_SETTINGS
*MtrrSettings
;
171 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
172 MtrrSetAllMtrrs (MtrrSettings
);
176 Programs registers for the calling processor.
178 This function programs registers for the calling processor.
180 @param RegisterTable Pointer to register table of the running processor.
184 SetProcessorRegister (
185 IN CPU_REGISTER_TABLE
*RegisterTable
188 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
191 SPIN_LOCK
*MsrSpinLock
;
194 // Traverse Register Table of this logical processor
196 RegisterTableEntry
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
197 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++, RegisterTableEntry
++) {
199 // Check the type of specified register
201 switch (RegisterTableEntry
->RegisterType
) {
203 // The specified register is Control Register
205 case ControlRegister
:
206 switch (RegisterTableEntry
->Index
) {
208 Value
= AsmReadCr0 ();
209 Value
= (UINTN
) BitFieldWrite64 (
211 RegisterTableEntry
->ValidBitStart
,
212 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
213 (UINTN
) RegisterTableEntry
->Value
218 Value
= AsmReadCr2 ();
219 Value
= (UINTN
) BitFieldWrite64 (
221 RegisterTableEntry
->ValidBitStart
,
222 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
223 (UINTN
) RegisterTableEntry
->Value
228 Value
= AsmReadCr3 ();
229 Value
= (UINTN
) BitFieldWrite64 (
231 RegisterTableEntry
->ValidBitStart
,
232 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
233 (UINTN
) RegisterTableEntry
->Value
238 Value
= AsmReadCr4 ();
239 Value
= (UINTN
) BitFieldWrite64 (
241 RegisterTableEntry
->ValidBitStart
,
242 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
243 (UINTN
) RegisterTableEntry
->Value
252 // The specified register is Model Specific Register
256 // If this function is called to restore register setting after INIT signal,
257 // there is no need to restore MSRs in register table.
259 if (RegisterTableEntry
->ValidBitLength
>= 64) {
261 // If length is not less than 64 bits, then directly write without reading
264 RegisterTableEntry
->Index
,
265 RegisterTableEntry
->Value
269 // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
270 // to make sure MSR read/write operation is atomic.
272 MsrSpinLock
= GetMsrSpinLockByIndex (RegisterTableEntry
->Index
);
273 AcquireSpinLock (MsrSpinLock
);
275 // Set the bit section according to bit start and length
277 AsmMsrBitFieldWrite64 (
278 RegisterTableEntry
->Index
,
279 RegisterTableEntry
->ValidBitStart
,
280 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
281 RegisterTableEntry
->Value
283 ReleaseSpinLock (MsrSpinLock
);
287 // Enable or disable cache
291 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
293 if (RegisterTableEntry
->Value
== 0) {
307 AP initialization before SMBASE relocation in the S3 boot path.
310 EarlyMPRendezvousProcedure (
314 CPU_REGISTER_TABLE
*RegisterTableList
;
318 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
321 // Find processor number for this CPU.
323 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
324 InitApicId
= GetInitialApicId ();
325 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
326 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
327 SetProcessorRegister (&RegisterTableList
[Index
]);
333 // Count down the number with lock mechanism.
335 InterlockedDecrement (&mNumberToFinish
);
339 AP initialization after SMBASE relocation in the S3 boot path.
342 MPRendezvousProcedure (
346 CPU_REGISTER_TABLE
*RegisterTableList
;
350 ProgramVirtualWireMode ();
351 DisableLvtInterrupts ();
353 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
354 InitApicId
= GetInitialApicId ();
355 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
356 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
357 SetProcessorRegister (&RegisterTableList
[Index
]);
363 // Count down the number with lock mechanism.
365 InterlockedDecrement (&mNumberToFinish
);
369 Prepares startup vector for APs.
371 This function prepares startup vector for APs.
373 @param WorkingBuffer The address of the work buffer.
376 PrepareApStartupVector (
377 EFI_PHYSICAL_ADDRESS WorkingBuffer
380 EFI_PHYSICAL_ADDRESS StartupVector
;
381 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
384 // Get the address map of startup code for AP,
385 // including code size, and offset of long jump instructions to redirect.
387 ZeroMem (&AddressMap
, sizeof (AddressMap
));
388 AsmGetAddressMap (&AddressMap
);
390 StartupVector
= WorkingBuffer
;
393 // Copy AP startup code to startup vector, and then redirect the long jump
394 // instructions for mode switching.
396 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
397 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
398 if (AddressMap
.LongJumpOffset
!= 0) {
399 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
403 // Get the start address of exchange data between BSP and AP.
405 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
406 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
408 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
409 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
412 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
414 CopyMem ((VOID
*) mExchangeInfo
->GdtrProfile
.Base
, mGdtForAp
, mExchangeInfo
->GdtrProfile
.Limit
+ 1);
415 CopyMem ((VOID
*) mExchangeInfo
->IdtrProfile
.Base
, mIdtForAp
, mExchangeInfo
->IdtrProfile
.Limit
+ 1);
416 CopyMem ((VOID
*)(UINTN
) mAcpiCpuData
.ApMachineCheckHandlerBase
, mMachineCheckHandlerForAp
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
418 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
419 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
420 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
421 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
425 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
427 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
428 and restores MTRRs for both BSP and APs.
436 CPU_REGISTER_TABLE
*RegisterTableList
;
440 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
443 // Find processor number for this CPU.
445 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
446 InitApicId
= GetInitialApicId ();
447 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
448 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
449 SetProcessorRegister (&RegisterTableList
[Index
]);
454 ProgramVirtualWireMode ();
456 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
458 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
459 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) EarlyMPRendezvousProcedure
;
462 // Send INIT IPI - SIPI to all APs
464 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
466 while (mNumberToFinish
> 0) {
472 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
474 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
475 data saved by normal boot path for both BSP and APs.
483 CPU_REGISTER_TABLE
*RegisterTableList
;
487 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
488 InitApicId
= GetInitialApicId ();
489 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
490 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
491 SetProcessorRegister (&RegisterTableList
[Index
]);
496 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
498 // StackStart was updated when APs were waken up in EarlyInitializeCpu.
499 // Re-initialize StackAddress to original beginning address.
501 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
502 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) MPRendezvousProcedure
;
505 // Send INIT IPI - SIPI to all APs
507 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
509 while (mNumberToFinish
> 0) {