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