From 38c2cbb9354d7f58e48f9f649f23eb9bd0d3cfca Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Thu, 27 Apr 2017 11:22:26 +0800 Subject: UefiCpuPkg: Move to new location Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.S | 38 + .../Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.asm | 45 + .../Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.nasm | 41 + .../Universal/Acpi/S3Resume2Pei/S3Resume.c | 1176 ++++++++++++++++++++ .../Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf | 101 ++ .../Universal/Acpi/S3Resume2Pei/S3Resume2Pei.uni | 26 + .../Acpi/S3Resume2Pei/S3Resume2PeiExtra.uni | 20 + .../Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.S | 37 + .../Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.asm | 41 + .../Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.nasm | 41 + 10 files changed, 1566 insertions(+) create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.S create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.asm create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.nasm create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.uni create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2PeiExtra.uni create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.S create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.asm create mode 100644 Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.nasm (limited to 'Core/UefiCpuPkg/Universal/Acpi') diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.S b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.S new file mode 100644 index 0000000000..ede19f21c3 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.S @@ -0,0 +1,38 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2012, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* AsmFuncs.S +#* +#* Abstract: +#* +#* Assembly function to set segment selectors. +# +#------------------------------------------------------------------------------ + +.text + +#------------------------------------------------------------------------------ +# +# VOID +# EFIAPI +# AsmSetDataSelectors ( +# IN UINT16 SelectorValue +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmSetDataSelectors) +ASM_PFX(AsmSetDataSelectors): + movl 4(%esp), %eax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + ret diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.asm b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.asm new file mode 100644 index 0000000000..79496c48d7 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.asm @@ -0,0 +1,45 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmFuncs.Asm +; +; Abstract: +; +; Assembly function to set segment selectors. +; +; Notes: +; +;------------------------------------------------------------------------------ + +.686 +.model flat,C + +.code + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmSetDataSelectors ( +; IN UINT16 SelectorValue +; ); +;------------------------------------------------------------------------------ +AsmSetDataSelectors PROC near public + mov eax, [esp + 4] + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ret +AsmSetDataSelectors ENDP + +END diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.nasm b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.nasm new file mode 100644 index 0000000000..fa5dda1466 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/Ia32/AsmFuncs.nasm @@ -0,0 +1,41 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmFuncs.Asm +; +; Abstract: +; +; Assembly function to set segment selectors. +; +; Notes: +; +;------------------------------------------------------------------------------ + +SECTION .text + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmSetDataSelectors ( +; IN UINT16 SelectorValue +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmSetDataSelectors) +ASM_PFX(AsmSetDataSelectors): + mov eax, [esp + 4] +o16 mov ds, ax +o16 mov es, ax +o16 mov fs, ax +o16 mov gs, ax +o16 mov ss, ax + ret + diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c new file mode 100644 index 0000000000..e53ed21bdc --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c @@ -0,0 +1,1176 @@ +/** @file + This module produces the EFI_PEI_S3_RESUME2_PPI. + This module works with StandAloneBootScriptExecutor to S3 resume to OS. + This module will execute the boot script saved during last boot and after that, + control is passed to OS waking up handler. + + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions + of the BSD License which accompanies this distribution. The + full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + This macro aligns the address of a variable with auto storage + duration down to CPU_STACK_ALIGNMENT. + + Since the stack grows downward, the result preserves more of the + stack than the original address (or the same amount), not less. +**/ +#define STACK_ALIGN_DOWN(Ptr) \ + ((UINTN)(Ptr) & ~(UINTN)(CPU_STACK_ALIGNMENT - 1)) + +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull + +#pragma pack(1) +typedef union { + struct { + UINT32 LimitLow : 16; + UINT32 BaseLow : 16; + UINT32 BaseMid : 8; + UINT32 Type : 4; + UINT32 System : 1; + UINT32 Dpl : 2; + UINT32 Present : 1; + UINT32 LimitHigh : 4; + UINT32 Software : 1; + UINT32 Reserved : 1; + UINT32 DefaultSize : 1; + UINT32 Granularity : 1; + UINT32 BaseHigh : 8; + } Bits; + UINT64 Uint64; +} IA32_GDT; + +// +// Page-Map Level-4 Offset (PML4) and +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB +// +typedef union { + struct { + UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User + UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Reserved:1; // Reserved + UINT64 MustBeZero:2; // Must Be Zero + UINT64 Available:3; // Available for use by system software + UINT64 PageTableBaseAddress:40; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system software + UINT64 Nx:1; // No Execute bit + } Bits; + UINT64 Uint64; +} PAGE_MAP_AND_DIRECTORY_POINTER; + +// +// Page Table Entry 2MB +// +typedef union { + struct { + UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User + UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page + UINT64 MustBe1:1; // Must be 1 + UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system software + UINT64 PAT:1; // + UINT64 MustBeZero:8; // Must be zero; + UINT64 PageTableBaseAddress:31; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system software + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution + } Bits; + UINT64 Uint64; +} PAGE_TABLE_ENTRY; + +// +// Page Table Entry 1GB +// +typedef union { + struct { + UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User + UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page + UINT64 MustBe1:1; // Must be 1 + UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system software + UINT64 PAT:1; // + UINT64 MustBeZero:17; // Must be zero; + UINT64 PageTableBaseAddress:22; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system software + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution + } Bits; + UINT64 Uint64; +} PAGE_TABLE_1G_ENTRY; + +#pragma pack() + +// +// Function prototypes +// +/** + a ASM function to transfer control to OS. + + @param S3WakingVector The S3 waking up vector saved in ACPI Facs table + @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer +**/ +typedef +VOID +(EFIAPI *ASM_TRANSFER_CONTROL) ( + IN UINT32 S3WakingVector, + IN UINT32 AcpiLowMemoryBase + ); + +/** + Restores the platform to its preboot configuration for an S3 resume and + jumps to the OS waking vector. + + This function will restore the platform to its pre-boot configuration that was + pre-stored in the boot script table and transfer control to OS waking vector. + Upon invocation, this function is responsible for locating the following + information before jumping to OS waking vector: + - ACPI tables + - boot script table + - any other information that it needs + + The S3RestoreConfig() function then executes the pre-stored boot script table + and transitions the platform to the pre-boot state. The boot script is recorded + during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and + EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function + transfers control to the OS waking vector. If the OS supports only a real-mode + waking vector, this function will switch from flat mode to real mode before + jumping to the waking vector. If all platform pre-boot configurations are + successfully restored and all other necessary information is ready, this + function will never return and instead will directly jump to the OS waking + vector. If this function returns, it indicates that the attempt to resume + from the ACPI S3 sleep state failed. + + @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI + + @retval EFI_ABORTED Execution of the S3 resume boot script table failed. + @retval EFI_NOT_FOUND Some necessary information that is used for the S3 + resume boot path could not be located. + +**/ +EFI_STATUS +EFIAPI +S3RestoreConfig2 ( + IN EFI_PEI_S3_RESUME2_PPI *This + ); + +/** + Set data segment selectors value including DS/ES/FS/GS/SS. + + @param[in] SelectorValue Segment selector value to be set. + +**/ +VOID +EFIAPI +AsmSetDataSelectors ( + IN UINT16 SelectorValue + ); + +// +// Globals +// +EFI_PEI_S3_RESUME2_PPI mS3ResumePpi = { S3RestoreConfig2 }; + +EFI_PEI_PPI_DESCRIPTOR mPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiS3Resume2PpiGuid, + &mS3ResumePpi +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListPostScriptTable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiPostScriptTablePpiGuid, + 0 +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListEndOfPeiTable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + 0 +}; + +// +// Global Descriptor Table (GDT) +// +GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = { +/* selector { Global Segment Descriptor } */ +/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, +/* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, +/* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +/* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}}, +/* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}}, +/* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}}, +/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, +}; + +#define DATA_SEGEMENT_SELECTOR 0x18 + +// +// IA32 Gdt register +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = { + sizeof (mGdtEntries) - 1, + (UINTN) mGdtEntries + }; + +/** + Performance measure function to get S3 detailed performance data. + + This function will getS3 detailed performance data and saved in pre-reserved ACPI memory. +**/ +VOID +WriteToOsS3PerformanceData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase; + PERF_HEADER *PerfHeader; + PERF_DATA *PerfData; + UINT64 Ticker; + UINTN Index; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; + UINTN VarSize; + UINTN LogEntryKey; + CONST VOID *Handle; + CONST CHAR8 *Token; + CONST CHAR8 *Module; + UINT64 StartTicker; + UINT64 EndTicker; + UINT64 StartValue; + UINT64 EndValue; + BOOLEAN CountUp; + UINT64 Freq; + + // + // Retrieve time stamp count as early as possible + // + Ticker = GetPerformanceCounter (); + + Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); + + Freq = DivU64x32 (Freq, 1000); + + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **) &VariableServices + ); + if (EFI_ERROR (Status)) { + return; + } + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = VariableServices->GetVariable ( + VariableServices, + L"PerfDataMemAddr", + &gPerformanceProtocolGuid, + NULL, + &VarSize, + &mAcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to retrieve variable to log S3 performance data \n")); + return; + } + + PerfHeader = (PERF_HEADER *) (UINTN) mAcpiLowMemoryBase; + + if (PerfHeader->Signiture != PERFORMANCE_SIGNATURE) { + DEBUG ((EFI_D_ERROR, "Performance data in ACPI memory get corrupted! \n")); + return; + } + + // + // Record total S3 resume time. + // + if (EndValue >= StartValue) { + PerfHeader->S3Resume = Ticker - StartValue; + CountUp = TRUE; + } else { + PerfHeader->S3Resume = StartValue - Ticker; + CountUp = FALSE; + } + + // + // Get S3 detailed performance data + // + Index = 0; + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if (EndTicker != 0) { + PerfData = &PerfHeader->S3Entry[Index]; + + // + // Use File Handle to specify the different performance log for PEIM. + // File Handle is the base address of PEIM FFS file. + // + if ((AsciiStrnCmp (Token, "PEIM", PEI_PERFORMANCE_STRING_SIZE) == 0) && (Handle != NULL)) { + AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle); + } else { + AsciiStrnCpyS (PerfData->Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); + } + if (StartTicker == 1) { + StartTicker = StartValue; + } + if (EndTicker == 1) { + EndTicker = StartValue; + } + Ticker = CountUp? (EndTicker - StartTicker) : (StartTicker - EndTicker); + PerfData->Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + + // + // Only Record > 1ms performance data so that more big performance can be recorded. + // + if ((Ticker > Freq) && (++Index >= PERF_PEI_ENTRY_MAX_NUM)) { + // + // Reach the maximum number of PEI performance log entries. + // + break; + } + } + } + PerfHeader->S3EntryNum = (UINT32) Index; +} + +/** + The function will check if current waking vector is long mode. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + + @retval TRUE Current context need long mode waking vector. + @retval FALSE Current context need not long mode waking vector. +**/ +BOOLEAN +IsLongModeWakingVector ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ) +{ + EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + + Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); + if ((Facs == NULL) || + (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) || + ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) { + // Something wrong with FACS + return FALSE; + } + if (Facs->XFirmwareWakingVector != 0) { + 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)) { + // Both BIOS and OS wants 64bit vector + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + return TRUE; + } + } + } + return FALSE; +} + +/** + Jump to OS waking vector. + The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE +**/ +VOID +EFIAPI +S3ResumeBootOs ( + IN ACPI_S3_CONTEXT *AcpiS3Context, + IN PEI_S3_RESUME_STATE *PeiS3ResumeState + ) +{ + EFI_STATUS Status; + EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + ASM_TRANSFER_CONTROL AsmTransferControl; + UINTN TempStackTop; + UINTN TempStack[0x10]; + + // + // Restore IDT + // + AsmWriteIdtr (&PeiS3ResumeState->Idtr); + + if (PeiS3ResumeState->ReturnStatus != EFI_SUCCESS) { + // + // Report Status code that boot script execution is failed + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR) + ); + } + + // + // NOTE: Because Debug Timer interrupt and system interrupts will be disabled + // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted + // by soft debugger. + // + + PERF_END (NULL, "ScriptExec", NULL, 0); + + // + // Install BootScriptDonePpi + // + Status = PeiServicesInstallPpi (&mPpiListPostScriptTable); + ASSERT_EFI_ERROR (Status); + + // + // Get ACPI Table Address + // + Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); + + if ((Facs == NULL) || + (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) || + ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) { + // + // Report Status code that no valid vector is found + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MAJOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR) + ); + CpuDeadLoop (); + return ; + } + + // + // Install EndOfPeiPpi + // + Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable); + ASSERT_EFI_ERROR (Status); + + // + // report status code on S3 resume + // + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE); + + PERF_CODE ( + WriteToOsS3PerformanceData (); + ); + + AsmTransferControl = (ASM_TRANSFER_CONTROL)(UINTN)PeiS3ResumeState->AsmTransferControl; + if (Facs->XFirmwareWakingVector != 0) { + // + // Switch to native waking vector + // + TempStackTop = (UINTN)&TempStack + sizeof(TempStack); + DEBUG (( + DEBUG_INFO, + "%a() Stack Base: 0x%x, Stack Size: 0x%x\n", + __FUNCTION__, + TempStackTop, + 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 ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + AsmEnablePaging64 ( + 0x38, + Facs->XFirmwareWakingVector, + 0, + 0, + (UINT64)(UINTN)TempStackTop + ); + } else { + // + // Report Status code that no valid waking vector is found + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MAJOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR) + ); + DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); + ASSERT (FALSE); + CpuDeadLoop (); + return ; + } + } else { + // + // IA32 protected mode waking vector (Page disabled) + // + DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector, + NULL, + NULL, + (VOID *)(UINTN)TempStackTop + ); + } + } else { + // + // 16bit Realmode waking vector + // + DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); + AsmTransferControl (Facs->FirmwareWakingVector, 0x0); + } + + // + // Report Status code the failure of S3Resume + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MAJOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR) + ); + + // + // Never run to here + // + CpuDeadLoop(); +} + +/** + Restore S3 page table because we do not trust ACPINvs content. + If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. + + @param S3NvsPageTableAddress PageTableAddress in ACPINvs + @param Build4GPageTableOnly If BIOS just build 4G page table only +**/ +VOID +RestoreS3PageTables ( + IN UINTN S3NvsPageTableAddress, + IN BOOLEAN Build4GPageTableOnly + ) +{ + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + UINT32 RegEax; + UINT32 RegEdx; + UINT8 PhysicalAddressBits; + EFI_PHYSICAL_ADDRESS PageAddress; + UINTN IndexOfPml4Entries; + UINTN IndexOfPdpEntries; + UINTN IndexOfPageDirectoryEntries; + UINT32 NumberOfPml4EntriesNeeded; + UINT32 NumberOfPdpEntriesNeeded; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMap; + PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; + PAGE_TABLE_ENTRY *PageDirectoryEntry; + VOID *Hob; + BOOLEAN Page1GSupport; + PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry; + UINT64 AddressEncMask; + + // + // Make sure AddressEncMask is contained to smallest supported address field + // + AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64; + + // + // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information. + // The whole page table is too large to be saved in SMRAM. + // + // The assumption is : whole page table is allocated in CONTINUOUS memory and CR3 points to TOP page. + // + DEBUG ((DEBUG_INFO, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly)); + + // + // By architecture only one PageMapLevel4 exists - so lets allocate storage for it. + // + PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + Page1GSupport = FALSE; + if (PcdGetBool(PcdUse1GPageTable)) { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT26) != 0) { + Page1GSupport = TRUE; + } + } + } + + // + // Get physical address bits supported. + // + Hob = GetFirstHob (EFI_HOB_TYPE_CPU); + if (Hob != NULL) { + PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; + } else { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + } + + // + // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // + ASSERT (PhysicalAddressBits <= 52); + if (PhysicalAddressBits > 48) { + PhysicalAddressBits = 48; + } + + // + // NOTE: In order to save time to create full page table, we just create 4G page table by default. + // And let PF handler in BootScript driver to create more on request. + // + if (Build4GPageTableOnly) { + PhysicalAddressBits = 32; + ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2)); + } + // + // Calculate the table entries needed. + // + if (PhysicalAddressBits <= 39) { + NumberOfPml4EntriesNeeded = 1; + NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30)); + } else { + NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39)); + NumberOfPdpEntriesNeeded = 512; + } + + PageMapLevel4Entry = PageMap; + PageAddress = 0; + for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) { + // + // Each PML4 entry points to a page of Page Directory Pointer entires. + // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop. + // + PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + // + // Make a PML4 Entry + // + PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask; + PageMapLevel4Entry->Bits.ReadWrite = 1; + PageMapLevel4Entry->Bits.Present = 1; + + if (Page1GSupport) { + PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) { + // + // Fill in the Page Directory entries + // + PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask; + PageDirectory1GEntry->Bits.ReadWrite = 1; + PageDirectory1GEntry->Bits.Present = 1; + PageDirectory1GEntry->Bits.MustBe1 = 1; + } + } else { + for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { + // + // Each Directory Pointer entries points to a page of Page Directory entires. + // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop. + // + PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + // + // Fill in a Page Directory Pointer Entries + // + PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask; + PageDirectoryPointerEntry->Bits.ReadWrite = 1; + PageDirectoryPointerEntry->Bits.Present = 1; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask; + PageDirectoryEntry->Bits.ReadWrite = 1; + PageDirectoryEntry->Bits.Present = 1; + PageDirectoryEntry->Bits.MustBe1 = 1; + } + } + } + } + return ; + } else { + // + // If DXE is running 32-bit mode, no need to establish page table. + // + return ; + } +} + +/** + Jump to boot script executor driver. + + The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + @param EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in + boot script execute driver +**/ +VOID +EFIAPI +S3ResumeExecuteBootScript ( + IN ACPI_S3_CONTEXT *AcpiS3Context, + IN BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable + ) +{ + EFI_STATUS Status; + PEI_SMM_ACCESS_PPI *SmmAccess; + UINTN Index; + VOID *GuidHob; + IA32_DESCRIPTOR *IdtDescriptor; + VOID *IdtBuffer; + PEI_S3_RESUME_STATE *PeiS3ResumeState; + BOOLEAN InterruptStatus; + + DEBUG ((DEBUG_INFO, "S3ResumeExecuteBootScript()\n")); + + // + // Attempt to use content from SMRAM first + // + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + if (GuidHob != NULL) { + // + // Last step for SMM - send SMI for initialization + // + + // + // Send SMI to APs + // + SendSmiIpiAllExcludingSelf (); + // + // Send SMI to BSP + // + SendSmiIpi (GetApicId ()); + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccess + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Close all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + + DEBUG ((DEBUG_INFO, "Lock all SMRAM regions before executing boot script\n")); + + for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + } + } + + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress); + } + + if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { + // + // On some platform, such as ECP, a dispatch node in boot script table may execute a 32-bit PEIM which may need PeiServices + // pointer. So PeiServices need preserve in (IDTBase- sizeof (UINTN)). + // + IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile); + // + // Make sure the newly allocated IDT align with 16-bytes + // + IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16)); + if (IdtBuffer == NULL) { + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MAJOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED) + ); + ASSERT (FALSE); + } + // + // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer + // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code + // + ZeroMem (IdtBuffer, 16); + AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer); + CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1)); + IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16); + *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer (); + } + + InterruptStatus = SaveAndDisableInterrupts (); + // + // Need to make sure the GDT is loaded with values that support long mode and real mode. + // + AsmWriteGdtr (&mGdt); + // + // update segment selectors per the new GDT. + // + AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR); + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + + // + // Prepare data for return back + // + PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState)); + if (PeiS3ResumeState == NULL) { + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MAJOR, + (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_FAILED) + ); + ASSERT (FALSE); + } + DEBUG ((DEBUG_INFO, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState)); + PeiS3ResumeState->ReturnCs = 0x10; + PeiS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs; + PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status); + // + // Save IDT + // + AsmReadIdtr (&PeiS3ResumeState->Idtr); + + // + // Report Status Code to indicate S3 boot script execution + // + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT); + + PERF_START (NULL, "ScriptExec", NULL, 0); + + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + // + // X64 S3 Resume + // + DEBUG ((DEBUG_INFO, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n")); + + // + // Switch to long mode to complete resume. + // + AsmEnablePaging64 ( + 0x38, + EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint, + (UINT64)(UINTN)AcpiS3Context, + (UINT64)(UINTN)PeiS3ResumeState, + (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize) + ); + } else { + // + // IA32 S3 Resume + // + DEBUG ((DEBUG_INFO, "transfer control to Standalone Boot Script Executor\r\n")); + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint, + (VOID *)AcpiS3Context, + (VOID *)PeiS3ResumeState, + (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize) + ); + } + + // + // Never run to here + // + CpuDeadLoop(); +} +/** + Restores the platform to its preboot configuration for an S3 resume and + jumps to the OS waking vector. + + This function will restore the platform to its pre-boot configuration that was + pre-stored in the boot script table and transfer control to OS waking vector. + Upon invocation, this function is responsible for locating the following + information before jumping to OS waking vector: + - ACPI tables + - boot script table + - any other information that it needs + + The S3RestoreConfig() function then executes the pre-stored boot script table + and transitions the platform to the pre-boot state. The boot script is recorded + during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and + EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function + transfers control to the OS waking vector. If the OS supports only a real-mode + waking vector, this function will switch from flat mode to real mode before + jumping to the waking vector. If all platform pre-boot configurations are + successfully restored and all other necessary information is ready, this + function will never return and instead will directly jump to the OS waking + vector. If this function returns, it indicates that the attempt to resume + from the ACPI S3 sleep state failed. + + @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI + + @retval EFI_ABORTED Execution of the S3 resume boot script table failed. + @retval EFI_NOT_FOUND Some necessary information that is used for the S3 + resume boot path could not be located. + +**/ +EFI_STATUS +EFIAPI +S3RestoreConfig2 ( + IN EFI_PEI_S3_RESUME2_PPI *This + ) +{ + EFI_STATUS Status; + PEI_SMM_ACCESS_PPI *SmmAccess; + UINTN Index; + ACPI_S3_CONTEXT *AcpiS3Context; + EFI_PHYSICAL_ADDRESS TempEfiBootScriptExecutorVariable; + EFI_PHYSICAL_ADDRESS TempAcpiS3Context; + BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; + UINTN VarSize; + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + SMM_S3_RESUME_STATE *SmmS3ResumeState; + VOID *GuidHob; + BOOLEAN Build4GPageTableOnly; + BOOLEAN InterruptStatus; + + TempAcpiS3Context = 0; + TempEfiBootScriptExecutorVariable = 0; + + DEBUG ((DEBUG_INFO, "Enter S3 PEIM\r\n")); + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = RestoreLockBox ( + &gEfiAcpiVariableGuid, + &TempAcpiS3Context, + &VarSize + ); + ASSERT_EFI_ERROR (Status); + + Status = RestoreLockBox ( + &gEfiAcpiS3ContextGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context; + ASSERT (AcpiS3Context != NULL); + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = RestoreLockBox ( + &gEfiBootScriptExecutorVariableGuid, + &TempEfiBootScriptExecutorVariable, + &VarSize + ); + ASSERT_EFI_ERROR (Status); + + Status = RestoreLockBox ( + &gEfiBootScriptExecutorContextGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable; + ASSERT (EfiBootScriptExecutorVariable != NULL); + + DEBUG (( DEBUG_INFO, "AcpiS3Context = %x\n", AcpiS3Context)); + DEBUG (( DEBUG_INFO, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->IdtrProfile = %x\n", AcpiS3Context->IdtrProfile)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackBase = %x\n", AcpiS3Context->BootScriptStackBase)); + DEBUG (( DEBUG_INFO, "AcpiS3Context->BootScriptStackSize = %x\n", AcpiS3Context->BootScriptStackSize)); + DEBUG (( DEBUG_INFO, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint)); + + // + // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor. + // Script dispatch image and context (parameter) are handled by platform. + // We just use restore all lock box in place, no need restore one by one. + // + Status = RestoreAllLockBoxInPlace (); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + // Something wrong + CpuDeadLoop (); + } + + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + // + // Need reconstruct page table here, since we do not trust ACPINvs. + // + if (IsLongModeWakingVector (AcpiS3Context)) { + Build4GPageTableOnly = FALSE; + } else { + Build4GPageTableOnly = TRUE; + } + RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly); + } + + // + // Attempt to use content from SMRAM first + // + GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid); + if (GuidHob != NULL) { + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccess + ); + for (Index = 0; !EFI_ERROR (Status); Index++) { + Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index); + } + + SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob); + SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart; + + SmmS3ResumeState->ReturnCs = AsmReadCs (); + SmmS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript; + SmmS3ResumeState->ReturnContext1 = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context; + SmmS3ResumeState->ReturnContext2 = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable; + SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)STACK_ALIGN_DOWN (&Status); + + DEBUG (( DEBUG_INFO, "SMM S3 Signature = %x\n", SmmS3ResumeState->Signature)); + DEBUG (( DEBUG_INFO, "SMM S3 Stack Base = %x\n", SmmS3ResumeState->SmmS3StackBase)); + DEBUG (( DEBUG_INFO, "SMM S3 Stack Size = %x\n", SmmS3ResumeState->SmmS3StackSize)); + DEBUG (( DEBUG_INFO, "SMM S3 Resume Entry Point = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint)); + DEBUG (( DEBUG_INFO, "SMM S3 CR0 = %x\n", SmmS3ResumeState->SmmS3Cr0)); + DEBUG (( DEBUG_INFO, "SMM S3 CR3 = %x\n", SmmS3ResumeState->SmmS3Cr3)); + DEBUG (( DEBUG_INFO, "SMM S3 CR4 = %x\n", SmmS3ResumeState->SmmS3Cr4)); + DEBUG (( DEBUG_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); + DEBUG (( DEBUG_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); + DEBUG (( DEBUG_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); + DEBUG (( DEBUG_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); + DEBUG (( DEBUG_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); + DEBUG (( DEBUG_INFO, "SMM S3 Smst = %x\n", SmmS3ResumeState->Smst)); + + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint, + (VOID *)AcpiS3Context, + 0, + (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize) + ); + } + if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { + // + // Switch to long mode to complete resume. + // + + InterruptStatus = SaveAndDisableInterrupts (); + // + // Need to make sure the GDT is loaded with values that support long mode and real mode. + // + AsmWriteGdtr (&mGdt); + // + // update segment selectors per the new GDT. + // + AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR); + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + + AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3); + + // + // Disable interrupt of Debug timer, since IDT table cannot work in long mode. + // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts, + // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger. + // + SaveAndSetDebugTimerInterrupt (FALSE); + + AsmEnablePaging64 ( + 0x38, + SmmS3ResumeState->SmmS3ResumeEntryPoint, + (UINT64)(UINTN)AcpiS3Context, + 0, + SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize + ); + } + + } + + S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable ); + return EFI_SUCCESS; +} +/** + Main entry for S3 Resume PEIM. + + This routine is to install EFI_PEI_S3_RESUME2_PPI. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Pointer to PEI Services table. + + @retval EFI_SUCCESS S3Resume Ppi is installed successfully. + +**/ +EFI_STATUS +EFIAPI +PeimS3ResumeEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + // + // Install S3 Resume Ppi + // + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf new file mode 100644 index 0000000000..d514523089 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf @@ -0,0 +1,101 @@ +## @file +# S3 Resume Module installs EFI_PEI_S3_RESUME2_PPI. +# +# This module works with StandAloneBootScriptExecutor to S3 resume to OS. +# This module will excute the boot script saved during last boot and after that, +# control is passed to OS waking up handler. +# +# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+# +# This program and the accompanying materials are +# licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = S3Resume2Pei + MODULE_UNI_FILE = S3Resume2Pei.uni + FILE_GUID = 89E549B0-7CFE-449d-9BA3-10D8B2312D71 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimS3ResumeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + S3Resume.c + +[Sources.IA32] + Ia32/AsmFuncs.asm + Ia32/AsmFuncs.nasm + Ia32/AsmFuncs.S + +[Sources.X64] + X64/AsmFuncs.asm + X64/AsmFuncs.nasm + X64/AsmFuncs.S + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + PeiServicesTablePointerLib + PerformanceLib + HobLib + PeiServicesLib + PeimEntryPoint + TimerLib + BaseLib + DebugLib + PcdLib + IoLib + BaseMemoryLib + MemoryAllocationLib + DebugAgentLib + LocalApicLib + ReportStatusCodeLib + LockBoxLib + PrintLib + +[Guids] + gEfiBootScriptExecutorVariableGuid ## SOMETIMES_CONSUMES ## UNDEFINED # LockBox + gEfiBootScriptExecutorContextGuid ## SOMETIMES_CONSUMES ## UNDEFINED # LockBox + gPerformanceProtocolGuid ## SOMETIMES_CONSUMES ## Variable:L"PerfDataMemAddr" + ## SOMETIMES_CONSUMES ## HOB + ## SOMETIMES_CONSUMES ## UNDEFINED # LockBox + gEfiAcpiVariableGuid + gEfiAcpiS3ContextGuid ## SOMETIMES_CONSUMES ## UNDEFINED # LockBox + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES + gEfiPeiS3Resume2PpiGuid ## PRODUCES + gPeiSmmAccessPpiGuid ## SOMETIMES_CONSUMES + gPeiPostScriptTablePpiGuid ## SOMETIMES_PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_PRODUCES + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES + +[Depex] + TRUE + +[UserExtensions.TianoCore."ExtraFiles"] + S3Resume2PeiExtra.uni diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.uni b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.uni new file mode 100644 index 0000000000..0f78a15173 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.uni @@ -0,0 +1,26 @@ +// /** @file +// S3 Resume Module installs EFI_PEI_S3_RESUME2_PPI. +// +// This module works with StandAloneBootScriptExecutor to S3 resume to OS. +// This module will excute the boot script saved during last boot and after that, +// control is passed to OS waking up handler. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials are +// licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "S3 Resume Module installs EFI_PEI_S3_RESUME2_PPI" + +#string STR_MODULE_DESCRIPTION #language en-US "This module works with StandAloneBootScriptExecutor to S3 resume to OS.\n" + "This module will execute the boot script saved during last boot and after that,\n" + "control is passed to the OS waking up handler." + diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2PeiExtra.uni b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2PeiExtra.uni new file mode 100644 index 0000000000..4d88423149 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2PeiExtra.uni @@ -0,0 +1,20 @@ +// /** @file +// S3Resume2Pei Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials are +// licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"S3 Resume v2 PEI Module" + + diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.S b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.S new file mode 100644 index 0000000000..2ced09f35c --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.S @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------ +#* +#* Copyright (c) 2012, Intel Corporation. All rights reserved.
+#* This program and the accompanying materials +#* are licensed and made available under the terms and conditions of the BSD License +#* which accompanies this distribution. The full text of the license may be found at +#* http://opensource.org/licenses/bsd-license.php +#* +#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +#* +#* AsmFuncs.S +#* +#* Abstract: +#* +#* Assembly function to set segment selectors. +# +#------------------------------------------------------------------------------ + +.text + +#------------------------------------------------------------------------------ +# +# VOID +# EFIAPI +# AsmSetDataSelectors ( +# IN UINT16 SelectorValue +# ); +#------------------------------------------------------------------------------ +ASM_GLOBAL ASM_PFX(AsmSetDataSelectors) +ASM_PFX(AsmSetDataSelectors): + movw %cx, %ss + movw %cx, %ds + movw %cx, %es + movw %cx, %fs + movw %cx, %gs + ret diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.asm b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.asm new file mode 100644 index 0000000000..eb014a5862 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.asm @@ -0,0 +1,41 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2012, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmFuncs.Asm +; +; Abstract: +; +; Assembly function to set segment selectors. +; +; Notes: +; +;------------------------------------------------------------------------------ + +.code + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmSetDataSelectors ( +; IN UINT16 SelectorValue +; ); +;------------------------------------------------------------------------------ +AsmSetDataSelectors PROC + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + mov ss, cx + ret +AsmSetDataSelectors ENDP + +END diff --git a/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.nasm b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.nasm new file mode 100644 index 0000000000..add73cacc0 --- /dev/null +++ b/Core/UefiCpuPkg/Universal/Acpi/S3Resume2Pei/X64/AsmFuncs.nasm @@ -0,0 +1,41 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmFuncs.Asm +; +; Abstract: +; +; Assembly function to set segment selectors. +; +; Notes: +; +;------------------------------------------------------------------------------ + +DEFAULT REL +SECTION .text + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmSetDataSelectors ( +; IN UINT16 SelectorValue +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmSetDataSelectors) +ASM_PFX(AsmSetDataSelectors): +o16 mov ds, cx +o16 mov es, cx +o16 mov fs, cx +o16 mov gs, cx +o16 mov ss, cx + ret + -- cgit v1.2.3