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 - 2019, Intel Corporation. All rights reserved.<BR>
8   Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
9 
10   SPDX-License-Identifier: BSD-2-Clause-Patent
11 
12 **/
13 
14 #include <PiPei.h>
15 
16 #include <Guid/AcpiS3Context.h>
17 #include <Guid/BootScriptExecutorVariable.h>
18 #include <Guid/ExtendedFirmwarePerformance.h>
19 #include <Guid/EndOfS3Resume.h>
20 #include <Guid/S3SmmInitDone.h>
21 #include <Ppi/S3Resume2.h>
22 #include <Ppi/SmmAccess.h>
23 #include <Ppi/PostBootScriptTable.h>
24 #include <Ppi/EndOfPeiPhase.h>
25 #include <Ppi/SmmCommunication.h>
26 
27 #include <Library/DebugLib.h>
28 #include <Library/BaseLib.h>
29 #include <Library/PeimEntryPoint.h>
30 #include <Library/PeiServicesLib.h>
31 #include <Library/HobLib.h>
32 #include <Library/PerformanceLib.h>
33 #include <Library/PeiServicesTablePointerLib.h>
34 #include <Library/IoLib.h>
35 #include <Library/BaseMemoryLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/PcdLib.h>
38 #include <Library/DebugAgentLib.h>
39 #include <Library/LocalApicLib.h>
40 #include <Library/ReportStatusCodeLib.h>
41 
42 #include <Library/HobLib.h>
43 #include <Library/LockBoxLib.h>
44 #include <IndustryStandard/Acpi.h>
45 
46 /**
47   This macro aligns the address of a variable with auto storage
48   duration down to CPU_STACK_ALIGNMENT.
49 
50   Since the stack grows downward, the result preserves more of the
51   stack than the original address (or the same amount), not less.
52 **/
53 #define STACK_ALIGN_DOWN(Ptr) \
54           ((UINTN)(Ptr) & ~(UINTN)(CPU_STACK_ALIGNMENT - 1))
55 
56 #define PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
57 
58 #pragma pack(1)
59 typedef union {
60   struct {
61     UINT32  LimitLow    : 16;
62     UINT32  BaseLow     : 16;
63     UINT32  BaseMid     : 8;
64     UINT32  Type        : 4;
65     UINT32  System      : 1;
66     UINT32  Dpl         : 2;
67     UINT32  Present     : 1;
68     UINT32  LimitHigh   : 4;
69     UINT32  Software    : 1;
70     UINT32  Reserved    : 1;
71     UINT32  DefaultSize : 1;
72     UINT32  Granularity : 1;
73     UINT32  BaseHigh    : 8;
74   } Bits;
75   UINT64  Uint64;
76 } IA32_GDT;
77 
78 //
79 // Page-Map Level-4 Offset (PML4) and
80 // Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
81 //
82 typedef union {
83   struct {
84     UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
85     UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
86     UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
87     UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
88     UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
89     UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
90     UINT64  Reserved:1;               // Reserved
91     UINT64  MustBeZero:2;             // Must Be Zero
92     UINT64  Available:3;              // Available for use by system software
93     UINT64  PageTableBaseAddress:40;  // Page Table Base Address
94     UINT64  AvabilableHigh:11;        // Available for use by system software
95     UINT64  Nx:1;                     // No Execute bit
96   } Bits;
97   UINT64    Uint64;
98 } PAGE_MAP_AND_DIRECTORY_POINTER;
99 
100 //
101 // Page Table Entry 2MB
102 //
103 typedef union {
104   struct {
105     UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
106     UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
107     UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
108     UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
109     UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
110     UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
111     UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
112     UINT64  MustBe1:1;                // Must be 1
113     UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
114     UINT64  Available:3;              // Available for use by system software
115     UINT64  PAT:1;                    //
116     UINT64  MustBeZero:8;             // Must be zero;
117     UINT64  PageTableBaseAddress:31;  // Page Table Base Address
118     UINT64  AvabilableHigh:11;        // Available for use by system software
119     UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
120   } Bits;
121   UINT64    Uint64;
122 } PAGE_TABLE_ENTRY;
123 
124 //
125 // Page Table Entry 1GB
126 //
127 typedef union {
128   struct {
129     UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
130     UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
131     UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
132     UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
133     UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
134     UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
135     UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
136     UINT64  MustBe1:1;                // Must be 1
137     UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
138     UINT64  Available:3;              // Available for use by system software
139     UINT64  PAT:1;                    //
140     UINT64  MustBeZero:17;            // Must be zero;
141     UINT64  PageTableBaseAddress:22;  // Page Table Base Address
142     UINT64  AvabilableHigh:11;        // Available for use by system software
143     UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
144   } Bits;
145   UINT64    Uint64;
146 } PAGE_TABLE_1G_ENTRY;
147 
148 //
149 // Define two type of smm communicate headers.
150 // One for 32 bits PEI + 64 bits DXE, the other for 32 bits PEI + 32 bits DXE case.
151 //
152 typedef struct {
153   EFI_GUID  HeaderGuid;
154   UINT32    MessageLength;
155   UINT8     Data[1];
156 } SMM_COMMUNICATE_HEADER_32;
157 
158 typedef struct {
159   EFI_GUID  HeaderGuid;
160   UINT64    MessageLength;
161   UINT8     Data[1];
162 } SMM_COMMUNICATE_HEADER_64;
163 
164 #pragma pack()
165 
166 //
167 // Function prototypes
168 //
169 /**
170   a ASM function to transfer control to OS.
171 
172   @param  S3WakingVector  The S3 waking up vector saved in ACPI Facs table
173   @param  AcpiLowMemoryBase a buffer under 1M which could be used during the transfer
174 **/
175 typedef
176 VOID
177 (EFIAPI *ASM_TRANSFER_CONTROL) (
178   IN   UINT32           S3WakingVector,
179   IN   UINT32           AcpiLowMemoryBase
180   );
181 
182 /**
183   Restores the platform to its preboot configuration for an S3 resume and
184   jumps to the OS waking vector.
185 
186   This function will restore the platform to its pre-boot configuration that was
187   pre-stored in the boot script table and transfer control to OS waking vector.
188   Upon invocation, this function is responsible for locating the following
189   information before jumping to OS waking vector:
190     - ACPI tables
191     - boot script table
192     - any other information that it needs
193 
194   The S3RestoreConfig() function then executes the pre-stored boot script table
195   and transitions the platform to the pre-boot state. The boot script is recorded
196   during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
197   EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions.  Finally, this function
198   transfers control to the OS waking vector. If the OS supports only a real-mode
199   waking vector, this function will switch from flat mode to real mode before
200   jumping to the waking vector.  If all platform pre-boot configurations are
201   successfully restored and all other necessary information is ready, this
202   function will never return and instead will directly jump to the OS waking
203   vector. If this function returns, it indicates that the attempt to resume
204   from the ACPI S3 sleep state failed.
205 
206   @param[in] This         Pointer to this instance of the PEI_S3_RESUME_PPI
207 
208   @retval EFI_ABORTED     Execution of the S3 resume boot script table failed.
209   @retval EFI_NOT_FOUND   Some necessary information that is used for the S3
210                           resume boot path could not be located.
211 
212 **/
213 EFI_STATUS
214 EFIAPI
215 S3RestoreConfig2 (
216   IN EFI_PEI_S3_RESUME2_PPI  *This
217   );
218 
219 /**
220   Set data segment selectors value including DS/ES/FS/GS/SS.
221 
222   @param[in]  SelectorValue      Segment selector value to be set.
223 
224 **/
225 VOID
226 EFIAPI
227 AsmSetDataSelectors (
228   IN UINT16   SelectorValue
229   );
230 
231 //
232 // Globals
233 //
234 EFI_PEI_S3_RESUME2_PPI      mS3ResumePpi = { S3RestoreConfig2 };
235 
236 EFI_PEI_PPI_DESCRIPTOR mPpiList = {
237   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
238   &gEfiPeiS3Resume2PpiGuid,
239   &mS3ResumePpi
240 };
241 
242 EFI_PEI_PPI_DESCRIPTOR mPpiListPostScriptTable = {
243   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
244   &gPeiPostScriptTablePpiGuid,
245   0
246 };
247 
248 EFI_PEI_PPI_DESCRIPTOR mPpiListEndOfPeiTable = {
249   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
250   &gEfiEndOfPeiSignalPpiGuid,
251   0
252 };
253 
254 EFI_PEI_PPI_DESCRIPTOR mPpiListS3SmmInitDoneTable = {
255   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
256   &gEdkiiS3SmmInitDoneGuid,
257   0
258 };
259 
260 //
261 // Global Descriptor Table (GDT)
262 //
263 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
264 /* selector { Global Segment Descriptor                              } */
265 /* 0x00 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
266 /* 0x08 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
267 /* 0x10 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}},
268 /* 0x18 */  {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}},
269 /* 0x20 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
270 /* 0x28 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 0,  1,  0}},
271 /* 0x30 */  {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 0,  1,  0}},
272 /* 0x38 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  1, 0,  1,  0}},
273 /* 0x40 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
274 };
275 
276 #define DATA_SEGEMENT_SELECTOR        0x18
277 
278 //
279 // IA32 Gdt register
280 //
281 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
282   sizeof (mGdtEntries) - 1,
283   (UINTN) mGdtEntries
284   };
285 
286 
287 /**
288   The function will check if current waking vector is long mode.
289 
290   @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
291 
292   @retval TRUE   Current context need long mode waking vector.
293   @retval FALSE  Current context need not long mode waking vector.
294 **/
295 BOOLEAN
IsLongModeWakingVector(IN ACPI_S3_CONTEXT * AcpiS3Context)296 IsLongModeWakingVector (
297   IN ACPI_S3_CONTEXT                *AcpiS3Context
298   )
299 {
300   EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
301 
302   Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
303   if ((Facs == NULL) ||
304       (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
305       ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
306     // Something wrong with FACS
307     return FALSE;
308   }
309   if (Facs->XFirmwareWakingVector != 0) {
310     if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
311         ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
312         ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
313       // Both BIOS and OS wants 64bit vector
314       if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
315         return TRUE;
316       }
317     }
318   }
319   return FALSE;
320 }
321 
322 /**
323   Signal to SMM through communication buffer way.
324 
325   @param[in]  HandlerType       SMI handler type to be signaled.
326 
327 **/
328 VOID
SignalToSmmByCommunication(IN EFI_GUID * HandlerType)329 SignalToSmmByCommunication (
330   IN EFI_GUID   *HandlerType
331   )
332 {
333   EFI_STATUS                         Status;
334   EFI_PEI_SMM_COMMUNICATION_PPI      *SmmCommunicationPpi;
335   UINTN                              CommSize;
336   SMM_COMMUNICATE_HEADER_32          Header32;
337   SMM_COMMUNICATE_HEADER_64          Header64;
338   VOID                               *CommBuffer;
339 
340   DEBUG ((DEBUG_INFO, "Signal %g to SMM - Enter\n", HandlerType));
341 
342   //
343   // This buffer consumed in DXE phase, so base on DXE mode to prepare communicate buffer.
344   // Detect whether DXE is 64 bits mode.
345   // if (sizeof(UINTN) == sizeof(UINT64), PEI already 64 bits, assume DXE also 64 bits.
346   // or (FeaturePcdGet (PcdDxeIplSwitchToLongMode)), DXE will switch to 64 bits.
347   //
348   if ((sizeof(UINTN) == sizeof(UINT64)) || (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
349     CommBuffer = &Header64;
350     Header64.MessageLength = 0;
351     CommSize = OFFSET_OF (SMM_COMMUNICATE_HEADER_64, Data);
352   } else {
353     CommBuffer = &Header32;
354     Header32.MessageLength = 0;
355     CommSize = OFFSET_OF (SMM_COMMUNICATE_HEADER_32, Data);
356   }
357   CopyGuid (CommBuffer, HandlerType);
358 
359   Status = PeiServicesLocatePpi (
360              &gEfiPeiSmmCommunicationPpiGuid,
361              0,
362              NULL,
363              (VOID **)&SmmCommunicationPpi
364              );
365   if (EFI_ERROR (Status)) {
366     DEBUG ((DEBUG_ERROR, "Locate Smm Communicate Ppi failed (%r)!\n", Status));
367     return;
368   }
369 
370   Status = SmmCommunicationPpi->Communicate (
371                                   SmmCommunicationPpi,
372                                   (VOID *)CommBuffer,
373                                   &CommSize
374                                   );
375   if (EFI_ERROR (Status)) {
376     DEBUG ((DEBUG_ERROR, "SmmCommunicationPpi->Communicate return failure (%r)!\n", Status));
377   }
378 
379   DEBUG ((DEBUG_INFO, "Signal %g to SMM - Exit (%r)\n", HandlerType, Status));
380   return;
381 }
382 
383 /**
384   Jump to OS waking vector.
385   The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.
386 
387   @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
388   @param  PeiS3ResumeState              a pointer to a structure of PEI_S3_RESUME_STATE
389 **/
390 VOID
391 EFIAPI
S3ResumeBootOs(IN ACPI_S3_CONTEXT * AcpiS3Context,IN PEI_S3_RESUME_STATE * PeiS3ResumeState)392 S3ResumeBootOs (
393   IN ACPI_S3_CONTEXT                *AcpiS3Context,
394   IN PEI_S3_RESUME_STATE            *PeiS3ResumeState
395   )
396 {
397   EFI_STATUS                                    Status;
398   EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
399   ASM_TRANSFER_CONTROL                          AsmTransferControl;
400   UINTN                                         TempStackTop;
401   UINTN                                         TempStack[0x10];
402 
403   //
404   // Restore IDT
405   //
406   AsmWriteIdtr (&PeiS3ResumeState->Idtr);
407 
408   if (PeiS3ResumeState->ReturnStatus != EFI_SUCCESS) {
409     //
410     // Report Status code that boot script execution is failed
411     //
412     REPORT_STATUS_CODE (
413       EFI_ERROR_CODE | EFI_ERROR_MINOR,
414       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR)
415       );
416   }
417 
418   //
419   // NOTE: Because Debug Timer interrupt and system interrupts will be disabled
420   // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted
421   // by soft debugger.
422   //
423 
424   PERF_INMODULE_END ("ScriptExec");
425 
426   //
427   // Install BootScriptDonePpi
428   //
429   PERF_INMODULE_BEGIN ("BootScriptDonePpi");
430 
431   Status = PeiServicesInstallPpi (&mPpiListPostScriptTable);
432   ASSERT_EFI_ERROR (Status);
433 
434   PERF_INMODULE_END ("BootScriptDonePpi");
435 
436   //
437   // Get ACPI Table Address
438   //
439   Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
440 
441   if ((Facs == NULL) ||
442       (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
443       ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
444     //
445     // Report Status code that no valid vector is found
446     //
447     REPORT_STATUS_CODE (
448       EFI_ERROR_CODE | EFI_ERROR_MAJOR,
449       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
450       );
451     CpuDeadLoop ();
452     return ;
453   }
454 
455   //
456   // Install EndOfPeiPpi
457   //
458   PERF_INMODULE_BEGIN("EndOfPeiPpi");
459 
460   Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);
461   ASSERT_EFI_ERROR (Status);
462 
463   PERF_INMODULE_END("EndOfPeiPpi");
464 
465   PERF_INMODULE_BEGIN("EndOfS3Resume");
466 
467   DEBUG ((DEBUG_INFO, "Signal EndOfS3Resume\n"));
468   //
469   // Signal EndOfS3Resume to SMM.
470   //
471   SignalToSmmByCommunication (&gEdkiiEndOfS3ResumeGuid);
472 
473   PERF_INMODULE_END ("EndOfS3Resume");
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->OspmFlags & 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
RestoreS3PageTables(IN UINTN S3NvsPageTableAddress,IN BOOLEAN Build4GPageTableOnly)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
S3ResumeExecuteBootScript(IN ACPI_S3_CONTEXT * AcpiS3Context,IN BOOT_SCRIPT_EXECUTOR_VARIABLE * EfiBootScriptExecutorVariable)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   PEI_S3_RESUME_STATE        *PeiS3ResumeState;
747   BOOLEAN                    InterruptStatus;
748 
749   DEBUG ((DEBUG_INFO, "S3ResumeExecuteBootScript()\n"));
750 
751   //
752   // Attempt to use content from SMRAM first
753   //
754   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
755   if (GuidHob != NULL) {
756     //
757     // Last step for SMM - send SMI for initialization
758     //
759 
760     //
761     // Send SMI to APs
762     //
763     SendSmiIpiAllExcludingSelf ();
764     //
765     // Send SMI to BSP
766     //
767     SendSmiIpi (GetApicId ());
768 
769     Status = PeiServicesLocatePpi (
770                               &gPeiSmmAccessPpiGuid,
771                               0,
772                               NULL,
773                               (VOID **) &SmmAccess
774                               );
775     if (!EFI_ERROR (Status)) {
776       DEBUG ((DEBUG_INFO, "Close all SMRAM regions before executing boot script\n"));
777 
778       for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
779         Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
780       }
781 
782       DEBUG ((DEBUG_INFO, "Lock all SMRAM regions before executing boot script\n"));
783 
784       for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
785         Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
786       }
787     }
788 
789     DEBUG ((DEBUG_INFO, "Signal S3SmmInitDone\n"));
790     //
791     // Install S3SmmInitDone PPI.
792     //
793     Status = PeiServicesInstallPpi (&mPpiListS3SmmInitDoneTable);
794     ASSERT_EFI_ERROR (Status);
795     //
796     // Signal S3SmmInitDone to SMM.
797     //
798     SignalToSmmByCommunication (&gEdkiiS3SmmInitDoneGuid);
799   }
800 
801   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
802     AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);
803   }
804 
805   InterruptStatus = SaveAndDisableInterrupts ();
806   //
807   // Need to make sure the GDT is loaded with values that support long mode and real mode.
808   //
809   AsmWriteGdtr (&mGdt);
810   //
811   // update segment selectors per the new GDT.
812   //
813   AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
814   //
815   // Restore interrupt state.
816   //
817   SetInterruptState (InterruptStatus);
818 
819   //
820   // Prepare data for return back
821   //
822   PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState));
823   if (PeiS3ResumeState == NULL) {
824     REPORT_STATUS_CODE (
825       EFI_ERROR_CODE | EFI_ERROR_MAJOR,
826       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED)
827       );
828     ASSERT (FALSE);
829   }
830   DEBUG ((DEBUG_INFO, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));
831   PeiS3ResumeState->ReturnCs           = 0x10;
832   PeiS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;
833   PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);
834   //
835   // Save IDT
836   //
837   AsmReadIdtr (&PeiS3ResumeState->Idtr);
838 
839   //
840   // Report Status Code to indicate S3 boot script execution
841   //
842   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT);
843 
844   PERF_INMODULE_BEGIN ("ScriptExec");
845 
846   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
847     //
848     // X64 S3 Resume
849     //
850     DEBUG ((DEBUG_INFO, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n"));
851 
852     //
853     // Switch to long mode to complete resume.
854     //
855     AsmEnablePaging64 (
856       0x38,
857       EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
858       (UINT64)(UINTN)AcpiS3Context,
859       (UINT64)(UINTN)PeiS3ResumeState,
860       (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
861       );
862   } else {
863     //
864     // IA32 S3 Resume
865     //
866     DEBUG ((DEBUG_INFO, "transfer control to Standalone Boot Script Executor\r\n"));
867     SwitchStack (
868       (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
869       (VOID *)AcpiS3Context,
870       (VOID *)PeiS3ResumeState,
871       (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
872       );
873   }
874 
875   //
876   // Never run to here
877   //
878   CpuDeadLoop();
879 }
880 /**
881   Restores the platform to its preboot configuration for an S3 resume and
882   jumps to the OS waking vector.
883 
884   This function will restore the platform to its pre-boot configuration that was
885   pre-stored in the boot script table and transfer control to OS waking vector.
886   Upon invocation, this function is responsible for locating the following
887   information before jumping to OS waking vector:
888     - ACPI tables
889     - boot script table
890     - any other information that it needs
891 
892   The S3RestoreConfig() function then executes the pre-stored boot script table
893   and transitions the platform to the pre-boot state. The boot script is recorded
894   during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
895   EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions.  Finally, this function
896   transfers control to the OS waking vector. If the OS supports only a real-mode
897   waking vector, this function will switch from flat mode to real mode before
898   jumping to the waking vector.  If all platform pre-boot configurations are
899   successfully restored and all other necessary information is ready, this
900   function will never return and instead will directly jump to the OS waking
901   vector. If this function returns, it indicates that the attempt to resume
902   from the ACPI S3 sleep state failed.
903 
904   @param[in] This         Pointer to this instance of the PEI_S3_RESUME_PPI
905 
906   @retval EFI_ABORTED     Execution of the S3 resume boot script table failed.
907   @retval EFI_NOT_FOUND   Some necessary information that is used for the S3
908                           resume boot path could not be located.
909 
910 **/
911 EFI_STATUS
912 EFIAPI
S3RestoreConfig2(IN EFI_PEI_S3_RESUME2_PPI * This)913 S3RestoreConfig2 (
914   IN EFI_PEI_S3_RESUME2_PPI  *This
915   )
916 {
917   EFI_STATUS                                    Status;
918   PEI_SMM_ACCESS_PPI                            *SmmAccess;
919   UINTN                                         Index;
920   ACPI_S3_CONTEXT                               *AcpiS3Context;
921   EFI_PHYSICAL_ADDRESS                          TempEfiBootScriptExecutorVariable;
922   EFI_PHYSICAL_ADDRESS                          TempAcpiS3Context;
923   BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;
924   UINTN                                         VarSize;
925   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;
926   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;
927   VOID                                          *GuidHob;
928   BOOLEAN                                       Build4GPageTableOnly;
929   BOOLEAN                                       InterruptStatus;
930   IA32_CR0                                      Cr0;
931 
932   TempAcpiS3Context = 0;
933   TempEfiBootScriptExecutorVariable = 0;
934 
935   DEBUG ((DEBUG_INFO, "Enter S3 PEIM\r\n"));
936 
937   VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
938   Status = RestoreLockBox (
939              &gEfiAcpiVariableGuid,
940              &TempAcpiS3Context,
941              &VarSize
942              );
943   ASSERT_EFI_ERROR (Status);
944 
945   Status = RestoreLockBox (
946              &gEfiAcpiS3ContextGuid,
947              NULL,
948              NULL
949              );
950   ASSERT_EFI_ERROR (Status);
951 
952   AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
953   ASSERT (AcpiS3Context != NULL);
954 
955   VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);
956   Status = RestoreLockBox (
957              &gEfiBootScriptExecutorVariableGuid,
958              &TempEfiBootScriptExecutorVariable,
959              &VarSize
960              );
961   ASSERT_EFI_ERROR (Status);
962 
963   Status = RestoreLockBox (
964              &gEfiBootScriptExecutorContextGuid,
965              NULL,
966              NULL
967              );
968   ASSERT_EFI_ERROR (Status);
969 
970   EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable;
971   ASSERT (EfiBootScriptExecutorVariable != NULL);
972 
973   DEBUG (( DEBUG_INFO, "AcpiS3Context = %x\n", AcpiS3Context));
974   DEBUG (( DEBUG_INFO, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));
975   DEBUG (( DEBUG_INFO, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));
976   DEBUG (( DEBUG_INFO, "AcpiS3Context->IdtrProfile = %x\n", AcpiS3Context->IdtrProfile));
977   DEBUG (( DEBUG_INFO, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));
978   DEBUG (( DEBUG_INFO, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));
979   DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackBase = %x\n", AcpiS3Context->BootScriptStackBase));
980   DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackSize = %x\n", AcpiS3Context->BootScriptStackSize));
981   DEBUG (( DEBUG_INFO, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));
982 
983   //
984   // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor.
985   // Script dispatch image and context (parameter) are handled by platform.
986   // We just use restore all lock box in place, no need restore one by one.
987   //
988   Status = RestoreAllLockBoxInPlace ();
989   ASSERT_EFI_ERROR (Status);
990   if (EFI_ERROR (Status)) {
991     // Something wrong
992     CpuDeadLoop ();
993   }
994 
995   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
996     //
997     // Need reconstruct page table here, since we do not trust ACPINvs.
998     //
999     if (IsLongModeWakingVector (AcpiS3Context)) {
1000       Build4GPageTableOnly = FALSE;
1001     } else {
1002       Build4GPageTableOnly = TRUE;
1003     }
1004     RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);
1005   }
1006 
1007   //
1008   // Attempt to use content from SMRAM first
1009   //
1010   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
1011   if (GuidHob != NULL) {
1012     //
1013     // Below SwitchStack/AsmEnablePaging64 function has
1014     // assumption that it's in 32 bits mode now.
1015     // Add ASSERT code to indicate this assumption.
1016     //
1017     ASSERT(sizeof (UINTN) == sizeof (UINT32));
1018 
1019     Status = PeiServicesLocatePpi (
1020                               &gPeiSmmAccessPpiGuid,
1021                               0,
1022                               NULL,
1023                               (VOID **) &SmmAccess
1024                               );
1025     for (Index = 0; !EFI_ERROR (Status); Index++) {
1026       Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
1027     }
1028 
1029     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
1030     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
1031 
1032     SmmS3ResumeState->ReturnCs           = AsmReadCs ();
1033     SmmS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;
1034     SmmS3ResumeState->ReturnContext1     = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
1035     SmmS3ResumeState->ReturnContext2     = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;
1036     SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);
1037 
1038     DEBUG (( DEBUG_INFO, "SMM S3 Signature                = %x\n", SmmS3ResumeState->Signature));
1039     DEBUG (( DEBUG_INFO, "SMM S3 Stack Base               = %x\n", SmmS3ResumeState->SmmS3StackBase));
1040     DEBUG (( DEBUG_INFO, "SMM S3 Stack Size               = %x\n", SmmS3ResumeState->SmmS3StackSize));
1041     DEBUG (( DEBUG_INFO, "SMM S3 Resume Entry Point       = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint));
1042     DEBUG (( DEBUG_INFO, "SMM S3 CR0                      = %x\n", SmmS3ResumeState->SmmS3Cr0));
1043     DEBUG (( DEBUG_INFO, "SMM S3 CR3                      = %x\n", SmmS3ResumeState->SmmS3Cr3));
1044     DEBUG (( DEBUG_INFO, "SMM S3 CR4                      = %x\n", SmmS3ResumeState->SmmS3Cr4));
1045     DEBUG (( DEBUG_INFO, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));
1046     DEBUG (( DEBUG_INFO, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));
1047     DEBUG (( DEBUG_INFO, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));
1048     DEBUG (( DEBUG_INFO, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));
1049     DEBUG (( DEBUG_INFO, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));
1050     DEBUG (( DEBUG_INFO, "SMM S3 Smst                     = %x\n", SmmS3ResumeState->Smst));
1051 
1052     if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
1053       SwitchStack (
1054         (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,
1055         (VOID *)AcpiS3Context,
1056         0,
1057         (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize)
1058         );
1059     }
1060     if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
1061       //
1062       // Switch to long mode to complete resume.
1063       //
1064 
1065       InterruptStatus = SaveAndDisableInterrupts ();
1066       //
1067       // Need to make sure the GDT is loaded with values that support long mode and real mode.
1068       //
1069       AsmWriteGdtr (&mGdt);
1070       //
1071       // update segment selectors per the new GDT.
1072       //
1073       AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
1074       //
1075       // Restore interrupt state.
1076       //
1077       SetInterruptState (InterruptStatus);
1078 
1079       Cr0.UintN = AsmReadCr0 ();
1080       if (Cr0.Bits.PG != 0) {
1081         //
1082         // We're in 32-bit mode, with paging enabled. We can't set CR3 to
1083         // the 64-bit page tables without first disabling paging.
1084         //
1085         Cr0.Bits.PG = 0;
1086         AsmWriteCr0 (Cr0.UintN);
1087       }
1088       AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);
1089 
1090       //
1091       // Disable interrupt of Debug timer, since IDT table cannot work in long mode.
1092       // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,
1093       // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.
1094       //
1095       SaveAndSetDebugTimerInterrupt (FALSE);
1096 
1097       AsmEnablePaging64 (
1098         0x38,
1099         SmmS3ResumeState->SmmS3ResumeEntryPoint,
1100         (UINT64)(UINTN)AcpiS3Context,
1101         0,
1102         SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize
1103         );
1104     }
1105 
1106   }
1107 
1108   S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable );
1109   return EFI_SUCCESS;
1110 }
1111 /**
1112   Main entry for S3 Resume PEIM.
1113 
1114   This routine is to install EFI_PEI_S3_RESUME2_PPI.
1115 
1116   @param  FileHandle              Handle of the file being invoked.
1117   @param  PeiServices             Pointer to PEI Services table.
1118 
1119   @retval EFI_SUCCESS S3Resume Ppi is installed successfully.
1120 
1121 **/
1122 EFI_STATUS
1123 EFIAPI
PeimS3ResumeEntryPoint(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)1124 PeimS3ResumeEntryPoint (
1125   IN EFI_PEI_FILE_HANDLE       FileHandle,
1126   IN CONST EFI_PEI_SERVICES    **PeiServices
1127   )
1128 {
1129   EFI_STATUS  Status;
1130 
1131   //
1132   // Install S3 Resume Ppi
1133   //
1134   Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
1135   ASSERT_EFI_ERROR (Status);
1136 
1137   return EFI_SUCCESS;
1138 }
1139 
1140