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