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
= MSR_SPIN_LOCK_INIT_NUM
;
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 NewMsrSpinLockCount
;
98 if (mMsrSpinLocks
== NULL
) {
99 mMsrSpinLocks
= (MP_MSR_LOCK
*) AllocatePool (sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
);
100 ASSERT (mMsrSpinLocks
!= NULL
);
102 if (GetMsrSpinLockByIndex (MsrIndex
) == NULL
) {
104 // Initialize spin lock for MSR programming
106 mMsrSpinLocks
[mMsrCount
].MsrIndex
= MsrIndex
;
107 InitializeSpinLock (&mMsrSpinLocks
[mMsrCount
].SpinLock
);
109 if (mMsrCount
== mMsrSpinLockCount
) {
111 // If MSR spin lock buffer is full, enlarge it
113 NewMsrSpinLockCount
= mMsrSpinLockCount
+ MSR_SPIN_LOCK_INIT_NUM
;
114 mMsrSpinLocks
= ReallocatePool (
115 sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
,
116 sizeof (MP_MSR_LOCK
) * NewMsrSpinLockCount
,
119 mMsrSpinLockCount
= NewMsrSpinLockCount
;
125 Sync up the MTRR values for all processors.
127 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
132 EFI_PHYSICAL_ADDRESS MtrrTable
138 Sync up the MTRR values for all processors.
147 MTRR_SETTINGS
*MtrrSettings
;
149 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
150 MtrrSetAllMtrrs (MtrrSettings
);
154 Programs registers for the calling processor.
156 This function programs registers for the calling processor.
158 @param RegisterTable Pointer to register table of the running processor.
162 SetProcessorRegister (
163 IN CPU_REGISTER_TABLE
*RegisterTable
166 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
169 SPIN_LOCK
*MsrSpinLock
;
172 // Traverse Register Table of this logical processor
174 RegisterTableEntry
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
175 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++, RegisterTableEntry
++) {
177 // Check the type of specified register
179 switch (RegisterTableEntry
->RegisterType
) {
181 // The specified register is Control Register
183 case ControlRegister
:
184 switch (RegisterTableEntry
->Index
) {
186 Value
= AsmReadCr0 ();
187 Value
= (UINTN
) BitFieldWrite64 (
189 RegisterTableEntry
->ValidBitStart
,
190 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
191 (UINTN
) RegisterTableEntry
->Value
196 Value
= AsmReadCr2 ();
197 Value
= (UINTN
) BitFieldWrite64 (
199 RegisterTableEntry
->ValidBitStart
,
200 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
201 (UINTN
) RegisterTableEntry
->Value
206 Value
= AsmReadCr3 ();
207 Value
= (UINTN
) BitFieldWrite64 (
209 RegisterTableEntry
->ValidBitStart
,
210 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
211 (UINTN
) RegisterTableEntry
->Value
216 Value
= AsmReadCr4 ();
217 Value
= (UINTN
) BitFieldWrite64 (
219 RegisterTableEntry
->ValidBitStart
,
220 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
221 (UINTN
) RegisterTableEntry
->Value
230 // The specified register is Model Specific Register
234 // If this function is called to restore register setting after INIT signal,
235 // there is no need to restore MSRs in register table.
237 if (RegisterTableEntry
->ValidBitLength
>= 64) {
239 // If length is not less than 64 bits, then directly write without reading
242 RegisterTableEntry
->Index
,
243 RegisterTableEntry
->Value
247 // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
248 // to make sure MSR read/write operation is atomic.
250 MsrSpinLock
= GetMsrSpinLockByIndex (RegisterTableEntry
->Index
);
251 AcquireSpinLock (MsrSpinLock
);
253 // Set the bit section according to bit start and length
255 AsmMsrBitFieldWrite64 (
256 RegisterTableEntry
->Index
,
257 RegisterTableEntry
->ValidBitStart
,
258 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
259 RegisterTableEntry
->Value
261 ReleaseSpinLock (MsrSpinLock
);
265 // Enable or disable cache
269 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
271 if (RegisterTableEntry
->Value
== 0) {
285 AP initialization before SMBASE relocation in the S3 boot path.
288 EarlyMPRendezvousProcedure (
292 CPU_REGISTER_TABLE
*RegisterTableList
;
296 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
299 // Find processor number for this CPU.
301 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
302 InitApicId
= GetInitialApicId ();
303 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
304 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
305 SetProcessorRegister (&RegisterTableList
[Index
]);
311 // Count down the number with lock mechanism.
313 InterlockedDecrement (&mNumberToFinish
);
317 AP initialization after SMBASE relocation in the S3 boot path.
320 MPRendezvousProcedure (
324 CPU_REGISTER_TABLE
*RegisterTableList
;
328 ProgramVirtualWireMode ();
329 DisableLvtInterrupts ();
331 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
332 InitApicId
= GetInitialApicId ();
333 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
334 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
335 SetProcessorRegister (&RegisterTableList
[Index
]);
341 // Count down the number with lock mechanism.
343 InterlockedDecrement (&mNumberToFinish
);
347 Prepares startup vector for APs.
349 This function prepares startup vector for APs.
351 @param WorkingBuffer The address of the work buffer.
354 PrepareApStartupVector (
355 EFI_PHYSICAL_ADDRESS WorkingBuffer
358 EFI_PHYSICAL_ADDRESS StartupVector
;
359 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
362 // Get the address map of startup code for AP,
363 // including code size, and offset of long jump instructions to redirect.
365 ZeroMem (&AddressMap
, sizeof (AddressMap
));
366 AsmGetAddressMap (&AddressMap
);
368 StartupVector
= WorkingBuffer
;
371 // Copy AP startup code to startup vector, and then redirect the long jump
372 // instructions for mode switching.
374 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
375 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
376 if (AddressMap
.LongJumpOffset
!= 0) {
377 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
381 // Get the start address of exchange data between BSP and AP.
383 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
384 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
386 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
387 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
390 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
392 CopyMem ((VOID
*) mExchangeInfo
->GdtrProfile
.Base
, mGdtForAp
, mExchangeInfo
->GdtrProfile
.Limit
+ 1);
393 CopyMem ((VOID
*) mExchangeInfo
->IdtrProfile
.Base
, mIdtForAp
, mExchangeInfo
->IdtrProfile
.Limit
+ 1);
394 CopyMem ((VOID
*)(UINTN
) mAcpiCpuData
.ApMachineCheckHandlerBase
, mMachineCheckHandlerForAp
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
396 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
397 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
398 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
399 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
403 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
405 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
406 and restores MTRRs for both BSP and APs.
414 CPU_REGISTER_TABLE
*RegisterTableList
;
418 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
421 // Find processor number for this CPU.
423 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
424 InitApicId
= GetInitialApicId ();
425 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
426 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
427 SetProcessorRegister (&RegisterTableList
[Index
]);
432 ProgramVirtualWireMode ();
434 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
436 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
437 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) EarlyMPRendezvousProcedure
;
440 // Send INIT IPI - SIPI to all APs
442 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
444 while (mNumberToFinish
> 0) {
450 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
452 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
453 data saved by normal boot path for both BSP and APs.
461 CPU_REGISTER_TABLE
*RegisterTableList
;
465 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
466 InitApicId
= GetInitialApicId ();
467 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
468 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
469 SetProcessorRegister (&RegisterTableList
[Index
]);
474 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
476 // StackStart was updated when APs were waken up in EarlyInitializeCpu.
477 // Re-initialize StackAddress to original beginning address.
479 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
480 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) MPRendezvousProcedure
;
483 // Send INIT IPI - SIPI to all APs
485 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
487 while (mNumberToFinish
> 0) {