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 execute the boot script saved during last boot and after that,
      5   control is passed to OS waking up handler.
      6 
      7   Copyright (c) 2006 - 2016, 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   // Retrieve time stamp count as early as possible
    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     DEBUG ((
    519       DEBUG_INFO,
    520       "%a() Stack Base: 0x%x, Stack Size: 0x%x\n",
    521       __FUNCTION__,
    522       TempStackTop,
    523       sizeof (TempStack)
    524       ));
    525     if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
    526         ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
    527         ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
    528       //
    529       // X64 long mode waking vector
    530       //
    531       DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
    532       if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    533         AsmEnablePaging64 (
    534           0x38,
    535           Facs->XFirmwareWakingVector,
    536           0,
    537           0,
    538           (UINT64)(UINTN)TempStackTop
    539           );
    540       } else {
    541         //
    542         // Report Status code that no valid waking vector is found
    543         //
    544         REPORT_STATUS_CODE (
    545           EFI_ERROR_CODE | EFI_ERROR_MAJOR,
    546           (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
    547           );
    548         DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
    549         ASSERT (FALSE);
    550         CpuDeadLoop ();
    551         return ;
    552       }
    553     } else {
    554       //
    555       // IA32 protected mode waking vector (Page disabled)
    556       //
    557       DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
    558       SwitchStack (
    559         (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector,
    560         NULL,
    561         NULL,
    562         (VOID *)(UINTN)TempStackTop
    563         );
    564     }
    565   } else {
    566     //
    567     // 16bit Realmode waking vector
    568     //
    569     DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
    570     AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
    571   }
    572 
    573   //
    574   // Report Status code the failure of S3Resume
    575   //
    576   REPORT_STATUS_CODE (
    577     EFI_ERROR_CODE | EFI_ERROR_MAJOR,
    578     (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
    579     );
    580 
    581   //
    582   // Never run to here
    583   //
    584   CpuDeadLoop();
    585 }
    586 
    587 /**
    588   Restore S3 page table because we do not trust ACPINvs content.
    589   If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
    590 
    591   @param S3NvsPageTableAddress   PageTableAddress in ACPINvs
    592   @param Build4GPageTableOnly    If BIOS just build 4G page table only
    593 **/
    594 VOID
    595 RestoreS3PageTables (
    596   IN UINTN                                         S3NvsPageTableAddress,
    597   IN BOOLEAN                                       Build4GPageTableOnly
    598   )
    599 {
    600   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    601     UINT32                                        RegEax;
    602     UINT32                                        RegEdx;
    603     UINT8                                         PhysicalAddressBits;
    604     EFI_PHYSICAL_ADDRESS                          PageAddress;
    605     UINTN                                         IndexOfPml4Entries;
    606     UINTN                                         IndexOfPdpEntries;
    607     UINTN                                         IndexOfPageDirectoryEntries;
    608     UINT32                                        NumberOfPml4EntriesNeeded;
    609     UINT32                                        NumberOfPdpEntriesNeeded;
    610     PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel4Entry;
    611     PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;
    612     PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;
    613     PAGE_TABLE_ENTRY                              *PageDirectoryEntry;
    614     VOID                                          *Hob;
    615     BOOLEAN                                       Page1GSupport;
    616     PAGE_TABLE_1G_ENTRY                           *PageDirectory1GEntry;
    617 
    618     //
    619     // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information.
    620     // The whole page table is too large to be saved in SMRAM.
    621     //
    622     // The assumption is : whole page table is allocated in CONTINUOUS memory and CR3 points to TOP page.
    623     //
    624     DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));
    625 
    626     //
    627     // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
    628     //
    629     PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
    630     S3NvsPageTableAddress += SIZE_4KB;
    631 
    632     Page1GSupport = FALSE;
    633     if (PcdGetBool(PcdUse1GPageTable)) {
    634       AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    635       if (RegEax >= 0x80000001) {
    636         AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
    637         if ((RegEdx & BIT26) != 0) {
    638           Page1GSupport = TRUE;
    639         }
    640       }
    641     }
    642 
    643     //
    644     // Get physical address bits supported.
    645     //
    646     Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
    647     if (Hob != NULL) {
    648       PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
    649     } else {
    650       AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    651       if (RegEax >= 0x80000008) {
    652         AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
    653         PhysicalAddressBits = (UINT8) RegEax;
    654       } else {
    655         PhysicalAddressBits = 36;
    656       }
    657     }
    658 
    659     //
    660     // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
    661     //
    662     ASSERT (PhysicalAddressBits <= 52);
    663     if (PhysicalAddressBits > 48) {
    664       PhysicalAddressBits = 48;
    665     }
    666 
    667     //
    668     // NOTE: In order to save time to create full page table, we just create 4G page table by default.
    669     // And let PF handler in BootScript driver to create more on request.
    670     //
    671     if (Build4GPageTableOnly) {
    672       PhysicalAddressBits = 32;
    673       ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));
    674     }
    675     //
    676     // Calculate the table entries needed.
    677     //
    678     if (PhysicalAddressBits <= 39) {
    679       NumberOfPml4EntriesNeeded = 1;
    680       NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
    681     } else {
    682       NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
    683       NumberOfPdpEntriesNeeded = 512;
    684     }
    685 
    686     PageMapLevel4Entry = PageMap;
    687     PageAddress        = 0;
    688     for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
    689       //
    690       // Each PML4 entry points to a page of Page Directory Pointer entires.
    691       // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
    692       //
    693       PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
    694       S3NvsPageTableAddress += SIZE_4KB;
    695 
    696       //
    697       // Make a PML4 Entry
    698       //
    699       PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;
    700       PageMapLevel4Entry->Bits.ReadWrite = 1;
    701       PageMapLevel4Entry->Bits.Present = 1;
    702 
    703       if (Page1GSupport) {
    704         PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
    705 
    706         for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
    707           //
    708           // Fill in the Page Directory entries
    709           //
    710           PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
    711           PageDirectory1GEntry->Bits.ReadWrite = 1;
    712           PageDirectory1GEntry->Bits.Present = 1;
    713           PageDirectory1GEntry->Bits.MustBe1 = 1;
    714         }
    715       } else {
    716         for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
    717           //
    718           // Each Directory Pointer entries points to a page of Page Directory entires.
    719           // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
    720           //
    721           PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress;
    722           S3NvsPageTableAddress += SIZE_4KB;
    723 
    724           //
    725           // Fill in a Page Directory Pointer Entries
    726           //
    727           PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;
    728           PageDirectoryPointerEntry->Bits.ReadWrite = 1;
    729           PageDirectoryPointerEntry->Bits.Present = 1;
    730 
    731           for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
    732             //
    733             // Fill in the Page Directory entries
    734             //
    735             PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
    736             PageDirectoryEntry->Bits.ReadWrite = 1;
    737             PageDirectoryEntry->Bits.Present = 1;
    738             PageDirectoryEntry->Bits.MustBe1 = 1;
    739           }
    740         }
    741       }
    742     }
    743     return ;
    744   } else {
    745   	//
    746   	// If DXE is running 32-bit mode, no need to establish page table.
    747   	//
    748     return ;
    749   }
    750 }
    751 
    752 /**
    753   Jump to boot script executor driver.
    754 
    755   The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table.
    756 
    757   @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
    758   @param  EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in
    759                                         boot script execute driver
    760 **/
    761 VOID
    762 EFIAPI
    763 S3ResumeExecuteBootScript (
    764   IN ACPI_S3_CONTEXT                *AcpiS3Context,
    765   IN BOOT_SCRIPT_EXECUTOR_VARIABLE  *EfiBootScriptExecutorVariable
    766   )
    767 {
    768   EFI_STATUS                 Status;
    769   PEI_SMM_ACCESS_PPI         *SmmAccess;
    770   UINTN                      Index;
    771   VOID                       *GuidHob;
    772   IA32_DESCRIPTOR            *IdtDescriptor;
    773   VOID                       *IdtBuffer;
    774   PEI_S3_RESUME_STATE        *PeiS3ResumeState;
    775   BOOLEAN                    InterruptStatus;
    776 
    777   DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n"));
    778 
    779   //
    780   // Attempt to use content from SMRAM first
    781   //
    782   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
    783   if (GuidHob != NULL) {
    784     //
    785     // Last step for SMM - send SMI for initialization
    786     //
    787 
    788     //
    789     // Send SMI to APs
    790     //
    791     SendSmiIpiAllExcludingSelf ();
    792     //
    793     // Send SMI to BSP
    794     //
    795     SendSmiIpi (GetApicId ());
    796 
    797     Status = PeiServicesLocatePpi (
    798                               &gPeiSmmAccessPpiGuid,
    799                               0,
    800                               NULL,
    801                               (VOID **) &SmmAccess
    802                               );
    803     if (!EFI_ERROR (Status)) {
    804       DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n"));
    805 
    806       for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
    807         Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
    808       }
    809 
    810       DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n"));
    811 
    812       for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
    813         Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
    814       }
    815     }
    816   }
    817 
    818   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    819     AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);
    820   }
    821 
    822   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
    823     //
    824     // On some platform, such as ECP, a dispatch node in boot script table may execute a 32-bit PEIM which may need PeiServices
    825     // pointer. So PeiServices need preserve in (IDTBase- sizeof (UINTN)).
    826     //
    827     IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
    828     //
    829     // Make sure the newly allocated IDT align with 16-bytes
    830     //
    831     IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16));
    832     if (IdtBuffer == NULL) {
    833       REPORT_STATUS_CODE (
    834         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
    835         (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED)
    836         );
    837       ASSERT (FALSE);
    838     }
    839     //
    840     // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer
    841     // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code
    842     //
    843     ZeroMem (IdtBuffer, 16);
    844     AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer);
    845     CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1));
    846     IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16);
    847     *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();
    848   }
    849 
    850   InterruptStatus = SaveAndDisableInterrupts ();
    851   //
    852   // Need to make sure the GDT is loaded with values that support long mode and real mode.
    853   //
    854   AsmWriteGdtr (&mGdt);
    855   //
    856   // update segment selectors per the new GDT.
    857   //
    858   AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
    859   //
    860   // Restore interrupt state.
    861   //
    862   SetInterruptState (InterruptStatus);
    863 
    864   //
    865   // Prepare data for return back
    866   //
    867   PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState));
    868   if (PeiS3ResumeState == NULL) {
    869     REPORT_STATUS_CODE (
    870       EFI_ERROR_CODE | EFI_ERROR_MAJOR,
    871       (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED)
    872       );
    873     ASSERT (FALSE);
    874   }
    875   DEBUG (( EFI_D_ERROR, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));
    876   PeiS3ResumeState->ReturnCs           = 0x10;
    877   PeiS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;
    878   PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);
    879   //
    880   // Save IDT
    881   //
    882   AsmReadIdtr (&PeiS3ResumeState->Idtr);
    883 
    884   //
    885   // Report Status Code to indicate S3 boot script execution
    886   //
    887   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT);
    888 
    889   PERF_START (NULL, "ScriptExec", NULL, 0);
    890 
    891   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    892     //
    893     // X64 S3 Resume
    894     //
    895     DEBUG (( EFI_D_ERROR, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n"));
    896 
    897     //
    898     // Switch to long mode to complete resume.
    899     //
    900     AsmEnablePaging64 (
    901       0x38,
    902       EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
    903       (UINT64)(UINTN)AcpiS3Context,
    904       (UINT64)(UINTN)PeiS3ResumeState,
    905       (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
    906       );
    907   } else {
    908     //
    909     // IA32 S3 Resume
    910     //
    911     DEBUG (( EFI_D_ERROR, "transfer control to Standalone Boot Script Executor\r\n"));
    912     SwitchStack (
    913       (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
    914       (VOID *)AcpiS3Context,
    915       (VOID *)PeiS3ResumeState,
    916       (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
    917       );
    918   }
    919 
    920   //
    921   // Never run to here
    922   //
    923   CpuDeadLoop();
    924 }
    925 /**
    926   Restores the platform to its preboot configuration for an S3 resume and
    927   jumps to the OS waking vector.
    928 
    929   This function will restore the platform to its pre-boot configuration that was
    930   pre-stored in the boot script table and transfer control to OS waking vector.
    931   Upon invocation, this function is responsible for locating the following
    932   information before jumping to OS waking vector:
    933     - ACPI tables
    934     - boot script table
    935     - any other information that it needs
    936 
    937   The S3RestoreConfig() function then executes the pre-stored boot script table
    938   and transitions the platform to the pre-boot state. The boot script is recorded
    939   during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
    940   EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions.  Finally, this function
    941   transfers control to the OS waking vector. If the OS supports only a real-mode
    942   waking vector, this function will switch from flat mode to real mode before
    943   jumping to the waking vector.  If all platform pre-boot configurations are
    944   successfully restored and all other necessary information is ready, this
    945   function will never return and instead will directly jump to the OS waking
    946   vector. If this function returns, it indicates that the attempt to resume
    947   from the ACPI S3 sleep state failed.
    948 
    949   @param[in] This         Pointer to this instance of the PEI_S3_RESUME_PPI
    950 
    951   @retval EFI_ABORTED     Execution of the S3 resume boot script table failed.
    952   @retval EFI_NOT_FOUND   Some necessary information that is used for the S3
    953                           resume boot path could not be located.
    954 
    955 **/
    956 EFI_STATUS
    957 EFIAPI
    958 S3RestoreConfig2 (
    959   IN EFI_PEI_S3_RESUME2_PPI  *This
    960   )
    961 {
    962   EFI_STATUS                                    Status;
    963   PEI_SMM_ACCESS_PPI                            *SmmAccess;
    964   UINTN                                         Index;
    965   ACPI_S3_CONTEXT                               *AcpiS3Context;
    966   EFI_PHYSICAL_ADDRESS                          TempEfiBootScriptExecutorVariable;
    967   EFI_PHYSICAL_ADDRESS                          TempAcpiS3Context;
    968   BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;
    969   UINTN                                         VarSize;
    970   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;
    971   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;
    972   VOID                                          *GuidHob;
    973   BOOLEAN                                       Build4GPageTableOnly;
    974   BOOLEAN                                       InterruptStatus;
    975 
    976   TempAcpiS3Context = 0;
    977   TempEfiBootScriptExecutorVariable = 0;
    978 
    979   DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));
    980 
    981   VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
    982   Status = RestoreLockBox (
    983              &gEfiAcpiVariableGuid,
    984              &TempAcpiS3Context,
    985              &VarSize
    986              );
    987   ASSERT_EFI_ERROR (Status);
    988 
    989   Status = RestoreLockBox (
    990              &gEfiAcpiS3ContextGuid,
    991              NULL,
    992              NULL
    993              );
    994   ASSERT_EFI_ERROR (Status);
    995 
    996   AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
    997   ASSERT (AcpiS3Context != NULL);
    998 
    999   VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);
   1000   Status = RestoreLockBox (
   1001              &gEfiBootScriptExecutorVariableGuid,
   1002              &TempEfiBootScriptExecutorVariable,
   1003              &VarSize
   1004              );
   1005   ASSERT_EFI_ERROR (Status);
   1006 
   1007   Status = RestoreLockBox (
   1008              &gEfiBootScriptExecutorContextGuid,
   1009              NULL,
   1010              NULL
   1011              );
   1012   ASSERT_EFI_ERROR (Status);
   1013 
   1014   EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable;
   1015   ASSERT (EfiBootScriptExecutorVariable != NULL);
   1016 
   1017   DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context));
   1018   DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));
   1019   DEBUG (( EFI_D_ERROR, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));
   1020   DEBUG (( EFI_D_ERROR, "AcpiS3Context->IdtrProfile = %x\n", AcpiS3Context->IdtrProfile));
   1021   DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));
   1022   DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));
   1023   DEBUG (( EFI_D_ERROR, "AcpiS3Context->BootScriptStackBase = %x\n", AcpiS3Context->BootScriptStackBase));
   1024   DEBUG (( EFI_D_ERROR, "AcpiS3Context->BootScriptStackSize = %x\n", AcpiS3Context->BootScriptStackSize));
   1025   DEBUG (( EFI_D_ERROR, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));
   1026 
   1027   //
   1028   // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor.
   1029   // Script dispatch image and context (parameter) are handled by platform.
   1030   // We just use restore all lock box in place, no need restore one by one.
   1031   //
   1032   Status = RestoreAllLockBoxInPlace ();
   1033   ASSERT_EFI_ERROR (Status);
   1034   if (EFI_ERROR (Status)) {
   1035     // Something wrong
   1036     CpuDeadLoop ();
   1037   }
   1038 
   1039   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
   1040     //
   1041     // Need reconstruct page table here, since we do not trust ACPINvs.
   1042     //
   1043     if (IsLongModeWakingVector (AcpiS3Context)) {
   1044       Build4GPageTableOnly = FALSE;
   1045     } else {
   1046       Build4GPageTableOnly = TRUE;
   1047     }
   1048     RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);
   1049   }
   1050 
   1051   //
   1052   // Attempt to use content from SMRAM first
   1053   //
   1054   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
   1055   if (GuidHob != NULL) {
   1056     Status = PeiServicesLocatePpi (
   1057                               &gPeiSmmAccessPpiGuid,
   1058                               0,
   1059                               NULL,
   1060                               (VOID **) &SmmAccess
   1061                               );
   1062     for (Index = 0; !EFI_ERROR (Status); Index++) {
   1063       Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
   1064     }
   1065 
   1066     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
   1067     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
   1068 
   1069     SmmS3ResumeState->ReturnCs           = AsmReadCs ();
   1070     SmmS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;
   1071     SmmS3ResumeState->ReturnContext1     = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
   1072     SmmS3ResumeState->ReturnContext2     = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;
   1073     SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status);
   1074 
   1075     DEBUG (( EFI_D_ERROR, "SMM S3 Signature                = %x\n", SmmS3ResumeState->Signature));
   1076     DEBUG (( EFI_D_ERROR, "SMM S3 Stack Base               = %x\n", SmmS3ResumeState->SmmS3StackBase));
   1077     DEBUG (( EFI_D_ERROR, "SMM S3 Stack Size               = %x\n", SmmS3ResumeState->SmmS3StackSize));
   1078     DEBUG (( EFI_D_ERROR, "SMM S3 Resume Entry Point       = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint));
   1079     DEBUG (( EFI_D_ERROR, "SMM S3 CR0                      = %x\n", SmmS3ResumeState->SmmS3Cr0));
   1080     DEBUG (( EFI_D_ERROR, "SMM S3 CR3                      = %x\n", SmmS3ResumeState->SmmS3Cr3));
   1081     DEBUG (( EFI_D_ERROR, "SMM S3 CR4                      = %x\n", SmmS3ResumeState->SmmS3Cr4));
   1082     DEBUG (( EFI_D_ERROR, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));
   1083     DEBUG (( EFI_D_ERROR, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));
   1084     DEBUG (( EFI_D_ERROR, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));
   1085     DEBUG (( EFI_D_ERROR, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));
   1086     DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));
   1087     DEBUG (( EFI_D_ERROR, "SMM S3 Smst                     = %x\n", SmmS3ResumeState->Smst));
   1088 
   1089     if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
   1090       SwitchStack (
   1091         (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,
   1092         (VOID *)AcpiS3Context,
   1093         0,
   1094         (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize)
   1095         );
   1096     }
   1097     if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
   1098       //
   1099       // Switch to long mode to complete resume.
   1100       //
   1101 
   1102       InterruptStatus = SaveAndDisableInterrupts ();
   1103       //
   1104       // Need to make sure the GDT is loaded with values that support long mode and real mode.
   1105       //
   1106       AsmWriteGdtr (&mGdt);
   1107       //
   1108       // update segment selectors per the new GDT.
   1109       //
   1110       AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
   1111       //
   1112       // Restore interrupt state.
   1113       //
   1114       SetInterruptState (InterruptStatus);
   1115 
   1116       AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);
   1117 
   1118       //
   1119       // Disable interrupt of Debug timer, since IDT table cannot work in long mode.
   1120       // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,
   1121       // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.
   1122       //
   1123       SaveAndSetDebugTimerInterrupt (FALSE);
   1124 
   1125       AsmEnablePaging64 (
   1126         0x38,
   1127         SmmS3ResumeState->SmmS3ResumeEntryPoint,
   1128         (UINT64)(UINTN)AcpiS3Context,
   1129         0,
   1130         SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize
   1131         );
   1132     }
   1133 
   1134   }
   1135 
   1136   S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable );
   1137   return EFI_SUCCESS;
   1138 }
   1139 /**
   1140   Main entry for S3 Resume PEIM.
   1141 
   1142   This routine is to install EFI_PEI_S3_RESUME2_PPI.
   1143 
   1144   @param  FileHandle              Handle of the file being invoked.
   1145   @param  PeiServices             Pointer to PEI Services table.
   1146 
   1147   @retval EFI_SUCCESS S3Resume Ppi is installed successfully.
   1148 
   1149 **/
   1150 EFI_STATUS
   1151 EFIAPI
   1152 PeimS3ResumeEntryPoint (
   1153   IN EFI_PEI_FILE_HANDLE       FileHandle,
   1154   IN CONST EFI_PEI_SERVICES    **PeiServices
   1155   )
   1156 {
   1157   EFI_STATUS  Status;
   1158 
   1159   //
   1160   // Install S3 Resume Ppi
   1161   //
   1162   Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
   1163   ASSERT_EFI_ERROR (Status);
   1164 
   1165   return EFI_SUCCESS;
   1166 }
   1167 
   1168