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 // Spin lock used to serialize MemoryMapped operation
40 SPIN_LOCK
*mMemoryMappedLock
= NULL
;
43 Get starting address and size of the rendezvous entry for APs.
44 Information for fixing a jump instruction in the code is also returned.
46 @param AddressMap Output buffer for address map information.
51 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
54 #define LEGACY_REGION_SIZE (2 * 0x1000)
55 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
57 ACPI_CPU_DATA mAcpiCpuData
;
58 UINT32 mNumberToFinish
;
59 MP_CPU_EXCHANGE_INFO
*mExchangeInfo
;
60 BOOLEAN mRestoreSmmConfigurationInS3
= FALSE
;
61 VOID
*mGdtForAp
= NULL
;
62 VOID
*mIdtForAp
= NULL
;
63 VOID
*mMachineCheckHandlerForAp
= NULL
;
64 MP_MSR_LOCK
*mMsrSpinLocks
= NULL
;
65 UINTN mMsrSpinLockCount
;
69 Get MSR spin lock by MSR index.
71 @param MsrIndex MSR index value.
73 @return Pointer to MSR spin lock.
77 GetMsrSpinLockByIndex (
82 for (Index
= 0; Index
< mMsrCount
; Index
++) {
83 if (MsrIndex
== mMsrSpinLocks
[Index
].MsrIndex
) {
84 return mMsrSpinLocks
[Index
].SpinLock
;
91 Initialize MSR spin lock by MSR index.
93 @param MsrIndex MSR index value.
97 InitMsrSpinLockByIndex (
101 UINTN MsrSpinLockCount
;
102 UINTN NewMsrSpinLockCount
;
106 if (mMsrSpinLocks
== NULL
) {
107 MsrSpinLockCount
= mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
;
108 mMsrSpinLocks
= (MP_MSR_LOCK
*) AllocatePool (sizeof (MP_MSR_LOCK
) * MsrSpinLockCount
);
109 ASSERT (mMsrSpinLocks
!= NULL
);
110 for (Index
= 0; Index
< MsrSpinLockCount
; Index
++) {
111 mMsrSpinLocks
[Index
].SpinLock
=
112 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+ Index
* mSemaphoreSize
);
113 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
115 mMsrSpinLockCount
= MsrSpinLockCount
;
116 mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
= 0;
118 if (GetMsrSpinLockByIndex (MsrIndex
) == NULL
) {
120 // Initialize spin lock for MSR programming
122 mMsrSpinLocks
[mMsrCount
].MsrIndex
= MsrIndex
;
123 InitializeSpinLock (mMsrSpinLocks
[mMsrCount
].SpinLock
);
125 if (mMsrCount
== mMsrSpinLockCount
) {
127 // If MSR spin lock buffer is full, enlarge it
129 AddedSize
= SIZE_4KB
;
130 mSmmCpuSemaphores
.SemaphoreMsr
.Msr
=
131 AllocatePages (EFI_SIZE_TO_PAGES(AddedSize
));
132 ASSERT (mSmmCpuSemaphores
.SemaphoreMsr
.Msr
!= NULL
);
133 NewMsrSpinLockCount
= mMsrSpinLockCount
+ AddedSize
/ mSemaphoreSize
;
134 mMsrSpinLocks
= ReallocatePool (
135 sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
,
136 sizeof (MP_MSR_LOCK
) * NewMsrSpinLockCount
,
139 ASSERT (mMsrSpinLocks
!= NULL
);
140 mMsrSpinLockCount
= NewMsrSpinLockCount
;
141 for (Index
= mMsrCount
; Index
< mMsrSpinLockCount
; Index
++) {
142 mMsrSpinLocks
[Index
].SpinLock
=
143 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+
144 (Index
- mMsrCount
) * mSemaphoreSize
);
145 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
152 Sync up the MTRR values for all processors.
154 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
159 EFI_PHYSICAL_ADDRESS MtrrTable
165 Sync up the MTRR values for all processors.
174 MTRR_SETTINGS
*MtrrSettings
;
176 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
177 MtrrSetAllMtrrs (MtrrSettings
);
181 Programs registers for the calling processor.
183 This function programs registers for the calling processor.
185 @param RegisterTable Pointer to register table of the running processor.
189 SetProcessorRegister (
190 IN CPU_REGISTER_TABLE
*RegisterTable
193 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
196 SPIN_LOCK
*MsrSpinLock
;
199 // Traverse Register Table of this logical processor
201 RegisterTableEntry
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
202 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++, RegisterTableEntry
++) {
204 // Check the type of specified register
206 switch (RegisterTableEntry
->RegisterType
) {
208 // The specified register is Control Register
210 case ControlRegister
:
211 switch (RegisterTableEntry
->Index
) {
213 Value
= AsmReadCr0 ();
214 Value
= (UINTN
) BitFieldWrite64 (
216 RegisterTableEntry
->ValidBitStart
,
217 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
218 (UINTN
) RegisterTableEntry
->Value
223 Value
= AsmReadCr2 ();
224 Value
= (UINTN
) BitFieldWrite64 (
226 RegisterTableEntry
->ValidBitStart
,
227 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
228 (UINTN
) RegisterTableEntry
->Value
233 Value
= AsmReadCr3 ();
234 Value
= (UINTN
) BitFieldWrite64 (
236 RegisterTableEntry
->ValidBitStart
,
237 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
238 (UINTN
) RegisterTableEntry
->Value
243 Value
= AsmReadCr4 ();
244 Value
= (UINTN
) BitFieldWrite64 (
246 RegisterTableEntry
->ValidBitStart
,
247 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
248 (UINTN
) RegisterTableEntry
->Value
257 // The specified register is Model Specific Register
261 // If this function is called to restore register setting after INIT signal,
262 // there is no need to restore MSRs in register table.
264 if (RegisterTableEntry
->ValidBitLength
>= 64) {
266 // If length is not less than 64 bits, then directly write without reading
269 RegisterTableEntry
->Index
,
270 RegisterTableEntry
->Value
274 // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
275 // to make sure MSR read/write operation is atomic.
277 MsrSpinLock
= GetMsrSpinLockByIndex (RegisterTableEntry
->Index
);
278 AcquireSpinLock (MsrSpinLock
);
280 // Set the bit section according to bit start and length
282 AsmMsrBitFieldWrite64 (
283 RegisterTableEntry
->Index
,
284 RegisterTableEntry
->ValidBitStart
,
285 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
286 RegisterTableEntry
->Value
288 ReleaseSpinLock (MsrSpinLock
);
292 // MemoryMapped operations
295 AcquireSpinLock (mMemoryMappedLock
);
296 MmioBitFieldWrite32 (
297 RegisterTableEntry
->Index
,
298 RegisterTableEntry
->ValidBitStart
,
299 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
300 (UINT32
)RegisterTableEntry
->Value
302 ReleaseSpinLock (mMemoryMappedLock
);
305 // Enable or disable cache
309 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
311 if (RegisterTableEntry
->Value
== 0) {
325 AP initialization before SMBASE relocation in the S3 boot path.
328 EarlyMPRendezvousProcedure (
332 CPU_REGISTER_TABLE
*RegisterTableList
;
336 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
339 // Find processor number for this CPU.
341 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
342 InitApicId
= GetInitialApicId ();
343 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
344 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
345 SetProcessorRegister (&RegisterTableList
[Index
]);
351 // Count down the number with lock mechanism.
353 InterlockedDecrement (&mNumberToFinish
);
357 AP initialization after SMBASE relocation in the S3 boot path.
360 MPRendezvousProcedure (
364 CPU_REGISTER_TABLE
*RegisterTableList
;
368 ProgramVirtualWireMode ();
369 DisableLvtInterrupts ();
371 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
372 InitApicId
= GetInitialApicId ();
373 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
374 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
375 SetProcessorRegister (&RegisterTableList
[Index
]);
381 // Count down the number with lock mechanism.
383 InterlockedDecrement (&mNumberToFinish
);
387 Prepares startup vector for APs.
389 This function prepares startup vector for APs.
391 @param WorkingBuffer The address of the work buffer.
394 PrepareApStartupVector (
395 EFI_PHYSICAL_ADDRESS WorkingBuffer
398 EFI_PHYSICAL_ADDRESS StartupVector
;
399 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
402 // Get the address map of startup code for AP,
403 // including code size, and offset of long jump instructions to redirect.
405 ZeroMem (&AddressMap
, sizeof (AddressMap
));
406 AsmGetAddressMap (&AddressMap
);
408 StartupVector
= WorkingBuffer
;
411 // Copy AP startup code to startup vector, and then redirect the long jump
412 // instructions for mode switching.
414 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
415 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
416 if (AddressMap
.LongJumpOffset
!= 0) {
417 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
421 // Get the start address of exchange data between BSP and AP.
423 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
424 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
426 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
427 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
430 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
432 CopyMem ((VOID
*) mExchangeInfo
->GdtrProfile
.Base
, mGdtForAp
, mExchangeInfo
->GdtrProfile
.Limit
+ 1);
433 CopyMem ((VOID
*) mExchangeInfo
->IdtrProfile
.Base
, mIdtForAp
, mExchangeInfo
->IdtrProfile
.Limit
+ 1);
434 CopyMem ((VOID
*)(UINTN
) mAcpiCpuData
.ApMachineCheckHandlerBase
, mMachineCheckHandlerForAp
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
436 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
437 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
438 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
439 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
443 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
445 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
446 and restores MTRRs for both BSP and APs.
454 CPU_REGISTER_TABLE
*RegisterTableList
;
458 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
461 // Find processor number for this CPU.
463 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
464 InitApicId
= GetInitialApicId ();
465 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
466 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
467 SetProcessorRegister (&RegisterTableList
[Index
]);
472 ProgramVirtualWireMode ();
474 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
476 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
477 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) EarlyMPRendezvousProcedure
;
480 // Send INIT IPI - SIPI to all APs
482 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
484 while (mNumberToFinish
> 0) {
490 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
492 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
493 data saved by normal boot path for both BSP and APs.
501 CPU_REGISTER_TABLE
*RegisterTableList
;
505 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
506 InitApicId
= GetInitialApicId ();
507 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
508 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
509 SetProcessorRegister (&RegisterTableList
[Index
]);
514 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
516 // StackStart was updated when APs were waken up in EarlyInitializeCpu.
517 // Re-initialize StackAddress to original beginning address.
519 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
520 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) MPRendezvousProcedure
;
523 // Send INIT IPI - SIPI to all APs
525 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
527 while (mNumberToFinish
> 0) {