2 Code for Processor S3 restoration
4 Copyright (c) 2006 - 2018, 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"
23 IA32_DESCRIPTOR GdtrProfile
;
24 IA32_DESCRIPTOR IdtrProfile
;
27 UINTN InitializeFloatingPointUnitsAddress
;
28 } MP_CPU_EXCHANGE_INFO
;
32 UINT8
*RendezvousFunnelAddress
;
33 UINTN PModeEntryOffset
;
36 UINTN LModeEntryOffset
;
38 } MP_ASSEMBLY_ADDRESS_MAP
;
41 // Flags used when program the register.
44 volatile UINTN ConsoleLogLock
; // Spinlock used to control console.
45 volatile UINTN MemoryMappedLock
; // Spinlock used to program mmio
46 volatile UINT32
*CoreSemaphoreCount
; // Semaphore container used to program
47 // core level semaphore.
48 volatile UINT32
*PackageSemaphoreCount
; // Semaphore container used to program
49 // package level semaphore.
50 } PROGRAM_CPU_REGISTER_FLAGS
;
53 // Signal that SMM BASE relocation is complete.
55 volatile BOOLEAN mInitApsAfterSmmBaseReloc
;
58 Get starting address and size of the rendezvous entry for APs.
59 Information for fixing a jump instruction in the code is also returned.
61 @param AddressMap Output buffer for address map information.
66 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
69 #define LEGACY_REGION_SIZE (2 * 0x1000)
70 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
72 PROGRAM_CPU_REGISTER_FLAGS mCpuFlags
;
73 ACPI_CPU_DATA mAcpiCpuData
;
74 volatile UINT32 mNumberToFinish
;
75 MP_CPU_EXCHANGE_INFO
*mExchangeInfo
;
76 BOOLEAN mRestoreSmmConfigurationInS3
= FALSE
;
81 BOOLEAN mSmmS3Flag
= FALSE
;
84 // Pointer to structure used during S3 Resume
86 SMM_S3_RESUME_STATE
*mSmmS3ResumeState
= NULL
;
88 BOOLEAN mAcpiS3Enable
= TRUE
;
90 UINT8
*mApHltLoopCode
= NULL
;
91 UINT8 mApHltLoopCodeTemplate
[] = {
92 0x8B, 0x44, 0x24, 0x04, // mov eax, dword ptr [esp+4]
93 0xF0, 0xFF, 0x08, // lock dec dword ptr [eax]
99 CHAR16
*mRegisterTypeStr
[] = {L
"MSR", L
"CR", L
"MMIO", L
"CACHE", L
"SEMAP", L
"INVALID" };
102 Sync up the MTRR values for all processors.
104 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
109 EFI_PHYSICAL_ADDRESS MtrrTable
115 Sync up the MTRR values for all processors.
124 MTRR_SETTINGS
*MtrrSettings
;
126 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
127 MtrrSetAllMtrrs (MtrrSettings
);
131 Increment semaphore by 1.
133 @param Sem IN: 32-bit unsigned integer
138 IN OUT
volatile UINT32
*Sem
141 InterlockedIncrement (Sem
);
145 Decrement the semaphore by 1 if it is not zero.
147 Performs an atomic decrement operation for semaphore.
148 The compare exchange operation must be performed using
151 @param Sem IN: 32-bit unsigned integer
156 IN OUT
volatile UINT32
*Sem
163 } while (Value
== 0 ||
164 InterlockedCompareExchange32 (
172 Initialize the CPU registers from a register table.
174 @param[in] RegisterTable The register table for this AP.
175 @param[in] ApLocation AP location info for this ap.
176 @param[in] CpuStatus CPU status info for this CPU.
177 @param[in] CpuFlags Flags data structure used when program the register.
179 @note This service could be called by BSP/APs.
182 ProgramProcessorRegister (
183 IN CPU_REGISTER_TABLE
*RegisterTable
,
184 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
185 IN CPU_STATUS_INFORMATION
*CpuStatus
,
186 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
189 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
192 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
193 volatile UINT32
*SemaphorePtr
;
195 UINT32 PackageThreadsCount
;
196 UINT32 CurrentThread
;
197 UINTN ProcessorIndex
;
199 UINTN ValidThreadCount
;
200 UINT32
*ValidCoreCountPerPackage
;
203 // Traverse Register Table of this logical processor
205 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
207 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
209 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
212 if (ApLocation
!= NULL
) {
213 AcquireSpinLock (&CpuFlags
->ConsoleLogLock
);
214 ThreadIndex
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
+
215 ApLocation
->Core
* CpuStatus
->MaxThreadCount
+
219 "Processor = %lu, Entry Index %lu, Type = %s!\n",
222 mRegisterTypeStr
[MIN ((REGISTER_TYPE
)RegisterTableEntry
->RegisterType
, InvalidReg
)]
224 ReleaseSpinLock (&CpuFlags
->ConsoleLogLock
);
229 // Check the type of specified register
231 switch (RegisterTableEntry
->RegisterType
) {
233 // The specified register is Control Register
235 case ControlRegister
:
236 switch (RegisterTableEntry
->Index
) {
238 Value
= AsmReadCr0 ();
239 Value
= (UINTN
) BitFieldWrite64 (
241 RegisterTableEntry
->ValidBitStart
,
242 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
243 (UINTN
) RegisterTableEntry
->Value
248 Value
= AsmReadCr2 ();
249 Value
= (UINTN
) BitFieldWrite64 (
251 RegisterTableEntry
->ValidBitStart
,
252 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
253 (UINTN
) RegisterTableEntry
->Value
258 Value
= AsmReadCr3 ();
259 Value
= (UINTN
) BitFieldWrite64 (
261 RegisterTableEntry
->ValidBitStart
,
262 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
263 (UINTN
) RegisterTableEntry
->Value
268 Value
= AsmReadCr4 ();
269 Value
= (UINTN
) BitFieldWrite64 (
271 RegisterTableEntry
->ValidBitStart
,
272 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
273 (UINTN
) RegisterTableEntry
->Value
282 // The specified register is Model Specific Register
286 // If this function is called to restore register setting after INIT signal,
287 // there is no need to restore MSRs in register table.
289 if (RegisterTableEntry
->ValidBitLength
>= 64) {
291 // If length is not less than 64 bits, then directly write without reading
294 RegisterTableEntry
->Index
,
295 RegisterTableEntry
->Value
299 // Set the bit section according to bit start and length
301 AsmMsrBitFieldWrite64 (
302 RegisterTableEntry
->Index
,
303 RegisterTableEntry
->ValidBitStart
,
304 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
305 RegisterTableEntry
->Value
310 // MemoryMapped operations
313 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
314 MmioBitFieldWrite32 (
315 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
316 RegisterTableEntry
->ValidBitStart
,
317 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
318 (UINT32
)RegisterTableEntry
->Value
320 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
323 // Enable or disable cache
327 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
329 if (RegisterTableEntry
->Value
== 0) {
337 // Semaphore works logic like below:
339 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
340 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
342 // All threads (T0...Tn) waits in P() line and continues running
348 // V(0...n) V(0...n) ... V(0...n)
349 // n * P(0) n * P(1) ... n * P(n)
352 (ApLocation
!= NULL
) &&
353 (CpuStatus
->ValidCoreCountPerPackage
!= 0) &&
354 (CpuFlags
->CoreSemaphoreCount
!= NULL
) &&
355 (CpuFlags
->PackageSemaphoreCount
!= NULL
)
357 switch (RegisterTableEntry
->Value
) {
359 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
361 // Get Offset info for the first thread in the core which current thread belongs to.
363 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
364 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
366 // First Notify all threads in current Core that this thread has ready.
368 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
369 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
372 // Second, check whether all valid threads in current core have ready.
374 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
375 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
380 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
381 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
383 // Get Offset info for the first thread in the package which current thread belongs to.
385 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
387 // Get the possible threads count for current package.
389 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
390 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
392 // Get the valid thread count for current package.
394 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
397 // Different packages may have different valid cores in them. If driver maintail clearly
398 // cores number in different packages, the logic will be much complicated.
399 // Here driver just simply records the max core number in all packages and use it as expect
400 // core number for all packages.
401 // In below two steps logic, first current thread will Release semaphore for each thread
402 // in current package. Maybe some threads are not valid in this package, but driver don't
403 // care. Second, driver will let current thread wait semaphore for all valid threads in
404 // current package. Because only the valid threads will do release semaphore for this
405 // thread, driver here only need to wait the valid thread count.
409 // First Notify all threads in current package that this thread has ready.
411 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
412 S3ReleaseSemaphore (&SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
415 // Second, check whether all valid threads in current package have ready.
417 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
418 S3WaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
435 Set Processor register for one AP.
437 @param PreSmmRegisterTable Use pre Smm register table or register table.
442 IN BOOLEAN PreSmmRegisterTable
445 CPU_REGISTER_TABLE
*RegisterTable
;
446 CPU_REGISTER_TABLE
*RegisterTables
;
451 if (PreSmmRegisterTable
) {
452 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.PreSmmInitRegisterTable
;
454 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.RegisterTable
;
457 InitApicId
= GetInitialApicId ();
458 RegisterTable
= NULL
;
459 ProcIndex
= (UINTN
)-1;
460 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
461 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
462 RegisterTable
= &RegisterTables
[Index
];
467 ASSERT (RegisterTable
!= NULL
);
469 if (mAcpiCpuData
.ApLocation
!= 0) {
470 ProgramProcessorRegister (
472 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)mAcpiCpuData
.ApLocation
+ ProcIndex
,
473 &mAcpiCpuData
.CpuStatus
,
477 ProgramProcessorRegister (
480 &mAcpiCpuData
.CpuStatus
,
487 AP initialization before then after SMBASE relocation in the S3 boot path.
497 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
502 // Count down the number with lock mechanism.
504 InterlockedDecrement (&mNumberToFinish
);
507 // Wait for BSP to signal SMM Base relocation done.
509 while (!mInitApsAfterSmmBaseReloc
) {
513 ProgramVirtualWireMode ();
514 DisableLvtInterrupts ();
519 // Place AP into the safe code, count down the number with lock mechanism in the safe code.
521 TopOfStack
= (UINTN
) Stack
+ sizeof (Stack
);
522 TopOfStack
&= ~(UINTN
) (CPU_STACK_ALIGNMENT
- 1);
523 CopyMem ((VOID
*) (UINTN
) mApHltLoopCode
, mApHltLoopCodeTemplate
, sizeof (mApHltLoopCodeTemplate
));
524 TransferApToSafeState ((UINTN
)mApHltLoopCode
, TopOfStack
, (UINTN
)&mNumberToFinish
);
528 Prepares startup vector for APs.
530 This function prepares startup vector for APs.
532 @param WorkingBuffer The address of the work buffer.
535 PrepareApStartupVector (
536 EFI_PHYSICAL_ADDRESS WorkingBuffer
539 EFI_PHYSICAL_ADDRESS StartupVector
;
540 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
543 // Get the address map of startup code for AP,
544 // including code size, and offset of long jump instructions to redirect.
546 ZeroMem (&AddressMap
, sizeof (AddressMap
));
547 AsmGetAddressMap (&AddressMap
);
549 StartupVector
= WorkingBuffer
;
552 // Copy AP startup code to startup vector, and then redirect the long jump
553 // instructions for mode switching.
555 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
556 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
557 if (AddressMap
.LongJumpOffset
!= 0) {
558 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
562 // Get the start address of exchange data between BSP and AP.
564 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
565 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
567 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
568 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
570 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
571 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
572 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
573 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
574 mExchangeInfo
->InitializeFloatingPointUnitsAddress
= (UINTN
)InitializeFloatingPointUnits
;
578 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
580 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
581 and restores MTRRs for both BSP and APs.
585 InitializeCpuBeforeRebase (
589 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
593 ProgramVirtualWireMode ();
595 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
597 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
598 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) InitializeAp
;
601 // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
603 mInitApsAfterSmmBaseReloc
= FALSE
;
606 // Send INIT IPI - SIPI to all APs
608 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
610 while (mNumberToFinish
> 0) {
616 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
618 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
619 data saved by normal boot path for both BSP and APs.
623 InitializeCpuAfterRebase (
627 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
630 // Signal that SMM base relocation is complete and to continue initialization for all APs.
632 mInitApsAfterSmmBaseReloc
= TRUE
;
635 // Must begin set register after all APs have continue their initialization.
636 // This is a requirement to support semaphore mechanism in register table.
637 // Because if semaphore's dependence type is package type, semaphore will wait
638 // for all Aps in one package finishing their tasks before set next register
639 // for all APs. If the Aps not begin its task during BSP doing its task, the
640 // BSP thread will hang because it is waiting for other Aps in the same
641 // package finishing their task.
645 while (mNumberToFinish
> 0) {
651 Restore SMM Configuration in S3 boot path.
655 RestoreSmmConfigurationInS3 (
659 if (!mAcpiS3Enable
) {
664 // Restore SMM Configuration in S3 boot path.
666 if (mRestoreSmmConfigurationInS3
) {
668 // Need make sure gSmst is correct because below function may use them.
670 gSmst
->SmmStartupThisAp
= gSmmCpuPrivate
->SmmCoreEntryContext
.SmmStartupThisAp
;
671 gSmst
->CurrentlyExecutingCpu
= gSmmCpuPrivate
->SmmCoreEntryContext
.CurrentlyExecutingCpu
;
672 gSmst
->NumberOfCpus
= gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
673 gSmst
->CpuSaveStateSize
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveStateSize
;
674 gSmst
->CpuSaveState
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveState
;
677 // Configure SMM Code Access Check feature if available.
679 ConfigSmmCodeAccessCheck ();
681 SmmCpuFeaturesCompleteSmmReadyToLock ();
683 mRestoreSmmConfigurationInS3
= FALSE
;
688 Perform SMM initialization for all processors in the S3 boot path.
690 For a native platform, MP initialization in the S3 boot path is also performed in this function.
698 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
699 IA32_DESCRIPTOR Ia32Idtr
;
700 IA32_DESCRIPTOR X64Idtr
;
701 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable
[EXCEPTION_VECTOR_NUMBER
];
704 DEBUG ((EFI_D_INFO
, "SmmRestoreCpu()\n"));
709 // See if there is enough context to resume PEI Phase
711 if (mSmmS3ResumeState
== NULL
) {
712 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
716 SmmS3ResumeState
= mSmmS3ResumeState
;
717 ASSERT (SmmS3ResumeState
!= NULL
);
719 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
721 // Save the IA32 IDT Descriptor
723 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
726 // Setup X64 IDT table
728 ZeroMem (IdtEntryTable
, sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32);
729 X64Idtr
.Base
= (UINTN
) IdtEntryTable
;
730 X64Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32 - 1);
731 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &X64Idtr
);
734 // Setup the default exception handler
736 Status
= InitializeCpuExceptionHandlers (NULL
);
737 ASSERT_EFI_ERROR (Status
);
740 // Initialize Debug Agent to support source level debug
742 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
, (VOID
*)&Ia32Idtr
, NULL
);
746 // Skip initialization if mAcpiCpuData is not valid
748 if (mAcpiCpuData
.NumberOfCpus
> 0) {
750 // First time microcode load and restore MTRRs
752 InitializeCpuBeforeRebase ();
756 // Restore SMBASE for BSP and all APs
761 // Skip initialization if mAcpiCpuData is not valid
763 if (mAcpiCpuData
.NumberOfCpus
> 0) {
765 // Restore MSRs for BSP and all APs
767 InitializeCpuAfterRebase ();
771 // Set a flag to restore SMM configuration in S3 path.
773 mRestoreSmmConfigurationInS3
= TRUE
;
775 DEBUG (( EFI_D_INFO
, "SMM S3 Return CS = %x\n", SmmS3ResumeState
->ReturnCs
));
776 DEBUG (( EFI_D_INFO
, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState
->ReturnEntryPoint
));
777 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState
->ReturnContext1
));
778 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState
->ReturnContext2
));
779 DEBUG (( EFI_D_INFO
, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState
->ReturnStackPointer
));
782 // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
784 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_32
) {
785 DEBUG ((EFI_D_INFO
, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
788 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)SmmS3ResumeState
->ReturnEntryPoint
,
789 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext1
,
790 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext2
,
791 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnStackPointer
796 // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
798 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
799 DEBUG ((EFI_D_INFO
, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
801 // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
803 SaveAndSetDebugTimerInterrupt (FALSE
);
805 // Restore IA32 IDT table
807 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
809 SmmS3ResumeState
->ReturnCs
,
810 (UINT32
)SmmS3ResumeState
->ReturnEntryPoint
,
811 (UINT32
)SmmS3ResumeState
->ReturnContext1
,
812 (UINT32
)SmmS3ResumeState
->ReturnContext2
,
813 (UINT32
)SmmS3ResumeState
->ReturnStackPointer
818 // Can not resume PEI Phase
820 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
825 Initialize SMM S3 resume state structure used during S3 Resume.
827 @param[in] Cr3 The base address of the page tables to use in SMM.
831 InitSmmS3ResumeState (
836 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
837 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
838 EFI_PHYSICAL_ADDRESS Address
;
841 if (!mAcpiS3Enable
) {
845 GuidHob
= GetFirstGuidHob (&gEfiAcpiVariableGuid
);
846 if (GuidHob
== NULL
) {
849 "ERROR:%a(): HOB(gEfiAcpiVariableGuid=%g) needed by S3 resume doesn't exist!\n",
851 &gEfiAcpiVariableGuid
855 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
857 DEBUG ((EFI_D_INFO
, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor
));
858 DEBUG ((EFI_D_INFO
, "SMM S3 Structure = %x\n", SmramDescriptor
->CpuStart
));
860 SmmS3ResumeState
= (SMM_S3_RESUME_STATE
*)(UINTN
)SmramDescriptor
->CpuStart
;
861 ZeroMem (SmmS3ResumeState
, sizeof (SMM_S3_RESUME_STATE
));
863 mSmmS3ResumeState
= SmmS3ResumeState
;
864 SmmS3ResumeState
->Smst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)gSmst
;
866 SmmS3ResumeState
->SmmS3ResumeEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)SmmRestoreCpu
;
868 SmmS3ResumeState
->SmmS3StackSize
= SIZE_32KB
;
869 SmmS3ResumeState
->SmmS3StackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)SmmS3ResumeState
->SmmS3StackSize
));
870 if (SmmS3ResumeState
->SmmS3StackBase
== 0) {
871 SmmS3ResumeState
->SmmS3StackSize
= 0;
874 SmmS3ResumeState
->SmmS3Cr0
= mSmmCr0
;
875 SmmS3ResumeState
->SmmS3Cr3
= Cr3
;
876 SmmS3ResumeState
->SmmS3Cr4
= mSmmCr4
;
878 if (sizeof (UINTN
) == sizeof (UINT64
)) {
879 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_64
;
881 if (sizeof (UINTN
) == sizeof (UINT32
)) {
882 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_32
;
886 // Patch SmmS3ResumeState->SmmS3Cr3
892 // Allocate safe memory in ACPI NVS for AP to execute hlt loop in
893 // protected mode on S3 path
895 Address
= BASE_4GB
- 1;
896 Status
= gBS
->AllocatePages (
899 EFI_SIZE_TO_PAGES (sizeof (mApHltLoopCodeTemplate
)),
902 ASSERT_EFI_ERROR (Status
);
903 mApHltLoopCode
= (UINT8
*) (UINTN
) Address
;
907 Copy register table from ACPI NVS memory into SMRAM.
909 @param[in] DestinationRegisterTableList Points to destination register table.
910 @param[in] SourceRegisterTableList Points to source register table.
911 @param[in] NumberOfCpus Number of CPUs.
916 IN CPU_REGISTER_TABLE
*DestinationRegisterTableList
,
917 IN CPU_REGISTER_TABLE
*SourceRegisterTableList
,
918 IN UINT32 NumberOfCpus
922 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
924 CopyMem (DestinationRegisterTableList
, SourceRegisterTableList
, NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
925 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
926 if (DestinationRegisterTableList
[Index
].AllocatedSize
!= 0) {
927 RegisterTableEntry
= AllocateCopyPool (
928 DestinationRegisterTableList
[Index
].AllocatedSize
,
929 (VOID
*)(UINTN
)SourceRegisterTableList
[Index
].RegisterTableEntry
931 ASSERT (RegisterTableEntry
!= NULL
);
932 DestinationRegisterTableList
[Index
].RegisterTableEntry
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RegisterTableEntry
;
946 ACPI_CPU_DATA
*AcpiCpuData
;
947 IA32_DESCRIPTOR
*Gdtr
;
948 IA32_DESCRIPTOR
*Idtr
;
951 VOID
*MachineCheckHandlerForAp
;
952 CPU_STATUS_INFORMATION
*CpuStatus
;
954 if (!mAcpiS3Enable
) {
959 // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
961 mAcpiCpuData
.NumberOfCpus
= 0;
964 // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
966 AcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
967 if (AcpiCpuData
== 0) {
972 // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
974 CopyMem (&mAcpiCpuData
, AcpiCpuData
, sizeof (mAcpiCpuData
));
976 mAcpiCpuData
.MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (MTRR_SETTINGS
));
977 ASSERT (mAcpiCpuData
.MtrrTable
!= 0);
979 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.MtrrTable
, (VOID
*)(UINTN
)AcpiCpuData
->MtrrTable
, sizeof (MTRR_SETTINGS
));
981 mAcpiCpuData
.GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
982 ASSERT (mAcpiCpuData
.GdtrProfile
!= 0);
984 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.GdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
986 mAcpiCpuData
.IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
987 ASSERT (mAcpiCpuData
.IdtrProfile
!= 0);
989 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.IdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
991 mAcpiCpuData
.PreSmmInitRegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
992 ASSERT (mAcpiCpuData
.PreSmmInitRegisterTable
!= 0);
995 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.PreSmmInitRegisterTable
,
996 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->PreSmmInitRegisterTable
,
997 mAcpiCpuData
.NumberOfCpus
1000 mAcpiCpuData
.RegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
1001 ASSERT (mAcpiCpuData
.RegisterTable
!= 0);
1004 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.RegisterTable
,
1005 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
,
1006 mAcpiCpuData
.NumberOfCpus
1010 // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
1012 Gdtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.GdtrProfile
;
1013 Idtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.IdtrProfile
;
1015 GdtForAp
= AllocatePool ((Gdtr
->Limit
+ 1) + (Idtr
->Limit
+ 1) + mAcpiCpuData
.ApMachineCheckHandlerSize
);
1016 ASSERT (GdtForAp
!= NULL
);
1017 IdtForAp
= (VOID
*) ((UINTN
)GdtForAp
+ (Gdtr
->Limit
+ 1));
1018 MachineCheckHandlerForAp
= (VOID
*) ((UINTN
)IdtForAp
+ (Idtr
->Limit
+ 1));
1020 CopyMem (GdtForAp
, (VOID
*)Gdtr
->Base
, Gdtr
->Limit
+ 1);
1021 CopyMem (IdtForAp
, (VOID
*)Idtr
->Base
, Idtr
->Limit
+ 1);
1022 CopyMem (MachineCheckHandlerForAp
, (VOID
*)(UINTN
)mAcpiCpuData
.ApMachineCheckHandlerBase
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
1024 Gdtr
->Base
= (UINTN
)GdtForAp
;
1025 Idtr
->Base
= (UINTN
)IdtForAp
;
1026 mAcpiCpuData
.ApMachineCheckHandlerBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MachineCheckHandlerForAp
;
1028 CpuStatus
= &mAcpiCpuData
.CpuStatus
;
1029 CopyMem (CpuStatus
, &AcpiCpuData
->CpuStatus
, sizeof (CPU_STATUS_INFORMATION
));
1030 if (AcpiCpuData
->CpuStatus
.ValidCoreCountPerPackage
!= 0) {
1031 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1032 sizeof (UINT32
) * CpuStatus
->PackageCount
,
1033 (UINT32
*)(UINTN
)AcpiCpuData
->CpuStatus
.ValidCoreCountPerPackage
1035 ASSERT (CpuStatus
->ValidCoreCountPerPackage
!= 0);
1037 if (AcpiCpuData
->ApLocation
!= 0) {
1038 mAcpiCpuData
.ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateCopyPool (
1039 mAcpiCpuData
.NumberOfCpus
* sizeof (EFI_CPU_PHYSICAL_LOCATION
),
1040 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
1042 ASSERT (mAcpiCpuData
.ApLocation
!= 0);
1044 if (CpuStatus
->PackageCount
!= 0) {
1045 mCpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (
1046 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1047 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1049 ASSERT (mCpuFlags
.CoreSemaphoreCount
!= NULL
);
1050 mCpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (
1051 sizeof (UINT32
) * CpuStatus
->PackageCount
*
1052 CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
1054 ASSERT (mCpuFlags
.PackageSemaphoreCount
!= NULL
);
1056 InitializeSpinLock((SPIN_LOCK
*) &mCpuFlags
.MemoryMappedLock
);
1057 InitializeSpinLock((SPIN_LOCK
*) &mCpuFlags
.ConsoleLogLock
);
1061 Get ACPI S3 enable flag.
1065 GetAcpiS3EnableFlag (
1069 mAcpiS3Enable
= PcdGetBool (PcdAcpiS3Enable
);