]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c
UefiCpuPkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / UefiCpuPkg / Universal / Acpi / S3Resume2Pei / S3Resume.c
CommitLineData
1f569620 1/** @file\r
e48e0742 2 This module produces the EFI_PEI_S3_RESUME2_PPI.\r
1f569620 3 This module works with StandAloneBootScriptExecutor to S3 resume to OS.\r
438f1766 4 This module will execute the boot script saved during last boot and after that,\r
1f569620 5 control is passed to OS waking up handler.\r
6\r
de228fb1 7 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
787a085b 8 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
1f569620 9\r
0acd8697 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1f569620 11\r
12**/\r
13\r
14#include <PiPei.h>\r
15\r
16#include <Guid/AcpiS3Context.h>\r
17#include <Guid/BootScriptExecutorVariable.h>\r
582e4e44 18#include <Guid/ExtendedFirmwarePerformance.h>\r
a85e7127 19#include <Guid/EndOfS3Resume.h>\r
5b29e438 20#include <Guid/S3SmmInitDone.h>\r
1f569620 21#include <Ppi/S3Resume2.h>\r
22#include <Ppi/SmmAccess.h>\r
23#include <Ppi/PostBootScriptTable.h>\r
24#include <Ppi/EndOfPeiPhase.h>\r
18b13fab
ED
25#include <Ppi/SmmCommunication.h>\r
26\r
1f569620 27#include <Library/DebugLib.h>\r
28#include <Library/BaseLib.h>\r
1f569620 29#include <Library/PeimEntryPoint.h>\r
30#include <Library/PeiServicesLib.h>\r
31#include <Library/HobLib.h>\r
32#include <Library/PerformanceLib.h>\r
33#include <Library/PeiServicesTablePointerLib.h>\r
34#include <Library/IoLib.h>\r
35#include <Library/BaseMemoryLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/PcdLib.h>\r
38#include <Library/DebugAgentLib.h>\r
39#include <Library/LocalApicLib.h>\r
40#include <Library/ReportStatusCodeLib.h>\r
997731e7 41\r
c56b6566 42#include <Library/HobLib.h>\r
1f569620 43#include <Library/LockBoxLib.h>\r
44#include <IndustryStandard/Acpi.h>\r
45\r
f98f5ec3
LE
46/**\r
47 This macro aligns the address of a variable with auto storage\r
48 duration down to CPU_STACK_ALIGNMENT.\r
49\r
50 Since the stack grows downward, the result preserves more of the\r
51 stack than the original address (or the same amount), not less.\r
52**/\r
53#define STACK_ALIGN_DOWN(Ptr) \\r
54 ((UINTN)(Ptr) & ~(UINTN)(CPU_STACK_ALIGNMENT - 1))\r
55\r
787a085b
LD
56#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
57\r
1f569620 58#pragma pack(1)\r
59typedef union {\r
60 struct {\r
61 UINT32 LimitLow : 16;\r
62 UINT32 BaseLow : 16;\r
63 UINT32 BaseMid : 8;\r
64 UINT32 Type : 4;\r
65 UINT32 System : 1;\r
66 UINT32 Dpl : 2;\r
67 UINT32 Present : 1;\r
68 UINT32 LimitHigh : 4;\r
69 UINT32 Software : 1;\r
70 UINT32 Reserved : 1;\r
71 UINT32 DefaultSize : 1;\r
72 UINT32 Granularity : 1;\r
73 UINT32 BaseHigh : 8;\r
74 } Bits;\r
75 UINT64 Uint64;\r
76} IA32_GDT;\r
77\r
78//\r
79// Page-Map Level-4 Offset (PML4) and\r
80// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB\r
81//\r
82typedef union {\r
83 struct {\r
84 UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory\r
85 UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write\r
86 UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User\r
87 UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching\r
88 UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached\r
89 UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)\r
90 UINT64 Reserved:1; // Reserved\r
91 UINT64 MustBeZero:2; // Must Be Zero\r
92 UINT64 Available:3; // Available for use by system software\r
93 UINT64 PageTableBaseAddress:40; // Page Table Base Address\r
94 UINT64 AvabilableHigh:11; // Available for use by system software\r
95 UINT64 Nx:1; // No Execute bit\r
96 } Bits;\r
97 UINT64 Uint64;\r
98} PAGE_MAP_AND_DIRECTORY_POINTER;\r
99\r
100//\r
101// Page Table Entry 2MB\r
102//\r
103typedef union {\r
104 struct {\r
105 UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory\r
106 UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write\r
107 UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User\r
108 UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching\r
109 UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached\r
110 UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)\r
111 UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page\r
7367cc6c 112 UINT64 MustBe1:1; // Must be 1\r
1f569620 113 UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write\r
114 UINT64 Available:3; // Available for use by system software\r
115 UINT64 PAT:1; //\r
116 UINT64 MustBeZero:8; // Must be zero;\r
117 UINT64 PageTableBaseAddress:31; // Page Table Base Address\r
118 UINT64 AvabilableHigh:11; // Available for use by system software\r
119 UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution\r
120 } Bits;\r
121 UINT64 Uint64;\r
122} PAGE_TABLE_ENTRY;\r
123\r
c56b6566
JY
124//\r
125// Page Table Entry 1GB\r
126//\r
127typedef union {\r
128 struct {\r
129 UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory\r
130 UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write\r
131 UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User\r
132 UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching\r
133 UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached\r
134 UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)\r
135 UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page\r
7367cc6c 136 UINT64 MustBe1:1; // Must be 1\r
c56b6566
JY
137 UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write\r
138 UINT64 Available:3; // Available for use by system software\r
139 UINT64 PAT:1; //\r
140 UINT64 MustBeZero:17; // Must be zero;\r
141 UINT64 PageTableBaseAddress:22; // Page Table Base Address\r
142 UINT64 AvabilableHigh:11; // Available for use by system software\r
143 UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution\r
144 } Bits;\r
145 UINT64 Uint64;\r
146} PAGE_TABLE_1G_ENTRY;\r
147\r
18b13fab
ED
148//\r
149// Define two type of smm communicate headers.\r
a85e7127 150// One for 32 bits PEI + 64 bits DXE, the other for 32 bits PEI + 32 bits DXE case.\r
18b13fab
ED
151//\r
152typedef struct {\r
153 EFI_GUID HeaderGuid;\r
154 UINT32 MessageLength;\r
155 UINT8 Data[1];\r
156} SMM_COMMUNICATE_HEADER_32;\r
157\r
158typedef struct {\r
159 EFI_GUID HeaderGuid;\r
160 UINT64 MessageLength;\r
161 UINT8 Data[1];\r
162} SMM_COMMUNICATE_HEADER_64;\r
163\r
1f569620 164#pragma pack()\r
165\r
166//\r
167// Function prototypes\r
168//\r
169/**\r
170 a ASM function to transfer control to OS.\r
7367cc6c 171\r
1f569620 172 @param S3WakingVector The S3 waking up vector saved in ACPI Facs table\r
7367cc6c 173 @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer\r
1f569620 174**/\r
175typedef\r
176VOID\r
177(EFIAPI *ASM_TRANSFER_CONTROL) (\r
178 IN UINT32 S3WakingVector,\r
179 IN UINT32 AcpiLowMemoryBase\r
180 );\r
181\r
182/**\r
183 Restores the platform to its preboot configuration for an S3 resume and\r
184 jumps to the OS waking vector.\r
185\r
186 This function will restore the platform to its pre-boot configuration that was\r
187 pre-stored in the boot script table and transfer control to OS waking vector.\r
188 Upon invocation, this function is responsible for locating the following\r
189 information before jumping to OS waking vector:\r
190 - ACPI tables\r
191 - boot script table\r
192 - any other information that it needs\r
193\r
194 The S3RestoreConfig() function then executes the pre-stored boot script table\r
195 and transitions the platform to the pre-boot state. The boot script is recorded\r
196 during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and\r
197 EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function\r
198 transfers control to the OS waking vector. If the OS supports only a real-mode\r
199 waking vector, this function will switch from flat mode to real mode before\r
200 jumping to the waking vector. If all platform pre-boot configurations are\r
201 successfully restored and all other necessary information is ready, this\r
202 function will never return and instead will directly jump to the OS waking\r
203 vector. If this function returns, it indicates that the attempt to resume\r
204 from the ACPI S3 sleep state failed.\r
205\r
206 @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI\r
207\r
208 @retval EFI_ABORTED Execution of the S3 resume boot script table failed.\r
209 @retval EFI_NOT_FOUND Some necessary information that is used for the S3\r
210 resume boot path could not be located.\r
211\r
212**/\r
213EFI_STATUS\r
214EFIAPI\r
215S3RestoreConfig2 (\r
216 IN EFI_PEI_S3_RESUME2_PPI *This\r
217 );\r
218\r
abef469f 219/**\r
220 Set data segment selectors value including DS/ES/FS/GS/SS.\r
221\r
222 @param[in] SelectorValue Segment selector value to be set.\r
223\r
224**/\r
225VOID\r
226EFIAPI\r
227AsmSetDataSelectors (\r
228 IN UINT16 SelectorValue\r
229 );\r
230\r
1f569620 231//\r
232// Globals\r
233//\r
234EFI_PEI_S3_RESUME2_PPI mS3ResumePpi = { S3RestoreConfig2 };\r
235\r
236EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
237 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
238 &gEfiPeiS3Resume2PpiGuid,\r
239 &mS3ResumePpi\r
240};\r
241\r
242EFI_PEI_PPI_DESCRIPTOR mPpiListPostScriptTable = {\r
243 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
244 &gPeiPostScriptTablePpiGuid,\r
245 0\r
246};\r
247\r
248EFI_PEI_PPI_DESCRIPTOR mPpiListEndOfPeiTable = {\r
249 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
250 &gEfiEndOfPeiSignalPpiGuid,\r
251 0\r
252};\r
253\r
5b29e438
SZ
254EFI_PEI_PPI_DESCRIPTOR mPpiListS3SmmInitDoneTable = {\r
255 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
256 &gEdkiiS3SmmInitDoneGuid,\r
257 0\r
258};\r
259\r
1f569620 260//\r
261// Global Descriptor Table (GDT)\r
262//\r
263GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
264/* selector { Global Segment Descriptor } */\r
265/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
266/* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
267/* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},\r
268/* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},\r
269/* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
270/* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},\r
271/* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},\r
272/* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}},\r
273/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
274};\r
275\r
abef469f 276#define DATA_SEGEMENT_SELECTOR 0x18\r
277\r
1f569620 278//\r
279// IA32 Gdt register\r
280//\r
281GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {\r
282 sizeof (mGdtEntries) - 1,\r
283 (UINTN) mGdtEntries\r
284 };\r
285\r
1f569620 286\r
d0bf5623
JY
287/**\r
288 The function will check if current waking vector is long mode.\r
289\r
290 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
291\r
292 @retval TRUE Current context need long mode waking vector.\r
293 @retval FALSE Current context need not long mode waking vector.\r
294**/\r
295BOOLEAN\r
296IsLongModeWakingVector (\r
297 IN ACPI_S3_CONTEXT *AcpiS3Context\r
298 )\r
299{\r
300 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
301\r
302 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));\r
303 if ((Facs == NULL) ||\r
304 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
305 ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {\r
306 // Something wrong with FACS\r
307 return FALSE;\r
308 }\r
309 if (Facs->XFirmwareWakingVector != 0) {\r
310 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
311 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
de228fb1 312 ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {\r
d0bf5623
JY
313 // Both BIOS and OS wants 64bit vector\r
314 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
315 return TRUE;\r
316 }\r
317 }\r
318 }\r
319 return FALSE;\r
320}\r
321\r
18b13fab 322/**\r
5b29e438
SZ
323 Signal to SMM through communication buffer way.\r
324\r
325 @param[in] HandlerType SMI handler type to be signaled.\r
18b13fab 326\r
18b13fab 327**/\r
5b29e438
SZ
328VOID\r
329SignalToSmmByCommunication (\r
330 IN EFI_GUID *HandlerType\r
18b13fab
ED
331 )\r
332{\r
333 EFI_STATUS Status;\r
334 EFI_PEI_SMM_COMMUNICATION_PPI *SmmCommunicationPpi;\r
335 UINTN CommSize;\r
336 SMM_COMMUNICATE_HEADER_32 Header32;\r
337 SMM_COMMUNICATE_HEADER_64 Header64;\r
338 VOID *CommBuffer;\r
339\r
5b29e438 340 DEBUG ((DEBUG_INFO, "Signal %g to SMM - Enter\n", HandlerType));\r
18b13fab
ED
341\r
342 //\r
343 // This buffer consumed in DXE phase, so base on DXE mode to prepare communicate buffer.\r
344 // Detect whether DXE is 64 bits mode.\r
345 // if (sizeof(UINTN) == sizeof(UINT64), PEI already 64 bits, assume DXE also 64 bits.\r
a85e7127 346 // or (FeaturePcdGet (PcdDxeIplSwitchToLongMode)), DXE will switch to 64 bits.\r
18b13fab
ED
347 //\r
348 if ((sizeof(UINTN) == sizeof(UINT64)) || (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
349 CommBuffer = &Header64;\r
350 Header64.MessageLength = 0;\r
351 CommSize = OFFSET_OF (SMM_COMMUNICATE_HEADER_64, Data);\r
352 } else {\r
353 CommBuffer = &Header32;\r
354 Header32.MessageLength = 0;\r
355 CommSize = OFFSET_OF (SMM_COMMUNICATE_HEADER_32, Data);\r
356 }\r
5b29e438 357 CopyGuid (CommBuffer, HandlerType);\r
18b13fab 358\r
18b13fab
ED
359 Status = PeiServicesLocatePpi (\r
360 &gEfiPeiSmmCommunicationPpiGuid,\r
361 0,\r
362 NULL,\r
363 (VOID **)&SmmCommunicationPpi\r
364 );\r
152e8d76
ED
365 if (EFI_ERROR (Status)) {\r
366 DEBUG ((DEBUG_ERROR, "Locate Smm Communicate Ppi failed (%r)!\n", Status));\r
5b29e438 367 return;\r
152e8d76 368 }\r
18b13fab 369\r
18b13fab
ED
370 Status = SmmCommunicationPpi->Communicate (\r
371 SmmCommunicationPpi,\r
372 (VOID *)CommBuffer,\r
373 &CommSize\r
374 );\r
152e8d76
ED
375 if (EFI_ERROR (Status)) {\r
376 DEBUG ((DEBUG_ERROR, "SmmCommunicationPpi->Communicate return failure (%r)!\n", Status));\r
377 }\r
18b13fab 378\r
5b29e438
SZ
379 DEBUG ((DEBUG_INFO, "Signal %g to SMM - Exit (%r)\n", HandlerType, Status));\r
380 return;\r
18b13fab
ED
381}\r
382\r
1f569620 383/**\r
384 Jump to OS waking vector.\r
385 The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.\r
386\r
387 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
388 @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE\r
389**/\r
390VOID\r
391EFIAPI\r
392S3ResumeBootOs (\r
393 IN ACPI_S3_CONTEXT *AcpiS3Context,\r
394 IN PEI_S3_RESUME_STATE *PeiS3ResumeState\r
395 )\r
396{\r
397 EFI_STATUS Status;\r
398 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
399 ASM_TRANSFER_CONTROL AsmTransferControl;\r
400 UINTN TempStackTop;\r
401 UINTN TempStack[0x10];\r
402\r
403 //\r
404 // Restore IDT\r
405 //\r
406 AsmWriteIdtr (&PeiS3ResumeState->Idtr);\r
407\r
f6d5cbe7 408 if (PeiS3ResumeState->ReturnStatus != EFI_SUCCESS) {\r
409 //\r
410 // Report Status code that boot script execution is failed\r
411 //\r
412 REPORT_STATUS_CODE (\r
413 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
414 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR)\r
415 );\r
416 }\r
417\r
f5c941b1 418 //\r
7367cc6c 419 // NOTE: Because Debug Timer interrupt and system interrupts will be disabled\r
f5c941b1 420 // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted\r
421 // by soft debugger.\r
422 //\r
423\r
e5735040 424 PERF_INMODULE_END ("ScriptExec");\r
5c0687cc 425\r
1f569620 426 //\r
427 // Install BootScriptDonePpi\r
428 //\r
e5735040 429 PERF_INMODULE_BEGIN ("BootScriptDonePpi");\r
582e4e44 430\r
1f569620 431 Status = PeiServicesInstallPpi (&mPpiListPostScriptTable);\r
432 ASSERT_EFI_ERROR (Status);\r
433\r
e5735040 434 PERF_INMODULE_END ("BootScriptDonePpi");\r
582e4e44 435\r
1f569620 436 //\r
437 // Get ACPI Table Address\r
438 //\r
439 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));\r
440\r
441 if ((Facs == NULL) ||\r
442 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
443 ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {\r
f6d5cbe7 444 //\r
445 // Report Status code that no valid vector is found\r
446 //\r
447 REPORT_STATUS_CODE (\r
448 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
449 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
450 );\r
1f569620 451 CpuDeadLoop ();\r
452 return ;\r
453 }\r
454\r
1f569620 455 //\r
456 // Install EndOfPeiPpi\r
457 //\r
e5735040 458 PERF_INMODULE_BEGIN("EndOfPeiPpi");\r
582e4e44 459\r
1f569620 460 Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);\r
461 ASSERT_EFI_ERROR (Status);\r
462\r
e5735040 463 PERF_INMODULE_END("EndOfPeiPpi");\r
582e4e44 464\r
e5735040 465 PERF_INMODULE_BEGIN("EndOfS3Resume");\r
582e4e44 466\r
5b29e438
SZ
467 DEBUG ((DEBUG_INFO, "Signal EndOfS3Resume\n"));\r
468 //\r
469 // Signal EndOfS3Resume to SMM.\r
470 //\r
471 SignalToSmmByCommunication (&gEdkiiEndOfS3ResumeGuid);\r
18b13fab 472\r
e5735040 473 PERF_INMODULE_END ("EndOfS3Resume");\r
582e4e44 474\r
26c0ba77
SZ
475 //\r
476 // report status code on S3 resume\r
477 //\r
478 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE);\r
479\r
1f569620 480 AsmTransferControl = (ASM_TRANSFER_CONTROL)(UINTN)PeiS3ResumeState->AsmTransferControl;\r
481 if (Facs->XFirmwareWakingVector != 0) {\r
482 //\r
483 // Switch to native waking vector\r
484 //\r
485 TempStackTop = (UINTN)&TempStack + sizeof(TempStack);\r
af34c106
JF
486 DEBUG ((\r
487 DEBUG_INFO,\r
488 "%a() Stack Base: 0x%x, Stack Size: 0x%x\n",\r
489 __FUNCTION__,\r
490 TempStackTop,\r
491 sizeof (TempStack)\r
492 ));\r
1f569620 493 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
494 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
de228fb1 495 ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {\r
1f569620 496 //\r
497 // X64 long mode waking vector\r
498 //\r
c5719579 499 DEBUG ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));\r
1f569620 500 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
501 AsmEnablePaging64 (\r
502 0x38,\r
503 Facs->XFirmwareWakingVector,\r
504 0,\r
505 0,\r
506 (UINT64)(UINTN)TempStackTop\r
507 );\r
508 } else {\r
f6d5cbe7 509 //\r
510 // Report Status code that no valid waking vector is found\r
511 //\r
512 REPORT_STATUS_CODE (\r
513 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
514 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
515 );\r
96e1cba5 516 DEBUG (( DEBUG_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));\r
1f569620 517 ASSERT (FALSE);\r
f6d5cbe7 518 CpuDeadLoop ();\r
519 return ;\r
1f569620 520 }\r
521 } else {\r
522 //\r
523 // IA32 protected mode waking vector (Page disabled)\r
524 //\r
c5719579 525 DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));\r
1f569620 526 SwitchStack (\r
527 (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector,\r
528 NULL,\r
529 NULL,\r
530 (VOID *)(UINTN)TempStackTop\r
531 );\r
532 }\r
533 } else {\r
534 //\r
535 // 16bit Realmode waking vector\r
536 //\r
c5719579 537 DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));\r
1f569620 538 AsmTransferControl (Facs->FirmwareWakingVector, 0x0);\r
539 }\r
540\r
f6d5cbe7 541 //\r
542 // Report Status code the failure of S3Resume\r
543 //\r
544 REPORT_STATUS_CODE (\r
545 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
546 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)\r
547 );\r
548\r
1f569620 549 //\r
550 // Never run to here\r
551 //\r
552 CpuDeadLoop();\r
553}\r
554\r
555/**\r
556 Restore S3 page table because we do not trust ACPINvs content.\r
7367cc6c 557 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.\r
1f569620 558\r
559 @param S3NvsPageTableAddress PageTableAddress in ACPINvs\r
d0bf5623 560 @param Build4GPageTableOnly If BIOS just build 4G page table only\r
1f569620 561**/\r
562VOID\r
563RestoreS3PageTables (\r
d0bf5623
JY
564 IN UINTN S3NvsPageTableAddress,\r
565 IN BOOLEAN Build4GPageTableOnly\r
1f569620 566 )\r
567{\r
568 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
569 UINT32 RegEax;\r
c56b6566 570 UINT32 RegEdx;\r
1f569620 571 UINT8 PhysicalAddressBits;\r
572 EFI_PHYSICAL_ADDRESS PageAddress;\r
573 UINTN IndexOfPml4Entries;\r
574 UINTN IndexOfPdpEntries;\r
575 UINTN IndexOfPageDirectoryEntries;\r
c56b6566
JY
576 UINT32 NumberOfPml4EntriesNeeded;\r
577 UINT32 NumberOfPdpEntriesNeeded;\r
1f569620 578 PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;\r
579 PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;\r
580 PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;\r
581 PAGE_TABLE_ENTRY *PageDirectoryEntry;\r
c56b6566
JY
582 VOID *Hob;\r
583 BOOLEAN Page1GSupport;\r
584 PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;\r
787a085b
LD
585 UINT64 AddressEncMask;\r
586\r
587 //\r
588 // Make sure AddressEncMask is contained to smallest supported address field\r
589 //\r
590 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
1f569620 591\r
592 //\r
593 // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information.\r
594 // The whole page table is too large to be saved in SMRAM.\r
595 //\r
438f1766 596 // The assumption is : whole page table is allocated in CONTINUOUS memory and CR3 points to TOP page.\r
1f569620 597 //\r
c5719579 598 DEBUG ((DEBUG_INFO, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));\r
1f569620 599\r
600 //\r
438f1766 601 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
1f569620 602 //\r
603 PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;\r
604 S3NvsPageTableAddress += SIZE_4KB;\r
7367cc6c 605\r
c56b6566 606 Page1GSupport = FALSE;\r
378175d2
JY
607 if (PcdGetBool(PcdUse1GPageTable)) {\r
608 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
609 if (RegEax >= 0x80000001) {\r
610 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
611 if ((RegEdx & BIT26) != 0) {\r
612 Page1GSupport = TRUE;\r
613 }\r
c56b6566
JY
614 }\r
615 }\r
7367cc6c 616\r
1f569620 617 //\r
618 // Get physical address bits supported.\r
619 //\r
c56b6566
JY
620 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
621 if (Hob != NULL) {\r
622 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
1f569620 623 } else {\r
c56b6566
JY
624 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
625 if (RegEax >= 0x80000008) {\r
626 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
627 PhysicalAddressBits = (UINT8) RegEax;\r
628 } else {\r
629 PhysicalAddressBits = 36;\r
630 }\r
1f569620 631 }\r
7367cc6c 632\r
c56b6566
JY
633 //\r
634 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
635 //\r
636 ASSERT (PhysicalAddressBits <= 52);\r
637 if (PhysicalAddressBits > 48) {\r
638 PhysicalAddressBits = 48;\r
639 }\r
640\r
d0bf5623
JY
641 //\r
642 // NOTE: In order to save time to create full page table, we just create 4G page table by default.\r
643 // And let PF handler in BootScript driver to create more on request.\r
644 //\r
645 if (Build4GPageTableOnly) {\r
646 PhysicalAddressBits = 32;\r
647 ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));\r
648 }\r
1f569620 649 //\r
650 // Calculate the table entries needed.\r
651 //\r
652 if (PhysicalAddressBits <= 39) {\r
653 NumberOfPml4EntriesNeeded = 1;\r
c56b6566 654 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
1f569620 655 } else {\r
c56b6566 656 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
1f569620 657 NumberOfPdpEntriesNeeded = 512;\r
658 }\r
7367cc6c 659\r
1f569620 660 PageMapLevel4Entry = PageMap;\r
661 PageAddress = 0;\r
662 for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
663 //\r
664 // Each PML4 entry points to a page of Page Directory Pointer entires.\r
665 // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.\r
666 //\r
667 PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;\r
668 S3NvsPageTableAddress += SIZE_4KB;\r
7367cc6c 669\r
1f569620 670 //\r
671 // Make a PML4 Entry\r
672 //\r
787a085b 673 PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;\r
1f569620 674 PageMapLevel4Entry->Bits.ReadWrite = 1;\r
675 PageMapLevel4Entry->Bits.Present = 1;\r
c56b6566
JY
676\r
677 if (Page1GSupport) {\r
54d3b84e 678 PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
7367cc6c 679\r
c56b6566 680 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
1f569620 681 //\r
682 // Fill in the Page Directory entries\r
683 //\r
787a085b 684 PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
c56b6566
JY
685 PageDirectory1GEntry->Bits.ReadWrite = 1;\r
686 PageDirectory1GEntry->Bits.Present = 1;\r
687 PageDirectory1GEntry->Bits.MustBe1 = 1;\r
688 }\r
689 } else {\r
690 for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
691 //\r
692 // Each Directory Pointer entries points to a page of Page Directory entires.\r
693 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
7367cc6c 694 //\r
c56b6566
JY
695 PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress;\r
696 S3NvsPageTableAddress += SIZE_4KB;\r
7367cc6c 697\r
c56b6566
JY
698 //\r
699 // Fill in a Page Directory Pointer Entries\r
700 //\r
787a085b 701 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;\r
c56b6566
JY
702 PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
703 PageDirectoryPointerEntry->Bits.Present = 1;\r
7367cc6c 704\r
c56b6566
JY
705 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
706 //\r
707 // Fill in the Page Directory entries\r
708 //\r
787a085b 709 PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
c56b6566
JY
710 PageDirectoryEntry->Bits.ReadWrite = 1;\r
711 PageDirectoryEntry->Bits.Present = 1;\r
712 PageDirectoryEntry->Bits.MustBe1 = 1;\r
713 }\r
1f569620 714 }\r
715 }\r
716 }\r
717 return ;\r
718 } else {\r
7367cc6c
LG
719 //\r
720 // If DXE is running 32-bit mode, no need to establish page table.\r
721 //\r
1f569620 722 return ;\r
723 }\r
724}\r
725\r
726/**\r
727 Jump to boot script executor driver.\r
728\r
729 The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table.\r
730\r
731 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
732 @param EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in\r
733 boot script execute driver\r
734**/\r
735VOID\r
736EFIAPI\r
737S3ResumeExecuteBootScript (\r
738 IN ACPI_S3_CONTEXT *AcpiS3Context,\r
739 IN BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable\r
740 )\r
741{\r
742 EFI_STATUS Status;\r
743 PEI_SMM_ACCESS_PPI *SmmAccess;\r
744 UINTN Index;\r
745 VOID *GuidHob;\r
1f569620 746 PEI_S3_RESUME_STATE *PeiS3ResumeState;\r
abef469f 747 BOOLEAN InterruptStatus;\r
1f569620 748\r
c5719579 749 DEBUG ((DEBUG_INFO, "S3ResumeExecuteBootScript()\n"));\r
1f569620 750\r
751 //\r
752 // Attempt to use content from SMRAM first\r
753 //\r
754 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);\r
755 if (GuidHob != NULL) {\r
756 //\r
757 // Last step for SMM - send SMI for initialization\r
758 //\r
759\r
760 //\r
761 // Send SMI to APs\r
7367cc6c 762 //\r
1f569620 763 SendSmiIpiAllExcludingSelf ();\r
764 //\r
765 // Send SMI to BSP\r
766 //\r
767 SendSmiIpi (GetApicId ());\r
768\r
769 Status = PeiServicesLocatePpi (\r
770 &gPeiSmmAccessPpiGuid,\r
771 0,\r
772 NULL,\r
773 (VOID **) &SmmAccess\r
774 );\r
40ef06fc 775 if (!EFI_ERROR (Status)) {\r
c5719579 776 DEBUG ((DEBUG_INFO, "Close all SMRAM regions before executing boot script\n"));\r
7367cc6c 777\r
40ef06fc
SZ
778 for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
779 Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
780 }\r
1f569620 781\r
c5719579 782 DEBUG ((DEBUG_INFO, "Lock all SMRAM regions before executing boot script\n"));\r
7367cc6c 783\r
40ef06fc
SZ
784 for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
785 Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
786 }\r
1f569620 787 }\r
5b29e438
SZ
788\r
789 DEBUG ((DEBUG_INFO, "Signal S3SmmInitDone\n"));\r
790 //\r
791 // Install S3SmmInitDone PPI.\r
792 //\r
793 Status = PeiServicesInstallPpi (&mPpiListS3SmmInitDoneTable);\r
794 ASSERT_EFI_ERROR (Status);\r
795 //\r
796 // Signal S3SmmInitDone to SMM.\r
797 //\r
798 SignalToSmmByCommunication (&gEdkiiS3SmmInitDoneGuid);\r
1f569620 799 }\r
800\r
801 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
1f569620 802 AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);\r
803 }\r
804\r
abef469f 805 InterruptStatus = SaveAndDisableInterrupts ();\r
1f569620 806 //\r
807 // Need to make sure the GDT is loaded with values that support long mode and real mode.\r
808 //\r
809 AsmWriteGdtr (&mGdt);\r
abef469f 810 //\r
811 // update segment selectors per the new GDT.\r
812 //\r
813 AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);\r
814 //\r
815 // Restore interrupt state.\r
816 //\r
817 SetInterruptState (InterruptStatus);\r
1f569620 818\r
819 //\r
820 // Prepare data for return back\r
821 //\r
822 PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState));\r
6f9760d8
SZ
823 if (PeiS3ResumeState == NULL) {\r
824 REPORT_STATUS_CODE (\r
825 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
826 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED)\r
827 );\r
828 ASSERT (FALSE);\r
829 }\r
c5719579 830 DEBUG ((DEBUG_INFO, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));\r
1f569620 831 PeiS3ResumeState->ReturnCs = 0x10;\r
832 PeiS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;\r
f98f5ec3 833 PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);\r
1f569620 834 //\r
835 // Save IDT\r
836 //\r
837 AsmReadIdtr (&PeiS3ResumeState->Idtr);\r
7367cc6c 838\r
f6d5cbe7 839 //\r
840 // Report Status Code to indicate S3 boot script execution\r
841 //\r
842 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT);\r
1f569620 843\r
e5735040 844 PERF_INMODULE_BEGIN ("ScriptExec");\r
5c0687cc 845\r
1f569620 846 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
847 //\r
848 // X64 S3 Resume\r
849 //\r
c5719579 850 DEBUG ((DEBUG_INFO, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n"));\r
1f569620 851\r
852 //\r
853 // Switch to long mode to complete resume.\r
854 //\r
855 AsmEnablePaging64 (\r
856 0x38,\r
857 EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,\r
858 (UINT64)(UINTN)AcpiS3Context,\r
859 (UINT64)(UINTN)PeiS3ResumeState,\r
860 (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)\r
861 );\r
862 } else {\r
863 //\r
864 // IA32 S3 Resume\r
865 //\r
c5719579 866 DEBUG ((DEBUG_INFO, "transfer control to Standalone Boot Script Executor\r\n"));\r
1f569620 867 SwitchStack (\r
868 (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,\r
869 (VOID *)AcpiS3Context,\r
870 (VOID *)PeiS3ResumeState,\r
871 (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)\r
872 );\r
873 }\r
874\r
875 //\r
876 // Never run to here\r
877 //\r
878 CpuDeadLoop();\r
879}\r
880/**\r
881 Restores the platform to its preboot configuration for an S3 resume and\r
882 jumps to the OS waking vector.\r
883\r
884 This function will restore the platform to its pre-boot configuration that was\r
885 pre-stored in the boot script table and transfer control to OS waking vector.\r
886 Upon invocation, this function is responsible for locating the following\r
887 information before jumping to OS waking vector:\r
888 - ACPI tables\r
889 - boot script table\r
890 - any other information that it needs\r
891\r
892 The S3RestoreConfig() function then executes the pre-stored boot script table\r
893 and transitions the platform to the pre-boot state. The boot script is recorded\r
894 during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and\r
895 EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function\r
896 transfers control to the OS waking vector. If the OS supports only a real-mode\r
897 waking vector, this function will switch from flat mode to real mode before\r
898 jumping to the waking vector. If all platform pre-boot configurations are\r
899 successfully restored and all other necessary information is ready, this\r
900 function will never return and instead will directly jump to the OS waking\r
901 vector. If this function returns, it indicates that the attempt to resume\r
902 from the ACPI S3 sleep state failed.\r
903\r
904 @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI\r
905\r
906 @retval EFI_ABORTED Execution of the S3 resume boot script table failed.\r
907 @retval EFI_NOT_FOUND Some necessary information that is used for the S3\r
908 resume boot path could not be located.\r
909\r
910**/\r
911EFI_STATUS\r
912EFIAPI\r
913S3RestoreConfig2 (\r
914 IN EFI_PEI_S3_RESUME2_PPI *This\r
915 )\r
916{\r
917 EFI_STATUS Status;\r
918 PEI_SMM_ACCESS_PPI *SmmAccess;\r
919 UINTN Index;\r
920 ACPI_S3_CONTEXT *AcpiS3Context;\r
1f569620 921 EFI_PHYSICAL_ADDRESS TempEfiBootScriptExecutorVariable;\r
922 EFI_PHYSICAL_ADDRESS TempAcpiS3Context;\r
923 BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;\r
924 UINTN VarSize;\r
925 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;\r
926 SMM_S3_RESUME_STATE *SmmS3ResumeState;\r
927 VOID *GuidHob;\r
d0bf5623 928 BOOLEAN Build4GPageTableOnly;\r
abef469f 929 BOOLEAN InterruptStatus;\r
55e8ff01 930 IA32_CR0 Cr0;\r
1f569620 931\r
48ee8e3e
SZ
932 TempAcpiS3Context = 0;\r
933 TempEfiBootScriptExecutorVariable = 0;\r
934\r
c5719579 935 DEBUG ((DEBUG_INFO, "Enter S3 PEIM\r\n"));\r
1f569620 936\r
1f569620 937 VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
938 Status = RestoreLockBox (\r
939 &gEfiAcpiVariableGuid,\r
940 &TempAcpiS3Context,\r
941 &VarSize\r
942 );\r
943 ASSERT_EFI_ERROR (Status);\r
944\r
1f569620 945 Status = RestoreLockBox (\r
946 &gEfiAcpiS3ContextGuid,\r
947 NULL,\r
948 NULL\r
949 );\r
950 ASSERT_EFI_ERROR (Status);\r
951\r
48ee8e3e
SZ
952 AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;\r
953 ASSERT (AcpiS3Context != NULL);\r
954\r
955 VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
1f569620 956 Status = RestoreLockBox (\r
957 &gEfiBootScriptExecutorVariableGuid,\r
958 &TempEfiBootScriptExecutorVariable,\r
959 &VarSize\r
960 );\r
961 ASSERT_EFI_ERROR (Status);\r
962\r
963 Status = RestoreLockBox (\r
964 &gEfiBootScriptExecutorContextGuid,\r
965 NULL,\r
966 NULL\r
967 );\r
968 ASSERT_EFI_ERROR (Status);\r
969\r
970 EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable;\r
48ee8e3e 971 ASSERT (EfiBootScriptExecutorVariable != NULL);\r
1f569620 972\r
c5719579
JF
973 DEBUG (( DEBUG_INFO, "AcpiS3Context = %x\n", AcpiS3Context));\r
974 DEBUG (( DEBUG_INFO, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));\r
975 DEBUG (( DEBUG_INFO, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));\r
7367cc6c 976 DEBUG (( DEBUG_INFO, "AcpiS3Context->IdtrProfile = %x\n", AcpiS3Context->IdtrProfile));\r
c5719579
JF
977 DEBUG (( DEBUG_INFO, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));\r
978 DEBUG (( DEBUG_INFO, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));\r
979 DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackBase = %x\n", AcpiS3Context->BootScriptStackBase));\r
980 DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackSize = %x\n", AcpiS3Context->BootScriptStackSize));\r
981 DEBUG (( DEBUG_INFO, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));\r
1f569620 982\r
983 //\r
984 // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor.\r
985 // Script dispatch image and context (parameter) are handled by platform.\r
986 // We just use restore all lock box in place, no need restore one by one.\r
987 //\r
988 Status = RestoreAllLockBoxInPlace ();\r
989 ASSERT_EFI_ERROR (Status);\r
990 if (EFI_ERROR (Status)) {\r
991 // Something wrong\r
992 CpuDeadLoop ();\r
993 }\r
994\r
3a69f7cb 995 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
996 //\r
997 // Need reconstruct page table here, since we do not trust ACPINvs.\r
998 //\r
d0bf5623
JY
999 if (IsLongModeWakingVector (AcpiS3Context)) {\r
1000 Build4GPageTableOnly = FALSE;\r
1001 } else {\r
1002 Build4GPageTableOnly = TRUE;\r
1003 }\r
1004 RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);\r
3a69f7cb 1005 }\r
1006\r
1f569620 1007 //\r
1008 // Attempt to use content from SMRAM first\r
1009 //\r
1010 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);\r
1011 if (GuidHob != NULL) {\r
55e8ff01
ED
1012 //\r
1013 // Below SwitchStack/AsmEnablePaging64 function has\r
1014 // assumption that it's in 32 bits mode now.\r
1015 // Add ASSERT code to indicate this assumption.\r
1016 //\r
1017 ASSERT(sizeof (UINTN) == sizeof (UINT32));\r
1018\r
40ef06fc
SZ
1019 Status = PeiServicesLocatePpi (\r
1020 &gPeiSmmAccessPpiGuid,\r
1021 0,\r
1022 NULL,\r
1023 (VOID **) &SmmAccess\r
1024 );\r
1025 for (Index = 0; !EFI_ERROR (Status); Index++) {\r
1026 Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);\r
1027 }\r
1028\r
1f569620 1029 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);\r
1030 SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;\r
1031\r
1032 SmmS3ResumeState->ReturnCs = AsmReadCs ();\r
1033 SmmS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;\r
1034 SmmS3ResumeState->ReturnContext1 = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
1035 SmmS3ResumeState->ReturnContext2 = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;\r
f98f5ec3 1036 SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);\r
1f569620 1037\r
c5719579
JF
1038 DEBUG (( DEBUG_INFO, "SMM S3 Signature = %x\n", SmmS3ResumeState->Signature));\r
1039 DEBUG (( DEBUG_INFO, "SMM S3 Stack Base = %x\n", SmmS3ResumeState->SmmS3StackBase));\r
1040 DEBUG (( DEBUG_INFO, "SMM S3 Stack Size = %x\n", SmmS3ResumeState->SmmS3StackSize));\r
1041 DEBUG (( DEBUG_INFO, "SMM S3 Resume Entry Point = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint));\r
1042 DEBUG (( DEBUG_INFO, "SMM S3 CR0 = %x\n", SmmS3ResumeState->SmmS3Cr0));\r
1043 DEBUG (( DEBUG_INFO, "SMM S3 CR3 = %x\n", SmmS3ResumeState->SmmS3Cr3));\r
1044 DEBUG (( DEBUG_INFO, "SMM S3 CR4 = %x\n", SmmS3ResumeState->SmmS3Cr4));\r
1045 DEBUG (( DEBUG_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs));\r
1046 DEBUG (( DEBUG_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint));\r
1047 DEBUG (( DEBUG_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1));\r
1048 DEBUG (( DEBUG_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2));\r
1049 DEBUG (( DEBUG_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer));\r
1050 DEBUG (( DEBUG_INFO, "SMM S3 Smst = %x\n", SmmS3ResumeState->Smst));\r
1f569620 1051\r
1f569620 1052 if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {\r
1053 SwitchStack (\r
1054 (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,\r
1055 (VOID *)AcpiS3Context,\r
1056 0,\r
1057 (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize)\r
1058 );\r
1059 }\r
1060 if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {\r
1061 //\r
1062 // Switch to long mode to complete resume.\r
1063 //\r
1064\r
abef469f 1065 InterruptStatus = SaveAndDisableInterrupts ();\r
1f569620 1066 //\r
1067 // Need to make sure the GDT is loaded with values that support long mode and real mode.\r
1068 //\r
1069 AsmWriteGdtr (&mGdt);\r
abef469f 1070 //\r
1071 // update segment selectors per the new GDT.\r
7367cc6c 1072 //\r
abef469f 1073 AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);\r
1074 //\r
1075 // Restore interrupt state.\r
1076 //\r
1077 SetInterruptState (InterruptStatus);\r
1078\r
55e8ff01
ED
1079 Cr0.UintN = AsmReadCr0 ();\r
1080 if (Cr0.Bits.PG != 0) {\r
1081 //\r
1082 // We're in 32-bit mode, with paging enabled. We can't set CR3 to\r
1083 // the 64-bit page tables without first disabling paging.\r
1084 //\r
1085 Cr0.Bits.PG = 0;\r
1086 AsmWriteCr0 (Cr0.UintN);\r
1087 }\r
1f569620 1088 AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);\r
f5c941b1 1089\r
1090 //\r
1091 // Disable interrupt of Debug timer, since IDT table cannot work in long mode.\r
1092 // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,\r
1093 // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.\r
1094 //\r
1095 SaveAndSetDebugTimerInterrupt (FALSE);\r
1096\r
1f569620 1097 AsmEnablePaging64 (\r
1098 0x38,\r
1099 SmmS3ResumeState->SmmS3ResumeEntryPoint,\r
1100 (UINT64)(UINTN)AcpiS3Context,\r
1101 0,\r
1102 SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize\r
1103 );\r
1104 }\r
1105\r
1106 }\r
1107\r
1108 S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable );\r
1109 return EFI_SUCCESS;\r
1110}\r
1111/**\r
1112 Main entry for S3 Resume PEIM.\r
1113\r
1114 This routine is to install EFI_PEI_S3_RESUME2_PPI.\r
7367cc6c 1115\r
1f569620 1116 @param FileHandle Handle of the file being invoked.\r
1117 @param PeiServices Pointer to PEI Services table.\r
1118\r
1119 @retval EFI_SUCCESS S3Resume Ppi is installed successfully.\r
1120\r
1121**/\r
1122EFI_STATUS\r
1123EFIAPI\r
1124PeimS3ResumeEntryPoint (\r
1125 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1126 IN CONST EFI_PEI_SERVICES **PeiServices\r
1127 )\r
1128{\r
1129 EFI_STATUS Status;\r
1130\r
1131 //\r
1132 // Install S3 Resume Ppi\r
1133 //\r
1134 Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);\r
1135 ASSERT_EFI_ERROR (Status);\r
1136\r
1137 return EFI_SUCCESS;\r
1138}\r