2 Code for Processor S3 restoration
4 Copyright (c) 2006 - 2019, 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 PackageThreadsCount
;
239 UINT32 CurrentThread
;
240 UINTN ProcessorIndex
;
241 UINTN ValidThreadCount
;
242 UINT32
*ValidCoreCountPerPackage
;
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
->ValidCoreCountPerPackage
!= 0) &&
376 (CpuFlags
->CoreSemaphoreCount
!= NULL
) &&
377 (CpuFlags
->PackageSemaphoreCount
!= NULL
)
379 switch (RegisterTableEntry
->Value
) {
381 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
383 // Get Offset info for the first thread in the core which current thread belongs to.
385 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
386 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
388 // First Notify all threads in current Core that this thread has ready.
390 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
391 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
394 // Second, check whether all valid threads in current core have ready.
396 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
397 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
402 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
403 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
405 // Get Offset info for the first thread in the package which current thread belongs to.
407 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
409 // Get the possible threads count for current package.
411 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
412 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
414 // Get the valid thread count for current package.
416 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
419 // Different packages may have different valid cores in them. If driver maintail clearly
420 // cores number in different packages, the logic will be much complicated.
421 // Here driver just simply records the max core number in all packages and use it as expect
422 // core number for all packages.
423 // In below two steps logic, first current thread will Release semaphore for each thread
424 // in current package. Maybe some threads are not valid in this package, but driver don't
425 // care. Second, driver will let current thread wait semaphore for all valid threads in
426 // current package. Because only the valid threads will do release semaphore for this
427 // thread, driver here only need to wait the valid thread count.
431 // First Notify all threads in current package that this thread has ready.
433 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
434 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
437 // Second, check whether all valid threads in current package have ready.
439 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
440 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
457 Set Processor register for one AP.
459 @param PreSmmRegisterTable Use pre Smm register table or register table.
464 IN BOOLEAN PreSmmRegisterTable
467 CPU_REGISTER_TABLE
*RegisterTable
;
468 CPU_REGISTER_TABLE
*RegisterTables
;
473 if (PreSmmRegisterTable
) {
474 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.PreSmmInitRegisterTable
;
476 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.RegisterTable
;
479 InitApicId
= GetInitialApicId ();
480 RegisterTable
= NULL
;
481 ProcIndex
= (UINTN
)-1;
482 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
483 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
484 RegisterTable
= &RegisterTables
[Index
];
489 ASSERT (RegisterTable
!= NULL
);
491 if (mAcpiCpuData
.ApLocation
!= 0) {
492 ProgramProcessorRegister (
494 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)mAcpiCpuData
.ApLocation
+ ProcIndex
,
495 &mAcpiCpuData
.CpuStatus
,
499 ProgramProcessorRegister (
502 &mAcpiCpuData
.CpuStatus
,
509 AP initialization before then after SMBASE relocation in the S3 boot path.
519 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
524 // Count down the number with lock mechanism.
526 InterlockedDecrement (&mNumberToFinish
);
529 // Wait for BSP to signal SMM Base relocation done.
531 while (!mInitApsAfterSmmBaseReloc
) {
535 ProgramVirtualWireMode ();
536 DisableLvtInterrupts ();
541 // Place AP into the safe code, count down the number with lock mechanism in the safe code.
543 TopOfStack
= (UINTN
) Stack
+ sizeof (Stack
);
544 TopOfStack
&= ~(UINTN
) (CPU_STACK_ALIGNMENT
- 1);
545 CopyMem ((VOID
*) (UINTN
) mApHltLoopCode
, mApHltLoopCodeTemplate
, sizeof (mApHltLoopCodeTemplate
));
546 TransferApToSafeState ((UINTN
)mApHltLoopCode
, TopOfStack
, (UINTN
)&mNumberToFinish
);
550 Prepares startup vector for APs.
552 This function prepares startup vector for APs.
554 @param WorkingBuffer The address of the work buffer.
557 PrepareApStartupVector (
558 EFI_PHYSICAL_ADDRESS WorkingBuffer
561 EFI_PHYSICAL_ADDRESS StartupVector
;
562 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
565 // Get the address map of startup code for AP,
566 // including code size, and offset of long jump instructions to redirect.
568 ZeroMem (&AddressMap
, sizeof (AddressMap
));
569 AsmGetAddressMap (&AddressMap
);
571 StartupVector
= WorkingBuffer
;
574 // Copy AP startup code to startup vector, and then redirect the long jump
575 // instructions for mode switching.
577 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
578 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
579 if (AddressMap
.LongJumpOffset
!= 0) {
580 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
584 // Get the start address of exchange data between BSP and AP.
586 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
587 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
589 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
590 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
592 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
593 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
594 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
595 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
596 mExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
600 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
602 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
603 and restores MTRRs for both BSP and APs.
607 InitializeCpuBeforeRebase (
611 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
615 ProgramVirtualWireMode ();
617 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
619 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
620 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) InitializeAp
;
623 // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
625 mInitApsAfterSmmBaseReloc
= FALSE
;
628 // Send INIT IPI - SIPI to all APs
630 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
632 while (mNumberToFinish
> 0) {
638 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
640 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
641 data saved by normal boot path for both BSP and APs.
645 InitializeCpuAfterRebase (
649 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
652 // Signal that SMM base relocation is complete and to continue initialization for all APs.
654 mInitApsAfterSmmBaseReloc
= TRUE
;
657 // Must begin set register after all APs have continue their initialization.
658 // This is a requirement to support semaphore mechanism in register table.
659 // Because if semaphore's dependence type is package type, semaphore will wait
660 // for all Aps in one package finishing their tasks before set next register
661 // for all APs. If the Aps not begin its task during BSP doing its task, the
662 // BSP thread will hang because it is waiting for other Aps in the same
663 // package finishing their task.
667 while (mNumberToFinish
> 0) {
673 Restore SMM Configuration in S3 boot path.
677 RestoreSmmConfigurationInS3 (
681 if (!mAcpiS3Enable
) {
686 // Restore SMM Configuration in S3 boot path.
688 if (mRestoreSmmConfigurationInS3
) {
690 // Need make sure gSmst is correct because below function may use them.
692 gSmst
->SmmStartupThisAp
= gSmmCpuPrivate
->SmmCoreEntryContext
.SmmStartupThisAp
;
693 gSmst
->CurrentlyExecutingCpu
= gSmmCpuPrivate
->SmmCoreEntryContext
.CurrentlyExecutingCpu
;
694 gSmst
->NumberOfCpus
= gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
695 gSmst
->CpuSaveStateSize
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveStateSize
;
696 gSmst
->CpuSaveState
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveState
;
699 // Configure SMM Code Access Check feature if available.
701 ConfigSmmCodeAccessCheck ();
703 SmmCpuFeaturesCompleteSmmReadyToLock ();
705 mRestoreSmmConfigurationInS3
= FALSE
;
710 Perform SMM initialization for all processors in the S3 boot path.
712 For a native platform, MP initialization in the S3 boot path is also performed in this function.
720 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
721 IA32_DESCRIPTOR Ia32Idtr
;
722 IA32_DESCRIPTOR X64Idtr
;
723 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable
[EXCEPTION_VECTOR_NUMBER
];
726 DEBUG ((EFI_D_INFO
, "SmmRestoreCpu()\n"));
731 // See if there is enough context to resume PEI Phase
733 if (mSmmS3ResumeState
== NULL
) {
734 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
738 SmmS3ResumeState
= mSmmS3ResumeState
;
739 ASSERT (SmmS3ResumeState
!= NULL
);
741 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
743 // Save the IA32 IDT Descriptor
745 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
748 // Setup X64 IDT table
750 ZeroMem (IdtEntryTable
, sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32);
751 X64Idtr
.Base
= (UINTN
) IdtEntryTable
;
752 X64Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32 - 1);
753 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &X64Idtr
);
756 // Setup the default exception handler
758 Status
= InitializeCpuExceptionHandlers (NULL
);
759 ASSERT_EFI_ERROR (Status
);
762 // Initialize Debug Agent to support source level debug
764 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
, (VOID
*)&Ia32Idtr
, NULL
);
768 // Skip initialization if mAcpiCpuData is not valid
770 if (mAcpiCpuData
.NumberOfCpus
> 0) {
772 // First time microcode load and restore MTRRs
774 InitializeCpuBeforeRebase ();
778 // Restore SMBASE for BSP and all APs
783 // Skip initialization if mAcpiCpuData is not valid
785 if (mAcpiCpuData
.NumberOfCpus
> 0) {
787 // Restore MSRs for BSP and all APs
789 InitializeCpuAfterRebase ();
793 // Set a flag to restore SMM configuration in S3 path.
795 mRestoreSmmConfigurationInS3
= TRUE
;
797 DEBUG (( EFI_D_INFO
, "SMM S3 Return CS = %x\n", SmmS3ResumeState
->ReturnCs
));
798 DEBUG (( EFI_D_INFO
, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState
->ReturnEntryPoint
));
799 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState
->ReturnContext1
));
800 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState
->ReturnContext2
));
801 DEBUG (( EFI_D_INFO
, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState
->ReturnStackPointer
));
804 // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
806 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_32
) {
807 DEBUG ((EFI_D_INFO
, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
810 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)SmmS3ResumeState
->ReturnEntryPoint
,
811 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext1
,
812 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext2
,
813 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnStackPointer
818 // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
820 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
821 DEBUG ((EFI_D_INFO
, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
823 // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
825 SaveAndSetDebugTimerInterrupt (FALSE
);
827 // Restore IA32 IDT table
829 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
831 SmmS3ResumeState
->ReturnCs
,
832 (UINT32
)SmmS3ResumeState
->ReturnEntryPoint
,
833 (UINT32
)SmmS3ResumeState
->ReturnContext1
,
834 (UINT32
)SmmS3ResumeState
->ReturnContext2
,
835 (UINT32
)SmmS3ResumeState
->ReturnStackPointer
840 // Can not resume PEI Phase
842 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
847 Initialize SMM S3 resume state structure used during S3 Resume.
849 @param[in] Cr3 The base address of the page tables to use in SMM.
853 InitSmmS3ResumeState (
858 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
859 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
860 EFI_PHYSICAL_ADDRESS Address
;
863 if (!mAcpiS3Enable
) {
867 GuidHob
= GetFirstGuidHob (&gEfiAcpiVariableGuid
);
868 if (GuidHob
== NULL
) {
871 "ERROR:%a(): HOB(gEfiAcpiVariableGuid=%g) needed by S3 resume doesn't exist!\n",
873 &gEfiAcpiVariableGuid
877 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
879 DEBUG ((EFI_D_INFO
, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor
));
880 DEBUG ((EFI_D_INFO
, "SMM S3 Structure = %x\n", SmramDescriptor
->CpuStart
));
882 SmmS3ResumeState
= (SMM_S3_RESUME_STATE
*)(UINTN
)SmramDescriptor
->CpuStart
;
883 ZeroMem (SmmS3ResumeState
, sizeof (SMM_S3_RESUME_STATE
));
885 mSmmS3ResumeState
= SmmS3ResumeState
;
886 SmmS3ResumeState
->Smst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)gSmst
;
888 SmmS3ResumeState
->SmmS3ResumeEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)SmmRestoreCpu
;
890 SmmS3ResumeState
->SmmS3StackSize
= SIZE_32KB
;
891 SmmS3ResumeState
->SmmS3StackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)SmmS3ResumeState
->SmmS3StackSize
));
892 if (SmmS3ResumeState
->SmmS3StackBase
== 0) {
893 SmmS3ResumeState
->SmmS3StackSize
= 0;
896 SmmS3ResumeState
->SmmS3Cr0
= mSmmCr0
;
897 SmmS3ResumeState
->SmmS3Cr3
= Cr3
;
898 SmmS3ResumeState
->SmmS3Cr4
= mSmmCr4
;
900 if (sizeof (UINTN
) == sizeof (UINT64
)) {
901 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_64
;
903 if (sizeof (UINTN
) == sizeof (UINT32
)) {
904 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_32
;
908 // Patch SmmS3ResumeState->SmmS3Cr3
914 // Allocate safe memory in ACPI NVS for AP to execute hlt loop in
915 // protected mode on S3 path
917 Address
= BASE_4GB
- 1;
918 Status
= gBS
->AllocatePages (
921 EFI_SIZE_TO_PAGES (sizeof (mApHltLoopCodeTemplate
)),
924 ASSERT_EFI_ERROR (Status
);
925 mApHltLoopCode
= (UINT8
*) (UINTN
) Address
;
929 Copy register table from ACPI NVS memory into SMRAM.
931 @param[in] DestinationRegisterTableList Points to destination register table.
932 @param[in] SourceRegisterTableList Points to source register table.
933 @param[in] NumberOfCpus Number of CPUs.
938 IN CPU_REGISTER_TABLE
*DestinationRegisterTableList
,
939 IN CPU_REGISTER_TABLE
*SourceRegisterTableList
,
940 IN UINT32 NumberOfCpus
944 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
946 CopyMem (DestinationRegisterTableList
, SourceRegisterTableList
, NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
947 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
948 if (DestinationRegisterTableList
[Index
].AllocatedSize
!= 0) {
949 RegisterTableEntry
= AllocateCopyPool (
950 DestinationRegisterTableList
[Index
].AllocatedSize
,
951 (VOID
*)(UINTN
)SourceRegisterTableList
[Index
].RegisterTableEntry
953 ASSERT (RegisterTableEntry
!= NULL
);
954 DestinationRegisterTableList
[Index
].RegisterTableEntry
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RegisterTableEntry
;
968 ACPI_CPU_DATA
*AcpiCpuData
;
969 IA32_DESCRIPTOR
*Gdtr
;
970 IA32_DESCRIPTOR
*Idtr
;
973 VOID
*MachineCheckHandlerForAp
;
974 CPU_STATUS_INFORMATION
*CpuStatus
;
976 if (!mAcpiS3Enable
) {
981 // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
983 mAcpiCpuData
.NumberOfCpus
= 0;
986 // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
988 AcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
989 if (AcpiCpuData
== 0) {
994 // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
996 CopyMem (&mAcpiCpuData
, AcpiCpuData
, sizeof (mAcpiCpuData
));
998 mAcpiCpuData
.MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (MTRR_SETTINGS
));
999 ASSERT (mAcpiCpuData
.MtrrTable
!= 0);
1001 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.MtrrTable
, (VOID
*)(UINTN
)AcpiCpuData
->MtrrTable
, sizeof (MTRR_SETTINGS
));
1003 mAcpiCpuData
.GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
1004 ASSERT (mAcpiCpuData
.GdtrProfile
!= 0);
1006 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.GdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
1008 mAcpiCpuData
.IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
1009 ASSERT (mAcpiCpuData
.IdtrProfile
!= 0);
1011 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.IdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
1013 mAcpiCpuData
.PreSmmInitRegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
1014 ASSERT (mAcpiCpuData
.PreSmmInitRegisterTable
!= 0);
1017 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.PreSmmInitRegisterTable
,
1018 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->PreSmmInitRegisterTable
,
1019 mAcpiCpuData
.NumberOfCpus
1022 mAcpiCpuData
.RegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
1023 ASSERT (mAcpiCpuData
.RegisterTable
!= 0);
1026 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.RegisterTable
,
1027 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
,
1028 mAcpiCpuData
.NumberOfCpus
1032 // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
1034 Gdtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.GdtrProfile
;
1035 Idtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.IdtrProfile
;
1037 GdtForAp
= AllocatePool ((Gdtr
->Limit
+ 1) + (Idtr
->Limit
+ 1) + mAcpiCpuData
.ApMachineCheckHandlerSize
);
1038 ASSERT (GdtForAp
!= NULL
);
1039 IdtForAp
= (VOID
*) ((UINTN
)GdtForAp
+ (Gdtr
->Limit
+ 1));
1040 MachineCheckHandlerForAp
= (VOID
*) ((UINTN
)IdtForAp
+ (Idtr
->Limit
+ 1));
1042 CopyMem (GdtForAp
, (VOID
*)Gdtr
->Base
, Gdtr
->Limit
+ 1);
1043 CopyMem (IdtForAp
, (VOID
*)Idtr
->Base
, Idtr
->Limit
+ 1);
1044 CopyMem (MachineCheckHandlerForAp
, (VOID
*)(UINTN
)mAcpiCpuData
.ApMachineCheckHandlerBase
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
1046 Gdtr
->Base
= (UINTN
)GdtForAp
;
1047 Idtr
->Base
= (UINTN
)IdtForAp
;
1048 mAcpiCpuData
.ApMachineCheckHandlerBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MachineCheckHandlerForAp
;
1050 CpuStatus
= &mAcpiCpuData
.CpuStatus
;
1051 CopyMem (CpuStatus
, &AcpiCpuData
->CpuStatus
, sizeof (CPU_STATUS_INFORMATION
));
1052 if (AcpiCpuData
->CpuStatus
.ValidCoreCountPerPackage
!= 0) {
1053 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1054 sizeof (UINT32
) * CpuStatus
->PackageCount
,
1055 (UINT32
*)(UINTN
)AcpiCpuData
->CpuStatus
.ValidCoreCountPerPackage
1057 ASSERT (CpuStatus
->ValidCoreCountPerPackage
!= 0);
1059 if (AcpiCpuData
->ApLocation
!= 0) {
1060 mAcpiCpuData
.ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1061 mAcpiCpuData
.NumberOfCpus
* sizeof (EFI_CPU_PHYSICAL_LOCATION
),
1062 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
1064 ASSERT (mAcpiCpuData
.ApLocation
!= 0);
1066 if (CpuStatus
->PackageCount
!= 0) {
1067 mCpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (
1068 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1069 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1071 ASSERT (mCpuFlags
.CoreSemaphoreCount
!= NULL
);
1072 mCpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (
1073 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1074 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1076 ASSERT (mCpuFlags
.PackageSemaphoreCount
!= NULL
);
1078 InitializeSpinLock((SPIN_LOCK
*) &mCpuFlags
.MemoryMappedLock
);
1082 Get ACPI S3 enable flag.
1086 GetAcpiS3EnableFlag (
1090 mAcpiS3Enable
= PcdGetBool (PcdAcpiS3Enable
);