Beispiel #1
0
/**

  This function is IO write handler for reset.

  @param Context Context for IO write handler
  @param Port    IO port
  @param Value   IO port value
  @param Action  IO write action

**/
VOID
IoResetWriteHandler (
  IN VOID      *Context,
  IN UINT16    Port,
  IN UINT32    Value,
  OUT UINT32   *Action
  )
{
  UINT32  Index;

  Index = ApicToIndex (ReadLocalApicId ());

  DEBUG ((EFI_D_INFO, "(FRM) !!!IoResetHandler!!!\n"));

  FrmTeardownBsp (Index);
  AsmWbinvd ();
  
  //
  // Work-around for CTRL+ALT+DEL, it will pass 0x2.
  //
  Value = Value | 0x6;
  IoWrite8 (Port, (UINT8)Value);

  CpuDeadLoop ();

  *Action = IO_ACTION_PASSTHROUGH;

  return ;
}
Beispiel #2
0
/**

  This function is IO write handler for KBC reset.

  @param Context Context for IO write handler
  @param Port    IO port
  @param Value   IO port value
  @param Action  IO write action

**/
VOID
KbcResetWriteHandler (
  IN VOID      *Context,
  IN UINT16    Port,
  IN UINT32    Value,
  OUT UINT32   *Action
  )
{
  UINT32  Index;

  Index = ApicToIndex (ReadLocalApicId ());

  DEBUG ((EFI_D_INFO, "(FRM) !!!KbcResetHandler!!!\n"));

  if ((UINT8)Value != KBC_RESET_WRITE_VALUE) {
    // Normal KB
    *Action = IO_ACTION_PASSTHROUGH;
    return ;
  }

  // Reset
  FrmTeardownBsp (Index);
  AsmWbinvd ();
  *Action = IO_ACTION_PASSTHROUGH;

  return ;
}
/**
  Erase a certain block from address LbaWriteAddress

  @param[in] WriteAddress  The flash address to be erased.

  @return The status of flash erase.
**/
EFI_STATUS
FlashFdErase (
  IN UINTN                                WriteAddress
  )
{
  EFI_STATUS  Status;

  Status = mSpiProtocol->Execute (
                           mSpiProtocol,
                           SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
                           0,                      // PrefixOpcodeIndex
                           FALSE,                  // DataCycle
                           TRUE,                   // Atomic
                           FALSE,                  // ShiftOut
                           WriteAddress,           // Address
                           0,                      // Data Number
                           NULL,
                           EnumSpiRegionBios       // SPI_REGION_TYPE
                           );
  DEBUG((DEBUG_INFO, "FlashFdErase - 0x%x - %r\n", (UINTN)WriteAddress, Status));

  AsmWbinvd ();

  return Status;
}
/**
  Writes specified number of bytes from the input buffer to the address

  @param[in]      WriteAddress  The flash address to be written.
  @param[in, out] NumBytes      The number of bytes.
  @param[in]      Buffer        The data buffer to be written.

  @return The status of flash write.
**/
EFI_STATUS
FlashFdWrite (
  IN  UINTN                               WriteAddress,
  IN OUT UINTN                            *NumBytes,
  IN  UINT8                               *Buffer
  )
{
  EFI_STATUS  Status;

  Status = EFI_SUCCESS;

  Status = mSpiProtocol->Execute (
                           mSpiProtocol,
                           SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
                           0,                      // PrefixOpcodeIndex
                           TRUE,                   // DataCycle
                           TRUE,                   // Atomic
                           TRUE,                   // ShiftOut
                           WriteAddress,           // Address
                           (UINT32) (*NumBytes),   // Data Number
                           Buffer,
                           EnumSpiRegionBios
                           );
  DEBUG((DEBUG_INFO, "FlashFdWrite - 0x%x - %r\n", (UINTN)WriteAddress, Status));

  AsmWbinvd ();

  return Status;
}
Beispiel #5
0
/**
  Invalidates processor instruction cache for a memory range. Subsequent execution in this range
  causes a fresh memory fetch to retrieve code to be executed.                                  
    
  @param  This                  A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
  @param  ProcessorIndex        Specifies which processor's instruction cache is to be invalidated.
  @param  Start                 Specifies the physical base of the memory range to be invalidated.                                
  @param  Length                Specifies the minimum number of bytes in the processor's instruction
                                cache to invalidate.                                                 
                                
  @retval EFI_SUCCESS           Always returned.

**/
EFI_STATUS
EFIAPI
InvalidateInstructionCache (
  IN EFI_DEBUG_SUPPORT_PROTOCOL       *This,
  IN UINTN                            ProcessorIndex,
  IN VOID                             *Start,
  IN UINT64                           Length
  )
{
  AsmWbinvd ();
  return EFI_SUCCESS;
}
Beispiel #6
0
/**

  This function initialize host context per CPU.

  @param Index   CPU Index

**/
VOID
InitHostContextPerCpu (
  IN UINT32 Index
  )
{
  //
  // VmxOn for this CPU
  //
  AsmWbinvd ();
  AsmWriteCr3 (mHostContextCommon.PageTable);
  AsmWriteCr4 (AsmReadCr4 () | CR4_PAE | ((UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED1_MSR_INDEX)));
  AsmWriteCr0 (AsmReadCr0 () | ((UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED1_MSR_INDEX)));
  AsmVmxOn (&mHostContextCommon.HostContextPerCpu[Index].Vmcs);
}
Beispiel #7
0
/**
  Flush CPU data cache. If the instruction cache is fully coherent
  with all DMA operations then function can just return EFI_SUCCESS.

  @param  This              Protocol instance structure
  @param  Start             Physical address to start flushing from.
  @param  Length            Number of bytes to flush. Round up to chipset
                            granularity.
  @param  FlushType         Specifies the type of flush operation to perform.

  @retval EFI_SUCCESS       If cache was flushed
  @retval EFI_UNSUPPORTED   If flush type is not supported.
  @retval EFI_DEVICE_ERROR  If requested range could not be flushed.

**/
EFI_STATUS
EFIAPI
CpuFlushCpuDataCache (
  IN EFI_CPU_ARCH_PROTOCOL     *This,
  IN EFI_PHYSICAL_ADDRESS      Start,
  IN UINT64                    Length,
  IN EFI_CPU_FLUSH_TYPE        FlushType
  )
{
  if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
    AsmWbinvd ();
    return EFI_SUCCESS;
  } else if (FlushType == EfiCpuFlushTypeInvalidate) {
    AsmInvd ();
    return EFI_SUCCESS;
  } else {
    return EFI_UNSUPPORTED;
  }
}
Beispiel #8
0
/**

  This function is IO handler for reset.

  @param Index CPU index
  @param Port  Reset IO port address
  @param Data  Reset IO port data

**/
VOID
IoResetHandler (
  IN UINT32  Index,
  IN UINT16  Port,
  IN UINT8   Data
  )
{
  DEBUG ((EFI_D_INFO, "(FRM) !!!IoResetHandler!!!\n"));

  FrmTeardownBsp (Index);
  AsmWbinvd ();

  //
  // Work-around for CTRL+ALT+DEL, it will pass 0x2.
  //
  Data = Data | 0x6;
  IoWrite8 (Port, Data);

  CpuDeadLoop ();

  return ;
}
Beispiel #9
0
EFI_STATUS
EFIAPI
CpuFlushCpuDataCache (
  IN EFI_CPU_ARCH_PROTOCOL           *This,
  IN EFI_PHYSICAL_ADDRESS            Start,
  IN UINT64                          Length,
  IN EFI_CPU_FLUSH_TYPE              FlushType
  )
