2 Code for Processor S3 restoration
4 Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "PiSmmCpuDxeSmm.h"
17 IA32_DESCRIPTOR GdtrProfile
;
18 IA32_DESCRIPTOR IdtrProfile
;
21 UINTN InitializeFloatingPointUnitsAddress
;
22 } MP_CPU_EXCHANGE_INFO
;
26 UINT8
*RendezvousFunnelAddress
;
27 UINTN PModeEntryOffset
;
30 UINTN LModeEntryOffset
;
32 } MP_ASSEMBLY_ADDRESS_MAP
;
35 // Flags used when program the register.
38 volatile UINTN MemoryMappedLock
; // Spinlock used to program mmio
39 volatile UINT32
*CoreSemaphoreCount
; // Semaphore container used to program
40 // core level semaphore.
41 volatile UINT32
*PackageSemaphoreCount
; // Semaphore container used to program
42 // package level semaphore.
43 } PROGRAM_CPU_REGISTER_FLAGS
;
46 // Signal that SMM BASE relocation is complete.
48 volatile BOOLEAN mInitApsAfterSmmBaseReloc
;
51 Get starting address and size of the rendezvous entry for APs.
52 Information for fixing a jump instruction in the code is also returned.
54 @param AddressMap Output buffer for address map information.
59 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
62 #define LEGACY_REGION_SIZE (2 * 0x1000)
63 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
65 PROGRAM_CPU_REGISTER_FLAGS mCpuFlags
;
66 ACPI_CPU_DATA mAcpiCpuData
;
67 volatile UINT32 mNumberToFinish
;
68 MP_CPU_EXCHANGE_INFO
*mExchangeInfo
;
69 BOOLEAN mRestoreSmmConfigurationInS3
= FALSE
;
74 BOOLEAN mSmmS3Flag
= FALSE
;
77 // Pointer to structure used during S3 Resume
79 SMM_S3_RESUME_STATE
*mSmmS3ResumeState
= NULL
;
81 BOOLEAN mAcpiS3Enable
= TRUE
;
83 UINT8
*mApHltLoopCode
= NULL
;
84 UINT8 mApHltLoopCodeTemplate
[] = {
85 0x8B, 0x44, 0x24, 0x04, // mov eax, dword ptr [esp+4]
86 0xF0, 0xFF, 0x08, // lock dec dword ptr [eax]
93 Sync up the MTRR values for all processors.
95 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
100 EFI_PHYSICAL_ADDRESS MtrrTable
106 Sync up the MTRR values for all processors.
115 MTRR_SETTINGS
*MtrrSettings
;
117 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
118 MtrrSetAllMtrrs (MtrrSettings
);
122 Increment semaphore by 1.
124 @param Sem IN: 32-bit unsigned integer
129 IN OUT
volatile UINT32
*Sem
132 InterlockedIncrement (Sem
);
136 Decrement the semaphore by 1 if it is not zero.
138 Performs an atomic decrement operation for semaphore.
139 The compare exchange operation must be performed using
142 @param Sem IN: 32-bit unsigned integer
147 IN OUT
volatile UINT32
*Sem
154 } while (Value
== 0 ||
155 InterlockedCompareExchange32 (
163 Read / write CR value.
165 @param[in] CrIndex The CR index which need to read/write.
166 @param[in] Read Read or write. TRUE is read.
167 @param[in,out] CrValue CR value.
169 @retval EFI_SUCCESS means read/write success, else return EFI_UNSUPPORTED.
175 IN OUT UINTN
*CrValue
181 *CrValue
= AsmReadCr0 ();
183 AsmWriteCr0 (*CrValue
);
188 *CrValue
= AsmReadCr2 ();
190 AsmWriteCr2 (*CrValue
);
195 *CrValue
= AsmReadCr3 ();
197 AsmWriteCr3 (*CrValue
);
202 *CrValue
= AsmReadCr4 ();
204 AsmWriteCr4 (*CrValue
);
208 return EFI_UNSUPPORTED
;;
215 Initialize the CPU registers from a register table.
217 @param[in] RegisterTable The register table for this AP.
218 @param[in] ApLocation AP location info for this ap.
219 @param[in] CpuStatus CPU status info for this CPU.
220 @param[in] CpuFlags Flags data structure used when program the register.
222 @note This service could be called by BSP/APs.
225 ProgramProcessorRegister (
226 IN CPU_REGISTER_TABLE
*RegisterTable
,
227 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
228 IN CPU_STATUS_INFORMATION
*CpuStatus
,
229 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
232 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
235 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
236 volatile UINT32
*SemaphorePtr
;
238 UINT32 CurrentThread
;
240 UINTN ProcessorIndex
;
241 UINT32
*ThreadCountPerPackage
;
242 UINT8
*ThreadCountPerCore
;
247 // Traverse Register Table of this logical processor
249 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
251 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
253 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
256 // Check the type of specified register
258 switch (RegisterTableEntry
->RegisterType
) {
260 // The specified register is Control Register
262 case ControlRegister
:
263 Status
= ReadWriteCr (RegisterTableEntry
->Index
, TRUE
, &Value
);
264 if (EFI_ERROR (Status
)) {
267 if (RegisterTableEntry
->TestThenWrite
) {
268 CurrentValue
= BitFieldRead64 (
270 RegisterTableEntry
->ValidBitStart
,
271 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1
273 if (CurrentValue
== RegisterTableEntry
->Value
) {
277 Value
= (UINTN
) BitFieldWrite64 (
279 RegisterTableEntry
->ValidBitStart
,
280 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
281 RegisterTableEntry
->Value
283 ReadWriteCr (RegisterTableEntry
->Index
, FALSE
, &Value
);
286 // The specified register is Model Specific Register
289 if (RegisterTableEntry
->TestThenWrite
) {
290 Value
= (UINTN
)AsmReadMsr64 (RegisterTableEntry
->Index
);
291 if (RegisterTableEntry
->ValidBitLength
>= 64) {
292 if (Value
== RegisterTableEntry
->Value
) {
296 CurrentValue
= BitFieldRead64 (
298 RegisterTableEntry
->ValidBitStart
,
299 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1
301 if (CurrentValue
== RegisterTableEntry
->Value
) {
308 // If this function is called to restore register setting after INIT signal,
309 // there is no need to restore MSRs in register table.
311 if (RegisterTableEntry
->ValidBitLength
>= 64) {
313 // If length is not less than 64 bits, then directly write without reading
316 RegisterTableEntry
->Index
,
317 RegisterTableEntry
->Value
321 // Set the bit section according to bit start and length
323 AsmMsrBitFieldWrite64 (
324 RegisterTableEntry
->Index
,
325 RegisterTableEntry
->ValidBitStart
,
326 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
327 RegisterTableEntry
->Value
332 // MemoryMapped operations
335 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
336 MmioBitFieldWrite32 (
337 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
338 RegisterTableEntry
->ValidBitStart
,
339 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
340 (UINT32
)RegisterTableEntry
->Value
342 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
345 // Enable or disable cache
349 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
351 if (RegisterTableEntry
->Value
== 0) {
359 // Semaphore works logic like below:
361 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
362 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
364 // All threads (T0...Tn) waits in P() line and continues running
370 // V(0...n) V(0...n) ... V(0...n)
371 // n * P(0) n * P(1) ... n * P(n)
374 (ApLocation
!= NULL
) &&
375 (CpuStatus
->ThreadCountPerPackage
!= 0) &&
376 (CpuStatus
->ThreadCountPerCore
!= 0) &&
377 (CpuFlags
->CoreSemaphoreCount
!= NULL
) &&
378 (CpuFlags
->PackageSemaphoreCount
!= NULL
)
380 switch (RegisterTableEntry
->Value
) {
382 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
383 ThreadCountPerCore
= (UINT8
*)(UINTN
)CpuStatus
->ThreadCountPerCore
;
385 CurrentCore
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
;
387 // Get Offset info for the first thread in the core which current thread belongs to.
389 FirstThread
= CurrentCore
* CpuStatus
->MaxThreadCount
;
390 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
393 // Different cores may have different valid threads in them. If driver maintail clearly
394 // thread index in different cores, the logic will be much complicated.
395 // Here driver just simply records the max thread number in all cores and use it as expect
396 // thread number for all cores.
397 // In below two steps logic, first current thread will Release semaphore for each thread
398 // in current core. Maybe some threads are not valid in this core, but driver don't
399 // care. Second, driver will let current thread wait semaphore for all valid threads in
400 // current core. Because only the valid threads will do release semaphore for this
401 // thread, driver here only need to wait the valid thread count.
405 // First Notify ALL THREADs in current Core that this thread is ready.
407 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
408 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
411 // Second, check whether all VALID THREADs (not all threads) in current core are ready.
413 for (ProcessorIndex
= 0; ProcessorIndex
< ThreadCountPerCore
[CurrentCore
]; ProcessorIndex
++) {
414 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
419 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
420 ThreadCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ThreadCountPerPackage
;
422 // Get Offset info for the first thread in the package which current thread belongs to.
424 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
426 // Get the possible threads count for current package.
428 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
431 // Different packages may have different valid threads in them. If driver maintail clearly
432 // thread index in different packages, the logic will be much complicated.
433 // Here driver just simply records the max thread number in all packages and use it as expect
434 // thread number for all packages.
435 // In below two steps logic, first current thread will Release semaphore for each thread
436 // in current package. Maybe some threads are not valid in this package, but driver don't
437 // care. Second, driver will let current thread wait semaphore for all valid threads in
438 // current package. Because only the valid threads will do release semaphore for this
439 // thread, driver here only need to wait the valid thread count.
443 // First Notify ALL THREADS in current package that this thread is ready.
445 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
; ProcessorIndex
++) {
446 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
449 // Second, check whether VALID THREADS (not all threads) in current package are ready.
451 for (ProcessorIndex
= 0; ProcessorIndex
< ThreadCountPerPackage
[ApLocation
->Package
]; ProcessorIndex
++) {
452 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
469 Set Processor register for one AP.
471 @param PreSmmRegisterTable Use pre Smm register table or register table.
476 IN BOOLEAN PreSmmRegisterTable
479 CPU_FEATURE_INIT_DATA
*FeatureInitData
;
480 CPU_REGISTER_TABLE
*RegisterTable
;
481 CPU_REGISTER_TABLE
*RegisterTables
;
486 FeatureInitData
= &mAcpiCpuData
.CpuFeatureInitData
;
488 if (PreSmmRegisterTable
) {
489 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)FeatureInitData
->PreSmmInitRegisterTable
;
491 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)FeatureInitData
->RegisterTable
;
493 if (RegisterTables
== NULL
) {
497 InitApicId
= GetInitialApicId ();
498 RegisterTable
= NULL
;
499 ProcIndex
= (UINTN
)-1;
500 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
501 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
502 RegisterTable
= &RegisterTables
[Index
];
507 ASSERT (RegisterTable
!= NULL
);
509 if (FeatureInitData
->ApLocation
!= 0) {
510 ProgramProcessorRegister (
512 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)FeatureInitData
->ApLocation
+ ProcIndex
,
513 &FeatureInitData
->CpuStatus
,
517 ProgramProcessorRegister (
520 &FeatureInitData
->CpuStatus
,
527 AP initialization before then after SMBASE relocation in the S3 boot path.
537 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
542 // Count down the number with lock mechanism.
544 InterlockedDecrement (&mNumberToFinish
);
547 // Wait for BSP to signal SMM Base relocation done.
549 while (!mInitApsAfterSmmBaseReloc
) {
553 ProgramVirtualWireMode ();
554 DisableLvtInterrupts ();
559 // Place AP into the safe code, count down the number with lock mechanism in the safe code.
561 TopOfStack
= (UINTN
) Stack
+ sizeof (Stack
);
562 TopOfStack
&= ~(UINTN
) (CPU_STACK_ALIGNMENT
- 1);
563 CopyMem ((VOID
*) (UINTN
) mApHltLoopCode
, mApHltLoopCodeTemplate
, sizeof (mApHltLoopCodeTemplate
));
564 TransferApToSafeState ((UINTN
)mApHltLoopCode
, TopOfStack
, (UINTN
)&mNumberToFinish
);
568 Prepares startup vector for APs.
570 This function prepares startup vector for APs.
572 @param WorkingBuffer The address of the work buffer.
575 PrepareApStartupVector (
576 EFI_PHYSICAL_ADDRESS WorkingBuffer
579 EFI_PHYSICAL_ADDRESS StartupVector
;
580 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
583 // Get the address map of startup code for AP,
584 // including code size, and offset of long jump instructions to redirect.
586 ZeroMem (&AddressMap
, sizeof (AddressMap
));
587 AsmGetAddressMap (&AddressMap
);
589 StartupVector
= WorkingBuffer
;
592 // Copy AP startup code to startup vector, and then redirect the long jump
593 // instructions for mode switching.
595 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
596 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
597 if (AddressMap
.LongJumpOffset
!= 0) {
598 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
602 // Get the start address of exchange data between BSP and AP.
604 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
605 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
607 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
608 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
610 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
611 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
612 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
613 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
614 mExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
618 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
620 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
621 and restores MTRRs for both BSP and APs.
625 InitializeCpuBeforeRebase (
629 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
633 ProgramVirtualWireMode ();
635 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
637 if (FeaturePcdGet (PcdCpuHotPlugSupport
)) {
638 ASSERT (mNumberOfCpus
<= mAcpiCpuData
.NumberOfCpus
);
640 ASSERT (mNumberOfCpus
== mAcpiCpuData
.NumberOfCpus
);
642 mNumberToFinish
= (UINT32
)(mNumberOfCpus
- 1);
643 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) InitializeAp
;
646 // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
648 mInitApsAfterSmmBaseReloc
= FALSE
;
651 // Send INIT IPI - SIPI to all APs
653 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
655 while (mNumberToFinish
> 0) {
661 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
663 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
664 data saved by normal boot path for both BSP and APs.
668 InitializeCpuAfterRebase (
672 if (FeaturePcdGet (PcdCpuHotPlugSupport
)) {
673 ASSERT (mNumberOfCpus
<= mAcpiCpuData
.NumberOfCpus
);
675 ASSERT (mNumberOfCpus
== mAcpiCpuData
.NumberOfCpus
);
677 mNumberToFinish
= (UINT32
)(mNumberOfCpus
- 1);
680 // Signal that SMM base relocation is complete and to continue initialization for all APs.
682 mInitApsAfterSmmBaseReloc
= TRUE
;
685 // Must begin set register after all APs have continue their initialization.
686 // This is a requirement to support semaphore mechanism in register table.
687 // Because if semaphore's dependence type is package type, semaphore will wait
688 // for all Aps in one package finishing their tasks before set next register
689 // for all APs. If the Aps not begin its task during BSP doing its task, the
690 // BSP thread will hang because it is waiting for other Aps in the same
691 // package finishing their task.
695 while (mNumberToFinish
> 0) {
701 Restore SMM Configuration in S3 boot path.
705 RestoreSmmConfigurationInS3 (
709 if (!mAcpiS3Enable
) {
714 // Restore SMM Configuration in S3 boot path.
716 if (mRestoreSmmConfigurationInS3
) {
718 // Need make sure gSmst is correct because below function may use them.
720 gSmst
->SmmStartupThisAp
= gSmmCpuPrivate
->SmmCoreEntryContext
.SmmStartupThisAp
;
721 gSmst
->CurrentlyExecutingCpu
= gSmmCpuPrivate
->SmmCoreEntryContext
.CurrentlyExecutingCpu
;
722 gSmst
->NumberOfCpus
= gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
723 gSmst
->CpuSaveStateSize
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveStateSize
;
724 gSmst
->CpuSaveState
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveState
;
727 // Configure SMM Code Access Check feature if available.
729 ConfigSmmCodeAccessCheck ();
731 SmmCpuFeaturesCompleteSmmReadyToLock ();
733 mRestoreSmmConfigurationInS3
= FALSE
;
738 Perform SMM initialization for all processors in the S3 boot path.
740 For a native platform, MP initialization in the S3 boot path is also performed in this function.
748 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
749 IA32_DESCRIPTOR Ia32Idtr
;
750 IA32_DESCRIPTOR X64Idtr
;
751 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable
[EXCEPTION_VECTOR_NUMBER
];
754 DEBUG ((DEBUG_INFO
, "SmmRestoreCpu()\n"));
759 // See if there is enough context to resume PEI Phase
761 if (mSmmS3ResumeState
== NULL
) {
762 DEBUG ((DEBUG_ERROR
, "No context to return to PEI Phase\n"));
766 SmmS3ResumeState
= mSmmS3ResumeState
;
767 ASSERT (SmmS3ResumeState
!= NULL
);
769 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
771 // Save the IA32 IDT Descriptor
773 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
776 // Setup X64 IDT table
778 ZeroMem (IdtEntryTable
, sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32);
779 X64Idtr
.Base
= (UINTN
) IdtEntryTable
;
780 X64Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32 - 1);
781 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &X64Idtr
);
784 // Setup the default exception handler
786 Status
= InitializeCpuExceptionHandlers (NULL
);
787 ASSERT_EFI_ERROR (Status
);
790 // Initialize Debug Agent to support source level debug
792 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
, (VOID
*)&Ia32Idtr
, NULL
);
796 // Skip initialization if mAcpiCpuData is not valid
798 if (mAcpiCpuData
.NumberOfCpus
> 0) {
800 // First time microcode load and restore MTRRs
802 InitializeCpuBeforeRebase ();
806 // Restore SMBASE for BSP and all APs
811 // Skip initialization if mAcpiCpuData is not valid
813 if (mAcpiCpuData
.NumberOfCpus
> 0) {
815 // Restore MSRs for BSP and all APs
817 InitializeCpuAfterRebase ();
821 // Set a flag to restore SMM configuration in S3 path.
823 mRestoreSmmConfigurationInS3
= TRUE
;
825 DEBUG (( DEBUG_INFO
, "SMM S3 Return CS = %x\n", SmmS3ResumeState
->ReturnCs
));
826 DEBUG (( DEBUG_INFO
, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState
->ReturnEntryPoint
));
827 DEBUG (( DEBUG_INFO
, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState
->ReturnContext1
));
828 DEBUG (( DEBUG_INFO
, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState
->ReturnContext2
));
829 DEBUG (( DEBUG_INFO
, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState
->ReturnStackPointer
));
832 // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
834 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_32
) {
835 DEBUG ((DEBUG_INFO
, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
838 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)SmmS3ResumeState
->ReturnEntryPoint
,
839 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext1
,
840 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext2
,
841 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnStackPointer
846 // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
848 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
849 DEBUG ((DEBUG_INFO
, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
851 // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
853 SaveAndSetDebugTimerInterrupt (FALSE
);
855 // Restore IA32 IDT table
857 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
859 SmmS3ResumeState
->ReturnCs
,
860 (UINT32
)SmmS3ResumeState
->ReturnEntryPoint
,
861 (UINT32
)SmmS3ResumeState
->ReturnContext1
,
862 (UINT32
)SmmS3ResumeState
->ReturnContext2
,
863 (UINT32
)SmmS3ResumeState
->ReturnStackPointer
868 // Can not resume PEI Phase
870 DEBUG ((DEBUG_ERROR
, "No context to return to PEI Phase\n"));
875 Initialize SMM S3 resume state structure used during S3 Resume.
877 @param[in] Cr3 The base address of the page tables to use in SMM.
881 InitSmmS3ResumeState (
886 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
887 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
888 EFI_PHYSICAL_ADDRESS Address
;
891 if (!mAcpiS3Enable
) {
895 GuidHob
= GetFirstGuidHob (&gEfiAcpiVariableGuid
);
896 if (GuidHob
== NULL
) {
899 "ERROR:%a(): HOB(gEfiAcpiVariableGuid=%g) needed by S3 resume doesn't exist!\n",
901 &gEfiAcpiVariableGuid
905 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
907 DEBUG ((DEBUG_INFO
, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor
));
908 DEBUG ((DEBUG_INFO
, "SMM S3 Structure = %x\n", SmramDescriptor
->CpuStart
));
910 SmmS3ResumeState
= (SMM_S3_RESUME_STATE
*)(UINTN
)SmramDescriptor
->CpuStart
;
911 ZeroMem (SmmS3ResumeState
, sizeof (SMM_S3_RESUME_STATE
));
913 mSmmS3ResumeState
= SmmS3ResumeState
;
914 SmmS3ResumeState
->Smst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)gSmst
;
916 SmmS3ResumeState
->SmmS3ResumeEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)SmmRestoreCpu
;
918 SmmS3ResumeState
->SmmS3StackSize
= SIZE_32KB
;
919 SmmS3ResumeState
->SmmS3StackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)SmmS3ResumeState
->SmmS3StackSize
));
920 if (SmmS3ResumeState
->SmmS3StackBase
== 0) {
921 SmmS3ResumeState
->SmmS3StackSize
= 0;
924 SmmS3ResumeState
->SmmS3Cr0
= mSmmCr0
;
925 SmmS3ResumeState
->SmmS3Cr3
= Cr3
;
926 SmmS3ResumeState
->SmmS3Cr4
= mSmmCr4
;
928 if (sizeof (UINTN
) == sizeof (UINT64
)) {
929 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_64
;
931 if (sizeof (UINTN
) == sizeof (UINT32
)) {
932 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_32
;
936 // Patch SmmS3ResumeState->SmmS3Cr3
942 // Allocate safe memory in ACPI NVS for AP to execute hlt loop in
943 // protected mode on S3 path
945 Address
= BASE_4GB
- 1;
946 Status
= gBS
->AllocatePages (
949 EFI_SIZE_TO_PAGES (sizeof (mApHltLoopCodeTemplate
)),
952 ASSERT_EFI_ERROR (Status
);
953 mApHltLoopCode
= (UINT8
*) (UINTN
) Address
;
957 Copy register table from non-SMRAM into SMRAM.
959 @param[in] DestinationRegisterTableList Points to destination register table.
960 @param[in] SourceRegisterTableList Points to source register table.
961 @param[in] NumberOfCpus Number of CPUs.
966 IN CPU_REGISTER_TABLE
*DestinationRegisterTableList
,
967 IN CPU_REGISTER_TABLE
*SourceRegisterTableList
,
968 IN UINT32 NumberOfCpus
972 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
974 CopyMem (DestinationRegisterTableList
, SourceRegisterTableList
, NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
975 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
976 if (DestinationRegisterTableList
[Index
].TableLength
!= 0) {
977 DestinationRegisterTableList
[Index
].AllocatedSize
= DestinationRegisterTableList
[Index
].TableLength
* sizeof (CPU_REGISTER_TABLE_ENTRY
);
978 RegisterTableEntry
= AllocateCopyPool (
979 DestinationRegisterTableList
[Index
].AllocatedSize
,
980 (VOID
*)(UINTN
)SourceRegisterTableList
[Index
].RegisterTableEntry
982 ASSERT (RegisterTableEntry
!= NULL
);
983 DestinationRegisterTableList
[Index
].RegisterTableEntry
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RegisterTableEntry
;
989 Check whether the register table is empty or not.
991 @param[in] RegisterTable Point to the register table.
992 @param[in] NumberOfCpus Number of CPUs.
994 @retval TRUE The register table is empty.
995 @retval FALSE The register table is not empty.
998 IsRegisterTableEmpty (
999 IN CPU_REGISTER_TABLE
*RegisterTable
,
1000 IN UINT32 NumberOfCpus
1005 if (RegisterTable
!= NULL
) {
1006 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
1007 if (RegisterTable
[Index
].TableLength
!= 0) {
1017 Copy the data used to initialize processor register into SMRAM.
1019 @param[in,out] CpuFeatureInitDataDst Pointer to the destination CPU_FEATURE_INIT_DATA structure.
1020 @param[in] CpuFeatureInitDataSrc Pointer to the source CPU_FEATURE_INIT_DATA structure.
1024 CopyCpuFeatureInitDatatoSmram (
1025 IN OUT CPU_FEATURE_INIT_DATA
*CpuFeatureInitDataDst
,
1026 IN CPU_FEATURE_INIT_DATA
*CpuFeatureInitDataSrc
1029 CPU_STATUS_INFORMATION
*CpuStatus
;
1031 if (!IsRegisterTableEmpty ((CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataSrc
->PreSmmInitRegisterTable
, mAcpiCpuData
.NumberOfCpus
)) {
1032 CpuFeatureInitDataDst
->PreSmmInitRegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
1033 ASSERT (CpuFeatureInitDataDst
->PreSmmInitRegisterTable
!= 0);
1036 (CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataDst
->PreSmmInitRegisterTable
,
1037 (CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataSrc
->PreSmmInitRegisterTable
,
1038 mAcpiCpuData
.NumberOfCpus
1042 if (!IsRegisterTableEmpty ((CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataSrc
->RegisterTable
, mAcpiCpuData
.NumberOfCpus
)) {
1043 CpuFeatureInitDataDst
->RegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
1044 ASSERT (CpuFeatureInitDataDst
->RegisterTable
!= 0);
1047 (CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataDst
->RegisterTable
,
1048 (CPU_REGISTER_TABLE
*)(UINTN
)CpuFeatureInitDataSrc
->RegisterTable
,
1049 mAcpiCpuData
.NumberOfCpus
1053 CpuStatus
= &CpuFeatureInitDataDst
->CpuStatus
;
1054 CopyMem (CpuStatus
, &CpuFeatureInitDataSrc
->CpuStatus
, sizeof (CPU_STATUS_INFORMATION
));
1056 if (CpuFeatureInitDataSrc
->CpuStatus
.ThreadCountPerPackage
!= 0) {
1057 CpuStatus
->ThreadCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1058 sizeof (UINT32
) * CpuStatus
->PackageCount
,
1059 (UINT32
*)(UINTN
)CpuFeatureInitDataSrc
->CpuStatus
.ThreadCountPerPackage
1061 ASSERT (CpuStatus
->ThreadCountPerPackage
!= 0);
1064 if (CpuFeatureInitDataSrc
->CpuStatus
.ThreadCountPerCore
!= 0) {
1065 CpuStatus
->ThreadCountPerCore
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1066 sizeof (UINT8
) * (CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
),
1067 (UINT32
*)(UINTN
)CpuFeatureInitDataSrc
->CpuStatus
.ThreadCountPerCore
1069 ASSERT (CpuStatus
->ThreadCountPerCore
!= 0);
1072 if (CpuFeatureInitDataSrc
->ApLocation
!= 0) {
1073 CpuFeatureInitDataDst
->ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1074 mAcpiCpuData
.NumberOfCpus
* sizeof (EFI_CPU_PHYSICAL_LOCATION
),
1075 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)CpuFeatureInitDataSrc
->ApLocation
1077 ASSERT (CpuFeatureInitDataDst
->ApLocation
!= 0);
1090 ACPI_CPU_DATA
*AcpiCpuData
;
1091 IA32_DESCRIPTOR
*Gdtr
;
1092 IA32_DESCRIPTOR
*Idtr
;
1095 VOID
*MachineCheckHandlerForAp
;
1096 CPU_STATUS_INFORMATION
*CpuStatus
;
1098 if (!mAcpiS3Enable
) {
1103 // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
1105 mAcpiCpuData
.NumberOfCpus
= 0;
1108 // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
1110 AcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
1111 if (AcpiCpuData
== 0) {
1116 // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
1118 CopyMem (&mAcpiCpuData
, AcpiCpuData
, sizeof (mAcpiCpuData
));
1120 mAcpiCpuData
.MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (MTRR_SETTINGS
));
1121 ASSERT (mAcpiCpuData
.MtrrTable
!= 0);
1123 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.MtrrTable
, (VOID
*)(UINTN
)AcpiCpuData
->MtrrTable
, sizeof (MTRR_SETTINGS
));
1125 mAcpiCpuData
.GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
1126 ASSERT (mAcpiCpuData
.GdtrProfile
!= 0);
1128 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.GdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
1130 mAcpiCpuData
.IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
1131 ASSERT (mAcpiCpuData
.IdtrProfile
!= 0);
1133 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.IdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
1136 // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
1138 Gdtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.GdtrProfile
;
1139 Idtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.IdtrProfile
;
1141 GdtForAp
= AllocatePool ((Gdtr
->Limit
+ 1) + (Idtr
->Limit
+ 1) + mAcpiCpuData
.ApMachineCheckHandlerSize
);
1142 ASSERT (GdtForAp
!= NULL
);
1143 IdtForAp
= (VOID
*) ((UINTN
)GdtForAp
+ (Gdtr
->Limit
+ 1));
1144 MachineCheckHandlerForAp
= (VOID
*) ((UINTN
)IdtForAp
+ (Idtr
->Limit
+ 1));
1146 CopyMem (GdtForAp
, (VOID
*)Gdtr
->Base
, Gdtr
->Limit
+ 1);
1147 CopyMem (IdtForAp
, (VOID
*)Idtr
->Base
, Idtr
->Limit
+ 1);
1148 CopyMem (MachineCheckHandlerForAp
, (VOID
*)(UINTN
)mAcpiCpuData
.ApMachineCheckHandlerBase
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
1150 Gdtr
->Base
= (UINTN
)GdtForAp
;
1151 Idtr
->Base
= (UINTN
)IdtForAp
;
1152 mAcpiCpuData
.ApMachineCheckHandlerBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MachineCheckHandlerForAp
;
1154 ZeroMem (&mAcpiCpuData
.CpuFeatureInitData
, sizeof (CPU_FEATURE_INIT_DATA
));
1156 if (!PcdGetBool (PcdCpuFeaturesInitOnS3Resume
)) {
1158 // If the CPU features will not be initialized by CpuFeaturesPei module during
1159 // next ACPI S3 resume, copy the CPU features initialization data into SMRAM,
1160 // which will be consumed in SmmRestoreCpu during next S3 resume.
1162 CopyCpuFeatureInitDatatoSmram (&mAcpiCpuData
.CpuFeatureInitData
, &AcpiCpuData
->CpuFeatureInitData
);
1164 CpuStatus
= &mAcpiCpuData
.CpuFeatureInitData
.CpuStatus
;
1166 mCpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (
1167 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1168 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1170 ASSERT (mCpuFlags
.CoreSemaphoreCount
!= NULL
);
1172 mCpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (
1173 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1174 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1176 ASSERT (mCpuFlags
.PackageSemaphoreCount
!= NULL
);
1178 InitializeSpinLock((SPIN_LOCK
*) &mCpuFlags
.MemoryMappedLock
);
1183 Get ACPI S3 enable flag.
1187 GetAcpiS3EnableFlag (
1191 mAcpiS3Enable
= PcdGetBool (PcdAcpiS3Enable
);