2 Code for Processor S3 restoration
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PiSmmCpuDxeSmm.h"
22 IA32_DESCRIPTOR GdtrProfile
;
23 IA32_DESCRIPTOR IdtrProfile
;
26 } MP_CPU_EXCHANGE_INFO
;
29 UINT8
*RendezvousFunnelAddress
;
30 UINTN PModeEntryOffset
;
33 UINTN LModeEntryOffset
;
35 } MP_ASSEMBLY_ADDRESS_MAP
;
38 // Spin lock used to serialize MemoryMapped operation
40 SPIN_LOCK
*mMemoryMappedLock
= NULL
;
43 // Signal that SMM BASE relocation is complete.
45 volatile BOOLEAN mInitApsAfterSmmBaseReloc
;
48 Get starting address and size of the rendezvous entry for APs.
49 Information for fixing a jump instruction in the code is also returned.
51 @param AddressMap Output buffer for address map information.
56 MP_ASSEMBLY_ADDRESS_MAP
*AddressMap
59 #define LEGACY_REGION_SIZE (2 * 0x1000)
60 #define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
62 ACPI_CPU_DATA mAcpiCpuData
;
63 volatile UINT32 mNumberToFinish
;
64 MP_CPU_EXCHANGE_INFO
*mExchangeInfo
;
65 BOOLEAN mRestoreSmmConfigurationInS3
= FALSE
;
66 VOID
*mGdtForAp
= NULL
;
67 VOID
*mIdtForAp
= NULL
;
68 VOID
*mMachineCheckHandlerForAp
= NULL
;
69 MP_MSR_LOCK
*mMsrSpinLocks
= NULL
;
70 UINTN mMsrSpinLockCount
;
76 BOOLEAN mSmmS3Flag
= FALSE
;
79 // Pointer to structure used during S3 Resume
81 SMM_S3_RESUME_STATE
*mSmmS3ResumeState
= NULL
;
83 BOOLEAN mAcpiS3Enable
= TRUE
;
85 UINT8
*mApHltLoopCode
= NULL
;
86 UINT8 mApHltLoopCodeTemplate
[] = {
87 0x8B, 0x44, 0x24, 0x04, // mov eax, dword ptr [esp+4]
88 0xF0, 0xFF, 0x08, // lock dec dword ptr [eax]
95 Get MSR spin lock by MSR index.
97 @param MsrIndex MSR index value.
99 @return Pointer to MSR spin lock.
103 GetMsrSpinLockByIndex (
108 for (Index
= 0; Index
< mMsrCount
; Index
++) {
109 if (MsrIndex
== mMsrSpinLocks
[Index
].MsrIndex
) {
110 return mMsrSpinLocks
[Index
].SpinLock
;
117 Initialize MSR spin lock by MSR index.
119 @param MsrIndex MSR index value.
123 InitMsrSpinLockByIndex (
127 UINTN MsrSpinLockCount
;
128 UINTN NewMsrSpinLockCount
;
132 if (mMsrSpinLocks
== NULL
) {
133 MsrSpinLockCount
= mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
;
134 mMsrSpinLocks
= (MP_MSR_LOCK
*) AllocatePool (sizeof (MP_MSR_LOCK
) * MsrSpinLockCount
);
135 ASSERT (mMsrSpinLocks
!= NULL
);
136 for (Index
= 0; Index
< MsrSpinLockCount
; Index
++) {
137 mMsrSpinLocks
[Index
].SpinLock
=
138 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+ Index
* mSemaphoreSize
);
139 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
141 mMsrSpinLockCount
= MsrSpinLockCount
;
142 mSmmCpuSemaphores
.SemaphoreMsr
.AvailableCounter
= 0;
144 if (GetMsrSpinLockByIndex (MsrIndex
) == NULL
) {
146 // Initialize spin lock for MSR programming
148 mMsrSpinLocks
[mMsrCount
].MsrIndex
= MsrIndex
;
149 InitializeSpinLock (mMsrSpinLocks
[mMsrCount
].SpinLock
);
151 if (mMsrCount
== mMsrSpinLockCount
) {
153 // If MSR spin lock buffer is full, enlarge it
155 AddedSize
= SIZE_4KB
;
156 mSmmCpuSemaphores
.SemaphoreMsr
.Msr
=
157 AllocatePages (EFI_SIZE_TO_PAGES(AddedSize
));
158 ASSERT (mSmmCpuSemaphores
.SemaphoreMsr
.Msr
!= NULL
);
159 NewMsrSpinLockCount
= mMsrSpinLockCount
+ AddedSize
/ mSemaphoreSize
;
160 mMsrSpinLocks
= ReallocatePool (
161 sizeof (MP_MSR_LOCK
) * mMsrSpinLockCount
,
162 sizeof (MP_MSR_LOCK
) * NewMsrSpinLockCount
,
165 ASSERT (mMsrSpinLocks
!= NULL
);
166 mMsrSpinLockCount
= NewMsrSpinLockCount
;
167 for (Index
= mMsrCount
; Index
< mMsrSpinLockCount
; Index
++) {
168 mMsrSpinLocks
[Index
].SpinLock
=
169 (SPIN_LOCK
*)((UINTN
)mSmmCpuSemaphores
.SemaphoreMsr
.Msr
+
170 (Index
- mMsrCount
) * mSemaphoreSize
);
171 mMsrSpinLocks
[Index
].MsrIndex
= (UINT32
)-1;
178 Sync up the MTRR values for all processors.
180 @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
185 EFI_PHYSICAL_ADDRESS MtrrTable
191 Sync up the MTRR values for all processors.
200 MTRR_SETTINGS
*MtrrSettings
;
202 MtrrSettings
= (MTRR_SETTINGS
*) (UINTN
) MtrrTable
;
203 MtrrSetAllMtrrs (MtrrSettings
);
207 Programs registers for the calling processor.
209 This function programs registers for the calling processor.
211 @param RegisterTable Pointer to register table of the running processor.
215 SetProcessorRegister (
216 IN CPU_REGISTER_TABLE
*RegisterTable
219 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
222 SPIN_LOCK
*MsrSpinLock
;
225 // Traverse Register Table of this logical processor
227 RegisterTableEntry
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
228 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++, RegisterTableEntry
++) {
230 // Check the type of specified register
232 switch (RegisterTableEntry
->RegisterType
) {
234 // The specified register is Control Register
236 case ControlRegister
:
237 switch (RegisterTableEntry
->Index
) {
239 Value
= AsmReadCr0 ();
240 Value
= (UINTN
) BitFieldWrite64 (
242 RegisterTableEntry
->ValidBitStart
,
243 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
244 (UINTN
) RegisterTableEntry
->Value
249 Value
= AsmReadCr2 ();
250 Value
= (UINTN
) BitFieldWrite64 (
252 RegisterTableEntry
->ValidBitStart
,
253 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
254 (UINTN
) RegisterTableEntry
->Value
259 Value
= AsmReadCr3 ();
260 Value
= (UINTN
) BitFieldWrite64 (
262 RegisterTableEntry
->ValidBitStart
,
263 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
264 (UINTN
) RegisterTableEntry
->Value
269 Value
= AsmReadCr4 ();
270 Value
= (UINTN
) BitFieldWrite64 (
272 RegisterTableEntry
->ValidBitStart
,
273 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
274 (UINTN
) RegisterTableEntry
->Value
283 // The specified register is Model Specific Register
287 // If this function is called to restore register setting after INIT signal,
288 // there is no need to restore MSRs in register table.
290 if (RegisterTableEntry
->ValidBitLength
>= 64) {
292 // If length is not less than 64 bits, then directly write without reading
295 RegisterTableEntry
->Index
,
296 RegisterTableEntry
->Value
300 // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
301 // to make sure MSR read/write operation is atomic.
303 MsrSpinLock
= GetMsrSpinLockByIndex (RegisterTableEntry
->Index
);
304 AcquireSpinLock (MsrSpinLock
);
306 // Set the bit section according to bit start and length
308 AsmMsrBitFieldWrite64 (
309 RegisterTableEntry
->Index
,
310 RegisterTableEntry
->ValidBitStart
,
311 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
312 RegisterTableEntry
->Value
314 ReleaseSpinLock (MsrSpinLock
);
318 // MemoryMapped operations
321 AcquireSpinLock (mMemoryMappedLock
);
322 MmioBitFieldWrite32 (
323 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
324 RegisterTableEntry
->ValidBitStart
,
325 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
326 (UINT32
)RegisterTableEntry
->Value
328 ReleaseSpinLock (mMemoryMappedLock
);
331 // Enable or disable cache
335 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
337 if (RegisterTableEntry
->Value
== 0) {
353 AP initialization before then after SMBASE relocation in the S3 boot path.
356 MPRendezvousProcedure (
360 CPU_REGISTER_TABLE
*RegisterTableList
;
366 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
369 // Find processor number for this CPU.
371 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
372 InitApicId
= GetInitialApicId ();
373 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
374 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
375 SetProcessorRegister (&RegisterTableList
[Index
]);
382 // Count down the number with lock mechanism.
384 InterlockedDecrement (&mNumberToFinish
);
387 // Wait for BSP to signal SMM Base relocation done.
389 while (!mInitApsAfterSmmBaseReloc
) {
393 ProgramVirtualWireMode ();
394 DisableLvtInterrupts ();
396 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
397 InitApicId
= GetInitialApicId ();
398 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
399 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
400 SetProcessorRegister (&RegisterTableList
[Index
]);
406 // Place AP into the safe code, count down the number with lock mechanism in the safe code.
408 TopOfStack
= (UINTN
) Stack
+ sizeof (Stack
);
409 TopOfStack
&= ~(UINTN
) (CPU_STACK_ALIGNMENT
- 1);
410 CopyMem ((VOID
*) (UINTN
) mApHltLoopCode
, mApHltLoopCodeTemplate
, sizeof (mApHltLoopCodeTemplate
));
411 TransferApToSafeState ((UINTN
)mApHltLoopCode
, TopOfStack
, (UINTN
)&mNumberToFinish
);
415 Prepares startup vector for APs.
417 This function prepares startup vector for APs.
419 @param WorkingBuffer The address of the work buffer.
422 PrepareApStartupVector (
423 EFI_PHYSICAL_ADDRESS WorkingBuffer
426 EFI_PHYSICAL_ADDRESS StartupVector
;
427 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
430 // Get the address map of startup code for AP,
431 // including code size, and offset of long jump instructions to redirect.
433 ZeroMem (&AddressMap
, sizeof (AddressMap
));
434 AsmGetAddressMap (&AddressMap
);
436 StartupVector
= WorkingBuffer
;
439 // Copy AP startup code to startup vector, and then redirect the long jump
440 // instructions for mode switching.
442 CopyMem ((VOID
*) (UINTN
) StartupVector
, AddressMap
.RendezvousFunnelAddress
, AddressMap
.Size
);
443 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.FlatJumpOffset
+ 3) = (UINT32
) (StartupVector
+ AddressMap
.PModeEntryOffset
);
444 if (AddressMap
.LongJumpOffset
!= 0) {
445 *(UINT32
*) (UINTN
) (StartupVector
+ AddressMap
.LongJumpOffset
+ 2) = (UINT32
) (StartupVector
+ AddressMap
.LModeEntryOffset
);
449 // Get the start address of exchange data between BSP and AP.
451 mExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (StartupVector
+ AddressMap
.Size
);
452 ZeroMem ((VOID
*) mExchangeInfo
, sizeof (MP_CPU_EXCHANGE_INFO
));
454 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->GdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
455 CopyMem ((VOID
*) (UINTN
) &mExchangeInfo
->IdtrProfile
, (VOID
*) (UINTN
) mAcpiCpuData
.IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
458 // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
460 CopyMem ((VOID
*) mExchangeInfo
->GdtrProfile
.Base
, mGdtForAp
, mExchangeInfo
->GdtrProfile
.Limit
+ 1);
461 CopyMem ((VOID
*) mExchangeInfo
->IdtrProfile
.Base
, mIdtForAp
, mExchangeInfo
->IdtrProfile
.Limit
+ 1);
462 CopyMem ((VOID
*)(UINTN
) mAcpiCpuData
.ApMachineCheckHandlerBase
, mMachineCheckHandlerForAp
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
464 mExchangeInfo
->StackStart
= (VOID
*) (UINTN
) mAcpiCpuData
.StackAddress
;
465 mExchangeInfo
->StackSize
= mAcpiCpuData
.StackSize
;
466 mExchangeInfo
->BufferStart
= (UINT32
) StartupVector
;
467 mExchangeInfo
->Cr3
= (UINT32
) (AsmReadCr3 ());
471 The function is invoked before SMBASE relocation in S3 path to restores CPU status.
473 The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
474 and restores MTRRs for both BSP and APs.
482 CPU_REGISTER_TABLE
*RegisterTableList
;
486 LoadMtrrData (mAcpiCpuData
.MtrrTable
);
489 // Find processor number for this CPU.
491 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.PreSmmInitRegisterTable
;
492 InitApicId
= GetInitialApicId ();
493 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
494 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
495 SetProcessorRegister (&RegisterTableList
[Index
]);
500 ProgramVirtualWireMode ();
502 PrepareApStartupVector (mAcpiCpuData
.StartupVector
);
504 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
505 mExchangeInfo
->ApFunction
= (VOID
*) (UINTN
) MPRendezvousProcedure
;
508 // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
510 mInitApsAfterSmmBaseReloc
= FALSE
;
513 // Send INIT IPI - SIPI to all APs
515 SendInitSipiSipiAllExcludingSelf ((UINT32
)mAcpiCpuData
.StartupVector
);
517 while (mNumberToFinish
> 0) {
523 The function is invoked after SMBASE relocation in S3 path to restores CPU status.
525 The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
526 data saved by normal boot path for both BSP and APs.
534 CPU_REGISTER_TABLE
*RegisterTableList
;
538 RegisterTableList
= (CPU_REGISTER_TABLE
*) (UINTN
) mAcpiCpuData
.RegisterTable
;
539 InitApicId
= GetInitialApicId ();
540 for (Index
= 0; Index
< mAcpiCpuData
.NumberOfCpus
; Index
++) {
541 if (RegisterTableList
[Index
].InitialApicId
== InitApicId
) {
542 SetProcessorRegister (&RegisterTableList
[Index
]);
547 mNumberToFinish
= mAcpiCpuData
.NumberOfCpus
- 1;
550 // Signal that SMM base relocation is complete and to continue initialization.
552 mInitApsAfterSmmBaseReloc
= TRUE
;
554 while (mNumberToFinish
> 0) {
560 Restore SMM Configuration in S3 boot path.
564 RestoreSmmConfigurationInS3 (
568 if (!mAcpiS3Enable
) {
573 // Restore SMM Configuration in S3 boot path.
575 if (mRestoreSmmConfigurationInS3
) {
577 // Need make sure gSmst is correct because below function may use them.
579 gSmst
->SmmStartupThisAp
= gSmmCpuPrivate
->SmmCoreEntryContext
.SmmStartupThisAp
;
580 gSmst
->CurrentlyExecutingCpu
= gSmmCpuPrivate
->SmmCoreEntryContext
.CurrentlyExecutingCpu
;
581 gSmst
->NumberOfCpus
= gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
582 gSmst
->CpuSaveStateSize
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveStateSize
;
583 gSmst
->CpuSaveState
= gSmmCpuPrivate
->SmmCoreEntryContext
.CpuSaveState
;
586 // Configure SMM Code Access Check feature if available.
588 ConfigSmmCodeAccessCheck ();
590 SmmCpuFeaturesCompleteSmmReadyToLock ();
592 mRestoreSmmConfigurationInS3
= FALSE
;
597 Perform SMM initialization for all processors in the S3 boot path.
599 For a native platform, MP initialization in the S3 boot path is also performed in this function.
607 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
608 IA32_DESCRIPTOR Ia32Idtr
;
609 IA32_DESCRIPTOR X64Idtr
;
610 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable
[EXCEPTION_VECTOR_NUMBER
];
613 DEBUG ((EFI_D_INFO
, "SmmRestoreCpu()\n"));
617 InitializeSpinLock (mMemoryMappedLock
);
620 // See if there is enough context to resume PEI Phase
622 if (mSmmS3ResumeState
== NULL
) {
623 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
627 SmmS3ResumeState
= mSmmS3ResumeState
;
628 ASSERT (SmmS3ResumeState
!= NULL
);
630 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
632 // Save the IA32 IDT Descriptor
634 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
637 // Setup X64 IDT table
639 ZeroMem (IdtEntryTable
, sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32);
640 X64Idtr
.Base
= (UINTN
) IdtEntryTable
;
641 X64Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 32 - 1);
642 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &X64Idtr
);
645 // Setup the default exception handler
647 Status
= InitializeCpuExceptionHandlers (NULL
);
648 ASSERT_EFI_ERROR (Status
);
651 // Initialize Debug Agent to support source level debug
653 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64
, (VOID
*)&Ia32Idtr
, NULL
);
657 // Skip initialization if mAcpiCpuData is not valid
659 if (mAcpiCpuData
.NumberOfCpus
> 0) {
661 // First time microcode load and restore MTRRs
663 EarlyInitializeCpu ();
667 // Restore SMBASE for BSP and all APs
672 // Skip initialization if mAcpiCpuData is not valid
674 if (mAcpiCpuData
.NumberOfCpus
> 0) {
676 // Restore MSRs for BSP and all APs
682 // Set a flag to restore SMM configuration in S3 path.
684 mRestoreSmmConfigurationInS3
= TRUE
;
686 DEBUG (( EFI_D_INFO
, "SMM S3 Return CS = %x\n", SmmS3ResumeState
->ReturnCs
));
687 DEBUG (( EFI_D_INFO
, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState
->ReturnEntryPoint
));
688 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState
->ReturnContext1
));
689 DEBUG (( EFI_D_INFO
, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState
->ReturnContext2
));
690 DEBUG (( EFI_D_INFO
, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState
->ReturnStackPointer
));
693 // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
695 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_32
) {
696 DEBUG ((EFI_D_INFO
, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
699 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)SmmS3ResumeState
->ReturnEntryPoint
,
700 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext1
,
701 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnContext2
,
702 (VOID
*)(UINTN
)SmmS3ResumeState
->ReturnStackPointer
707 // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
709 if (SmmS3ResumeState
->Signature
== SMM_S3_RESUME_SMM_64
) {
710 DEBUG ((EFI_D_INFO
, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
712 // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
714 SaveAndSetDebugTimerInterrupt (FALSE
);
716 // Restore IA32 IDT table
718 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Ia32Idtr
);
720 SmmS3ResumeState
->ReturnCs
,
721 (UINT32
)SmmS3ResumeState
->ReturnEntryPoint
,
722 (UINT32
)SmmS3ResumeState
->ReturnContext1
,
723 (UINT32
)SmmS3ResumeState
->ReturnContext2
,
724 (UINT32
)SmmS3ResumeState
->ReturnStackPointer
729 // Can not resume PEI Phase
731 DEBUG ((EFI_D_ERROR
, "No context to return to PEI Phase\n"));
736 Initialize SMM S3 resume state structure used during S3 Resume.
738 @param[in] Cr3 The base address of the page tables to use in SMM.
742 InitSmmS3ResumeState (
747 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
748 SMM_S3_RESUME_STATE
*SmmS3ResumeState
;
749 EFI_PHYSICAL_ADDRESS Address
;
752 if (!mAcpiS3Enable
) {
756 GuidHob
= GetFirstGuidHob (&gEfiAcpiVariableGuid
);
757 if (GuidHob
!= NULL
) {
758 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
760 DEBUG ((EFI_D_INFO
, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor
));
761 DEBUG ((EFI_D_INFO
, "SMM S3 Structure = %x\n", SmramDescriptor
->CpuStart
));
763 SmmS3ResumeState
= (SMM_S3_RESUME_STATE
*)(UINTN
)SmramDescriptor
->CpuStart
;
764 ZeroMem (SmmS3ResumeState
, sizeof (SMM_S3_RESUME_STATE
));
766 mSmmS3ResumeState
= SmmS3ResumeState
;
767 SmmS3ResumeState
->Smst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)gSmst
;
769 SmmS3ResumeState
->SmmS3ResumeEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)SmmRestoreCpu
;
771 SmmS3ResumeState
->SmmS3StackSize
= SIZE_32KB
;
772 SmmS3ResumeState
->SmmS3StackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)SmmS3ResumeState
->SmmS3StackSize
));
773 if (SmmS3ResumeState
->SmmS3StackBase
== 0) {
774 SmmS3ResumeState
->SmmS3StackSize
= 0;
777 SmmS3ResumeState
->SmmS3Cr0
= gSmmCr0
;
778 SmmS3ResumeState
->SmmS3Cr3
= Cr3
;
779 SmmS3ResumeState
->SmmS3Cr4
= gSmmCr4
;
781 if (sizeof (UINTN
) == sizeof (UINT64
)) {
782 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_64
;
784 if (sizeof (UINTN
) == sizeof (UINT32
)) {
785 SmmS3ResumeState
->Signature
= SMM_S3_RESUME_SMM_32
;
790 // Patch SmmS3ResumeState->SmmS3Cr3
795 // Allocate safe memory in ACPI NVS for AP to execute hlt loop in
796 // protected mode on S3 path
798 Address
= BASE_4GB
- 1;
799 Status
= gBS
->AllocatePages (
802 EFI_SIZE_TO_PAGES (sizeof (mApHltLoopCodeTemplate
)),
805 ASSERT_EFI_ERROR (Status
);
806 mApHltLoopCode
= (UINT8
*) (UINTN
) Address
;
810 Copy register table from ACPI NVS memory into SMRAM.
812 @param[in] DestinationRegisterTableList Points to destination register table.
813 @param[in] SourceRegisterTableList Points to source register table.
814 @param[in] NumberOfCpus Number of CPUs.
819 IN CPU_REGISTER_TABLE
*DestinationRegisterTableList
,
820 IN CPU_REGISTER_TABLE
*SourceRegisterTableList
,
821 IN UINT32 NumberOfCpus
826 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
828 CopyMem (DestinationRegisterTableList
, SourceRegisterTableList
, NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
829 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
830 if (DestinationRegisterTableList
[Index
].AllocatedSize
!= 0) {
831 RegisterTableEntry
= AllocateCopyPool (
832 DestinationRegisterTableList
[Index
].AllocatedSize
,
833 (VOID
*)(UINTN
)SourceRegisterTableList
[Index
].RegisterTableEntry
835 ASSERT (RegisterTableEntry
!= NULL
);
836 DestinationRegisterTableList
[Index
].RegisterTableEntry
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RegisterTableEntry
;
838 // Go though all MSRs in register table to initialize MSR spin lock
840 for (Index1
= 0; Index1
< DestinationRegisterTableList
[Index
].TableLength
; Index1
++, RegisterTableEntry
++) {
841 if ((RegisterTableEntry
->RegisterType
== Msr
) && (RegisterTableEntry
->ValidBitLength
< 64)) {
843 // Initialize MSR spin lock only for those MSRs need bit field writing
845 InitMsrSpinLockByIndex (RegisterTableEntry
->Index
);
861 ACPI_CPU_DATA
*AcpiCpuData
;
862 IA32_DESCRIPTOR
*Gdtr
;
863 IA32_DESCRIPTOR
*Idtr
;
865 if (!mAcpiS3Enable
) {
870 // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
872 mAcpiCpuData
.NumberOfCpus
= 0;
875 // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
877 AcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
878 if (AcpiCpuData
== 0) {
883 // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
885 CopyMem (&mAcpiCpuData
, AcpiCpuData
, sizeof (mAcpiCpuData
));
887 mAcpiCpuData
.MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (MTRR_SETTINGS
));
888 ASSERT (mAcpiCpuData
.MtrrTable
!= 0);
890 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.MtrrTable
, (VOID
*)(UINTN
)AcpiCpuData
->MtrrTable
, sizeof (MTRR_SETTINGS
));
892 mAcpiCpuData
.GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
893 ASSERT (mAcpiCpuData
.GdtrProfile
!= 0);
895 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.GdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->GdtrProfile
, sizeof (IA32_DESCRIPTOR
));
897 mAcpiCpuData
.IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (sizeof (IA32_DESCRIPTOR
));
898 ASSERT (mAcpiCpuData
.IdtrProfile
!= 0);
900 CopyMem ((VOID
*)(UINTN
)mAcpiCpuData
.IdtrProfile
, (VOID
*)(UINTN
)AcpiCpuData
->IdtrProfile
, sizeof (IA32_DESCRIPTOR
));
902 mAcpiCpuData
.PreSmmInitRegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
903 ASSERT (mAcpiCpuData
.PreSmmInitRegisterTable
!= 0);
906 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.PreSmmInitRegisterTable
,
907 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->PreSmmInitRegisterTable
,
908 mAcpiCpuData
.NumberOfCpus
911 mAcpiCpuData
.RegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (mAcpiCpuData
.NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
));
912 ASSERT (mAcpiCpuData
.RegisterTable
!= 0);
915 (CPU_REGISTER_TABLE
*)(UINTN
)mAcpiCpuData
.RegisterTable
,
916 (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
,
917 mAcpiCpuData
.NumberOfCpus
921 // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
923 Gdtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.GdtrProfile
;
924 Idtr
= (IA32_DESCRIPTOR
*)(UINTN
)mAcpiCpuData
.IdtrProfile
;
926 mGdtForAp
= AllocatePool ((Gdtr
->Limit
+ 1) + (Idtr
->Limit
+ 1) + mAcpiCpuData
.ApMachineCheckHandlerSize
);
927 ASSERT (mGdtForAp
!= NULL
);
928 mIdtForAp
= (VOID
*) ((UINTN
)mGdtForAp
+ (Gdtr
->Limit
+ 1));
929 mMachineCheckHandlerForAp
= (VOID
*) ((UINTN
)mIdtForAp
+ (Idtr
->Limit
+ 1));
931 CopyMem (mGdtForAp
, (VOID
*)Gdtr
->Base
, Gdtr
->Limit
+ 1);
932 CopyMem (mIdtForAp
, (VOID
*)Idtr
->Base
, Idtr
->Limit
+ 1);
933 CopyMem (mMachineCheckHandlerForAp
, (VOID
*)(UINTN
)mAcpiCpuData
.ApMachineCheckHandlerBase
, mAcpiCpuData
.ApMachineCheckHandlerSize
);
937 Get ACPI S3 enable flag.
941 GetAcpiS3EnableFlag (
945 mAcpiS3Enable
= PcdGetBool (PcdAcpiS3Enable
);