/*++

Routine Description:
  Flush CPU data cache. If the instruction cache is fully coherent
  with all DMA operations then function can just return EFI_SUCCESS.

Arguments:
  This                - Protocol instance structure
  Start               - Physical address to start flushing from.
  Length              - Number of bytes to flush. Round up to chipset 
                         granularity.
  FlushType           - Specifies the type of flush operation to perform.

Returns: 

  EFI_SUCCESS           - If cache was flushed
  EFI_UNSUPPORTED       - If flush type is not supported.
  EFI_DEVICE_ERROR      - If requested range could not be flushed.

--*/
{
  if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
    AsmWbinvd ();
    return EFI_SUCCESS;
  } else if (FlushType == EfiCpuFlushTypeInvalidate) {
    AsmInvd ();
    return EFI_SUCCESS;
  } else {
    return EFI_UNSUPPORTED;
  }
}
Beispiel #10
0
/**

  This function launch guest BSP.

**/
VOID
LaunchGuestBsp (
  VOID
  )
{
  UINTN             Flag;
  UINTN             Rflags;

  Flag = SetJump (&mGuestJumpBuffer);
  if (Flag != 0) {
    DEBUG ((EFI_D_INFO, "(FRM) !!!Guest JumpBack to EFI!!!\n"));
    // Run successfully
    return ;
  }

  AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs);

  //
  // Launch STM
  //
  LaunchStm (mBspIndex);

  AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs);

  AcquireSpinLock (&mHostContextCommon.DebugLock);
  DumpVmcsAllField ();
  ReleaseSpinLock (&mHostContextCommon.DebugLock);

  AsmWbinvd ();

  Rflags = AsmVmLaunch (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Register);
  DEBUG ((EFI_D_ERROR, "(FRM) !!!LaunchGuestBsp FAIL!!!\n"));
  DEBUG ((EFI_D_ERROR, "(FRM) Rflags: %08x\n", Rflags));
  DEBUG ((EFI_D_ERROR, "(FRM) VMCS_32_RO_VM_INSTRUCTION_ERROR: %08x\n", (UINTN)VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX)));
 
  CpuDeadLoop ();
}
Beispiel #11
0
/**
  Entry function of Boot script exector. This function will be executed in
  S3 boot path.
  This function should not return, because it is invoked by switch stack.

  @param  AcpiS3Context    a pointer to a structure of ACPI_S3_CONTEXT
  @param  PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE

  @retval EFI_INVALID_PARAMETER - OS waking vector not found
  @retval EFI_UNSUPPORTED - something wrong when we resume to OS
**/
EFI_STATUS
EFIAPI
S3BootScriptExecutorEntryFunction (
  IN ACPI_S3_CONTEXT       *AcpiS3Context,
  IN PEI_S3_RESUME_STATE   *PeiS3ResumeState
  )
{
  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
  EFI_STATUS                                    Status;
  UINTN                                         TempStackTop;
  UINTN                                         TempStack[0x10];
  UINTN                                         AsmTransferControl16Address;
  IA32_DESCRIPTOR                               IdtDescriptor;

  //
  // Disable interrupt of Debug timer, since new IDT table cannot handle it.
  //
  SaveAndSetDebugTimerInterrupt (FALSE);

  AsmReadIdtr (&IdtDescriptor);
  //
  // Restore IDT for debug
  //
  SetIdtEntry (AcpiS3Context);

  //
  // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer.
  //
  InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL);

  //
  // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
  // for that parameter.
  //
  Status = S3BootScriptExecute ();
  
  //
  // If invalid script table or opcode in S3 boot script table.
  //
  ASSERT_EFI_ERROR (Status);
  
  if (EFI_ERROR (Status)) {
    CpuDeadLoop ();
    return Status;
  }

  AsmWbinvd ();

  //
  // Get ACPI Table Address
  //
  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));

  //
  // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
  //
  if (PeiS3ResumeState != 0) {
    //
    // Need report status back to S3ResumePeim. 
    // If boot script execution is failed, S3ResumePeim wil report the error status code.
    //
    PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
    if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
      //
      // X64 S3 Resume
      //
      DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
      PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32;

      if ((Facs != NULL) &&
          (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) &&
          (Facs->FirmwareWakingVector != 0) ) {
        //
        // more step needed - because relative address is handled differently between X64 and IA32.
        //
        AsmTransferControl16Address = (UINTN)AsmTransferControl16;
        AsmFixAddress16 = (UINT32)AsmTransferControl16Address;
        AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12));
      }

      AsmDisablePaging64 (
        PeiS3ResumeState->ReturnCs,
        (UINT32)PeiS3ResumeState->ReturnEntryPoint,
        (UINT32)(UINTN)AcpiS3Context,
        (UINT32)(UINTN)PeiS3ResumeState,
        (UINT32)PeiS3ResumeState->ReturnStackPointer
        );
    } else {
      //
      // IA32 S3 Resume
      //
      DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
      PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl;

      SwitchStack (
        (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
        (VOID *)(UINTN)AcpiS3Context,
        (VOID *)(UINTN)PeiS3ResumeState,
        (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
        );
    }

    //
    // Never run to here
    //
    CpuDeadLoop();
    return EFI_UNSUPPORTED;
  }
  
  //
  // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly
  //
  if (Facs->XFirmwareWakingVector != 0) {
    //
    // Switch to native waking vector
    //
    TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
        ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
      //
      // X64 long mode waking vector
      //
      DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
        SwitchStack (
          (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
          NULL,
          NULL,
          (VOID *)(UINTN)TempStackTop
          );
      } else {
        // Unsupported for 32bit DXE, 64bit OS vector
        DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
        ASSERT (FALSE);
      }
    } else {
      //
      // IA32 protected mode waking vector (Page disabled)
      //
      DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
        AsmDisablePaging64 (
          0x10,
          (UINT32)Facs->XFirmwareWakingVector,
          0,
          0,
          (UINT32)TempStackTop
          );
      } else {
        SwitchStack (
          (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
          NULL,
          NULL,
          (VOID *)(UINTN)TempStackTop
          );
      }
    }
  } else {
    //
    // 16bit Realmode waking vector
    //
    DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
    AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
  }

  //
  // Never run to here
  //
  CpuDeadLoop();
  return EFI_UNSUPPORTED;
}
Beispiel #12
0
/**
  Calling this function causes the system to enter a power state for capsule
  update.

  Reset update should not return, if it returns, it means the system does
  not support capsule update.

**/
VOID
EFIAPI
EnterS3WithImmediateWake (
VOID
)
{
  UINT8     Data8;
  UINT16    Data16;
  UINT32    Data32;
  UINTN     Eflags;
  UINTN     RegCr0;
  EFI_TIME  EfiTime;
  UINT32    SmiEnSave;

  Eflags  = AsmReadEflags ();
  if ( (Eflags & 0x200) ) {
     DisableInterrupts ();
  }

  //
  //  Write all cache data to memory because processor will lost power
  //
  AsmWbinvd();
  RegCr0 = AsmReadCr0();
  AsmWriteCr0 (RegCr0 | 0x060000000);

  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));

  //
  // Pogram RTC alarm for immediate WAKE
  //

  //
  // Disable SMI sources
  //
  IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);

  //
  // Disable RTC alarm interrupt
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));

  //
  // Clear RTC alarm if already set
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);              // Read clears alarm status

  //
  // Disable all WAKE events
  //
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);

  //
  // Clear all WAKE status bits
  //
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);

  //
  // Avoid RTC rollover
  //
  do {
    WaitForRTCUpdate();
    IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
    EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
  } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);

  //
  // Read RTC time
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
  EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
  EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
  EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);

  //
  // Set RTC alarm
  //

  //
  // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
  // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
  //
  if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
    Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
  } else {
    Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
  }

  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);

  //
  // Enable RTC alarm interrupt
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));

  //
  // Enable RTC alarm as WAKE event
  //
  Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));

  //
  // Enter S3
  //
  Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
  Data32  = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
  Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);

  //
  // Enable Interrupt if it's enabled before
  //
  if ( (Eflags & 0x200) ) {
     EnableInterrupts ();
  }
}
Beispiel #13
0
/**
  Entry function of Boot script exector. This function will be executed in
  S3 boot path.
  This function should not return, because it is invoked by switch stack.

  @param  AcpiS3Context    a pointer to a structure of ACPI_S3_CONTEXT
  @param  PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE

  @retval EFI_INVALID_PARAMETER - OS waking vector not found
  @retval EFI_UNSUPPORTED - something wrong when we resume to OS
**/
EFI_STATUS
EFIAPI
S3BootScriptExecutorEntryFunction (
    IN ACPI_S3_CONTEXT       *AcpiS3Context,
    IN PEI_S3_RESUME_STATE   *PeiS3ResumeState
)
{
    EFI_STATUS                                    Status;

    //
    // Disable interrupt of Debug timer, since new IDT table cannot handle it.
    //
    SaveAndSetDebugTimerInterrupt (FALSE);

    //
    // Restore IDT for debug
    //
    SetIdtEntry (AcpiS3Context);

    //
    // Initialize Debug Agent to support source level debug in S3 path.
    //
    InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL);

    //
    // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
    // for that parameter.
    //
    Status = S3BootScriptExecute ();

    AsmWbinvd ();

    //
    // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
    //
    if (PeiS3ResumeState != 0) {
        //
        // Need report status back to S3ResumePeim.
        // If boot script execution is failed, S3ResumePeim wil report the error status code.
        //
        PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
        //
        // IA32 S3 Resume
        //
        DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
        PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16;

        SwitchStack (
            (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
            (VOID *)(UINTN)AcpiS3Context,
            (VOID *)(UINTN)PeiS3ResumeState,
            (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
        );

        //
        // Never run to here
        //
        CpuDeadLoop();
        return EFI_UNSUPPORTED;
    }

    //
    // Never run to here
    //
    CpuDeadLoop();
    return EFI_UNSUPPORTED;
}