Home | History | Annotate | Download | only in S3Resume2Pei
      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
    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
    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
    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
    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
    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
    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
   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