TianoCore EDK2 master
Loading...
Searching...
No Matches
CpuS3.c
Go to the documentation of this file.
1
9#include "PiSmmCpuCommon.h"
10#include <PiPei.h>
11
12BOOLEAN mRestoreSmmConfigurationInS3 = FALSE;
13
14//
15// S3 boot flag
16//
17BOOLEAN mSmmS3Flag = FALSE;
18
19//
20// Pointer to structure used during S3 Resume
21//
22SMM_S3_RESUME_STATE *mSmmS3ResumeState = NULL;
23
24BOOLEAN mAcpiS3Enable = TRUE;
25
30VOID
32 VOID
33 )
34{
35 if (!mAcpiS3Enable) {
36 return;
37 }
38
39 //
40 // Restore SMM Configuration in S3 boot path.
41 //
42 if (mRestoreSmmConfigurationInS3) {
43 //
44 // Need make sure gMmst is correct because below function may use them.
45 //
46 gMmst->MmStartupThisAp = gSmmCpuPrivate->SmmCoreEntryContext.SmmStartupThisAp;
47 gMmst->CurrentlyExecutingCpu = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;
48 gMmst->NumberOfCpus = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
49 gMmst->CpuSaveStateSize = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveStateSize;
50 gMmst->CpuSaveState = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveState;
51
52 //
53 // Configure SMM Code Access Check feature if available.
54 //
56
58
59 mRestoreSmmConfigurationInS3 = FALSE;
60 }
61}
62
68VOID
69EFIAPI
71 VOID
72 )
73{
74 SMM_S3_RESUME_STATE *SmmS3ResumeState;
75 IA32_DESCRIPTOR Ia32Idtr;
76 IA32_DESCRIPTOR X64Idtr;
77 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
78 EFI_STATUS Status;
79
80 DEBUG ((DEBUG_INFO, "SmmRestoreCpu()\n"));
81
82 mSmmS3Flag = TRUE;
83
84 //
85 // See if there is enough context to resume PEI Phase
86 //
87 if (mSmmS3ResumeState == NULL) {
88 DEBUG ((DEBUG_ERROR, "No context to return to PEI Phase\n"));
89 CpuDeadLoop ();
90 }
91
92 SmmS3ResumeState = mSmmS3ResumeState;
93 ASSERT (SmmS3ResumeState != NULL);
94
95 //
96 // Setup 64bit IDT in 64bit SMM env when called from 32bit PEI.
97 // Note: 64bit PEI and 32bit DXE is not a supported combination.
98 //
99 if ((SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode) == TRUE)) {
100 //
101 // Save the IA32 IDT Descriptor
102 //
103 AsmReadIdtr ((IA32_DESCRIPTOR *)&Ia32Idtr);
104
105 //
106 // Setup X64 IDT table
107 //
108 ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32);
109 X64Idtr.Base = (UINTN)IdtEntryTable;
110 X64Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1);
111 AsmWriteIdtr ((IA32_DESCRIPTOR *)&X64Idtr);
112
113 //
114 // Setup the default exception handler
115 //
116 Status = InitializeCpuExceptionHandlers (NULL);
117 ASSERT_EFI_ERROR (Status);
118
119 //
120 // Initialize Debug Agent to support source level debug
121 //
122 if (mSmmDebugAgentSupport) {
123 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);
124 }
125 }
126
127 //
128 // Issue SMI IPI (All Excluding Self SMM IPI + BSP SMM IPI) to execute first SMI init.
129 //
131
132 //
133 // Set a flag to restore SMM configuration in S3 path.
134 //
135 mRestoreSmmConfigurationInS3 = TRUE;
136
137 DEBUG ((DEBUG_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs));
138 DEBUG ((DEBUG_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint));
139 DEBUG ((DEBUG_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1));
140 DEBUG ((DEBUG_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2));
141 DEBUG ((DEBUG_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer));
142
143 //
144 // If SMM is in 32-bit mode or PcdDxeIplSwitchToLongMode is FALSE, then use SwitchStack() to resume PEI Phase.
145 // Note: 64bit PEI and 32bit DXE is not a supported combination.
146 //
147 if ((SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) || (FeaturePcdGet (PcdDxeIplSwitchToLongMode) == FALSE)) {
148 DEBUG ((DEBUG_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
149
151 (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint,
152 (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1,
153 (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2,
154 (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer
155 );
156 }
157
158 //
159 // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
160 //
161 if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
162 DEBUG ((DEBUG_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
163 //
164 // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
165 //
167 //
168 // Restore IA32 IDT table
169 //
170 AsmWriteIdtr ((IA32_DESCRIPTOR *)&Ia32Idtr);
172 SmmS3ResumeState->ReturnCs,
173 (UINT32)SmmS3ResumeState->ReturnEntryPoint,
174 (UINT32)SmmS3ResumeState->ReturnContext1,
175 (UINT32)SmmS3ResumeState->ReturnContext2,
176 (UINT32)SmmS3ResumeState->ReturnStackPointer
177 );
178 }
179
180 //
181 // Can not resume PEI Phase
182 //
183 DEBUG ((DEBUG_ERROR, "No context to return to PEI Phase\n"));
184 CpuDeadLoop ();
185}
186
191VOID
193 VOID
194 )
195{
196 VOID *GuidHob;
197 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
198 SMM_S3_RESUME_STATE *SmmS3ResumeState;
199
200 if (!mAcpiS3Enable) {
201 return;
202 }
203
204 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
205 if (GuidHob == NULL) {
206 DEBUG ((
207 DEBUG_ERROR,
208 "ERROR:%a(): HOB(gEfiAcpiVariableGuid=%g) needed by S3 resume doesn't exist!\n",
209 __func__,
210 &gEfiAcpiVariableGuid
211 ));
212 CpuDeadLoop ();
213 } else {
214 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *)GET_GUID_HOB_DATA (GuidHob);
215
216 DEBUG ((DEBUG_INFO, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor));
217 DEBUG ((DEBUG_INFO, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart));
218
219 SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
220 ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE));
221
222 mSmmS3ResumeState = SmmS3ResumeState;
223 SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gMmst;
224
225 SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu;
226
227 SmmS3ResumeState->SmmS3StackSize = SIZE_32KB;
228 SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize));
229 if (SmmS3ResumeState->SmmS3StackBase == 0) {
230 SmmS3ResumeState->SmmS3StackSize = 0;
231 }
232
233 SmmS3ResumeState->SmmS3Cr0 = (UINT32)AsmReadCr0 ();
234 SmmS3ResumeState->SmmS3Cr4 = (UINT32)AsmReadCr4 ();
235
236 if (sizeof (UINTN) == sizeof (UINT64)) {
237 SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64;
238 }
239
240 if (sizeof (UINTN) == sizeof (UINT32)) {
241 SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32;
242 }
243
244 //
245 // Patch SmmS3ResumeState->SmmS3Cr3
246 // The SmmS3Cr3 is only used by S3Resume PEIM to switch CPU from 32bit to 64bit
247 //
248 InitSmmS3Cr3 ((UINTN *)&SmmS3ResumeState->SmmS3Cr3);
249 }
250}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
VOID EFIAPI SwitchStack(IN SWITCH_STACK_ENTRY_POINT EntryPoint, IN VOID *Context1 OPTIONAL, IN VOID *Context2 OPTIONAL, IN VOID *NewStack,...)
Definition: SwitchStack.c:42
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID(EFIAPI * SWITCH_STACK_ENTRY_POINT)(IN VOID *Context1 OPTIONAL, IN VOID *Context2 OPTIONAL)
Definition: BaseLib.h:5019
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID InitSmmS3ResumeState(VOID)
Definition: CpuS3.c:192
VOID EFIAPI SmmRestoreCpu(VOID)
Definition: CpuS3.c:70
VOID RestoreSmmConfigurationInS3(VOID)
Definition: CpuS3.c:31
BOOLEAN EFIAPI SaveAndSetDebugTimerInterrupt(IN BOOLEAN EnableStatus)
VOID EFIAPI InitializeDebugAgent(IN UINT32 InitFlag, IN VOID *Context OPTIONAL, IN DEBUG_AGENT_CONTINUE Function OPTIONAL)
UINTN EFIAPI AsmReadCr0(VOID)
UINTN EFIAPI AsmReadCr4(VOID)
VOID InitSmmS3Cr3(OUT UINTN *Cr3)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID EFIAPI SmmCpuFeaturesCompleteSmmReadyToLock(VOID)
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
VOID ConfigSmmCodeAccessCheck(VOID)
VOID ExecuteFirstSmiInit(VOID)
VOID *EFIAPI AllocatePages(IN UINTN Pages)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID EFIAPI AsmDisablePaging64(IN UINT16 Cs, IN UINT32 EntryPoint, IN UINT32 Context1 OPTIONAL, IN UINT32 Context2 OPTIONAL, IN UINT32 NewStack)
VOID EFIAPI AsmReadIdtr(OUT IA32_DESCRIPTOR *Idtr)
Definition: X86ReadIdtr.c:24
VOID EFIAPI AsmWriteIdtr(IN CONST IA32_DESCRIPTOR *Idtr)
UINTN CurrentlyExecutingCpu
Definition: PiMmCis.h:292
VOID ** CpuSaveState
Definition: PiMmCis.h:308
UINTN * CpuSaveStateSize
Definition: PiMmCis.h:302
EFI_MM_STARTUP_THIS_AP MmStartupThisAp
Definition: PiMmCis.h:282
UINTN CurrentlyExecutingCpu
Definition: PiSmmCis.h:69
UINTN * CpuSaveStateSize
Definition: PiSmmCis.h:80
EFI_PHYSICAL_ADDRESS CpuStart
Definition: PiMultiPhase.h:127