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