From be46cd5f85a8c9eb5a717987e9856aea47afeee5 Mon Sep 17 00:00:00 2001 From: jljusten Date: Mon, 29 Aug 2011 22:18:19 +0000 Subject: [PATCH] MdeModulePkg: Add BootScriptExecutorDxe driver Signed-off-by: jljusten Reviewed-by: mdkinney Reviewed-by: rsun3 Reviewed-by: jyao1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12225 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Guid/BootScriptExecutorVariable.h | 49 ++ MdeModulePkg/MdeModulePkg.dec | 4 + MdeModulePkg/MdeModulePkg.dsc | 3 + .../BootScriptExecutorDxe.inf | 83 +++ .../Acpi/BootScriptExecutorDxe/IA32/S3Asm.S | 66 +++ .../Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm | 71 +++ .../BootScriptExecutorDxe/IA32/SetIdtEntry.c | 63 +++ .../BootScriptExecutorDxe/ScriptExecute.c | 477 ++++++++++++++++++ .../BootScriptExecutorDxe/ScriptExecute.h | 88 ++++ .../Acpi/BootScriptExecutorDxe/X64/S3Asm.S | 82 +++ .../Acpi/BootScriptExecutorDxe/X64/S3Asm.asm | 84 +++ .../BootScriptExecutorDxe/X64/SetIdtEntry.c | 67 +++ 12 files changed, 1137 insertions(+) create mode 100644 MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm create mode 100644 MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c diff --git a/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h b/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h new file mode 100644 index 0000000000..420ccea255 --- /dev/null +++ b/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h @@ -0,0 +1,49 @@ +/** @file + Define Name, GUID and data format for an EFI Variable that is used to save the entry point + of a code segment which will be loaded and executed by a standalone boot script + executor on S3 boot path. + + Copyright (c) 2006 - 2010, 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. + +**/ + +#ifndef _BOOT_SCRIPT_EXECUTOR_VARIABLE_H_ +#define _BOOT_SCRIPT_EXECUTOR_VARIABLE_H_ + +#define EFI_BOOT_SCRIPT_EXECUTOR_VARIABLE_GUID \ + { \ + 0x3079818c, 0x46d4, 0x4a73, {0xae, 0xf3, 0xe3, 0xe4, 0x6c, 0xf1, 0xee, 0xdb} \ + } + +// +// The following structure boosts performance by combining structure all ACPI related variables into one. +// +#pragma pack(1) + +typedef struct { + EFI_PHYSICAL_ADDRESS BootScriptExecutorEntrypoint; +} BOOT_SCRIPT_EXECUTOR_VARIABLE; + +#pragma pack() + +#define BOOT_SCRIPT_EXECUTOR_VARIABLE_NAME L"BootScriptExecutorVariable" + +extern EFI_GUID gEfiBootScriptExecutorVariableGuid; + +#define EFI_BOOT_SCRIPT_EXECUTOR_CONTEXT_GUID \ + { \ + 0x79cb58c4, 0xac51, 0x442f, {0xaf, 0xd7, 0x98, 0xe4, 0x7d, 0x2e, 0x99, 0x8} \ + } + +extern EFI_GUID gEfiBootScriptExecutorContextGuid; + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 5207fb4903..746d6b33b5 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -198,6 +198,10 @@ ## Include/Guid/AcpiS3Context.h gEfiAcpiS3ContextGuid = { 0xef98d3a, 0x3e33, 0x497a, { 0xa4, 0x1, 0x77, 0xbe, 0x3e, 0xb7, 0x4f, 0x38 }} + ## Include/Guid/BootScriptExecutorVariable.h + gEfiBootScriptExecutorVariableGuid = { 0x3079818c, 0x46d4, 0x4a73, { 0xae, 0xf3, 0xe3, 0xe4, 0x6c, 0xf1, 0xee, 0xdb }} + gEfiBootScriptExecutorContextGuid = { 0x79cb58c4, 0xac51, 0x442f, { 0xaf, 0xd7, 0x98, 0xe4, 0x7d, 0x2e, 0x99, 0x8 }} + [Ppis] ## Include/Ppi/AtaController.h gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 859b2664f7..1a97ef29e0 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -87,6 +87,8 @@ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf + SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf + S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf [LibraryClasses.EBC.PEIM] IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf @@ -325,4 +327,5 @@ MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf + MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf new file mode 100644 index 0000000000..0869c9d775 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf @@ -0,0 +1,83 @@ +## @file +# Boot Script Executor Module +# +# This is a standalone Boot Script Executor. Standalone means it does not +# depends on any PEI or DXE service. +# +# Copyright (c) 2006 - 2010, 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BootScriptExecutorDxe + FILE_GUID = FA20568B-548B-4b2b-81EF-1BA08D4A3CEC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = BootScriptExecutorEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + ScriptExecute.h + ScriptExecute.c + +[Sources.X64] + X64/SetIdtEntry.c + X64/S3Asm.asm + X64/S3Asm.S + +[Sources.Ia32] + IA32/SetIdtEntry.c + IA32/S3Asm.asm + IA32/S3Asm.S + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + TimerLib + PcdLib + BaseMemoryLib + SmbusLib + UefiDriverEntryPoint + BaseLib + PciLib + IoLib + S3BootScriptLib + PeCoffLib + DxeServicesLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + CacheMaintenanceLib + PerformanceLib + UefiLib + DebugAgentLib + LockBoxLib + +[Guids] + gEfiBootScriptExecutorVariableGuid + gEfiBootScriptExecutorContextGuid + gPerformanceProtocolGuid + gEfiEventExitBootServicesGuid + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode + +[Depex] + gEfiLockBoxProtocolGuid + diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S new file mode 100644 index 0000000000..21516d5ad9 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S @@ -0,0 +1,66 @@ +## @file +# +# Copyright (c) 2010, 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. +# +## + +#----------------------------------------- +#VOID +#AsmTransferControl ( +# IN UINT32 S3WakingVector, +# IN UINT32 AcpiLowMemoryBase +# ); +#----------------------------------------- + +ASM_GLOBAL ASM_PFX(AsmTransferControl) +ASM_PFX(AsmTransferControl): + # S3WakingVector :DWORD + # AcpiLowMemoryBase :DWORD + pushl %ebp + movl %esp,%ebp + leal LABLE, %eax + pushl $0x28 # CS + pushl %eax + movl 8(%ebp),%ecx + shrdl $20,%ecx,%ebx + andl $0xf,%ecx + movw %cx,%bx + movl %ebx, jmp_addr + lret +LABLE: + .byte 0xb8,0x30,0 # mov ax, 30h as selector + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + movw %ax,%ss + movl %cr0, %eax # Get control register 0 + .byte 0x66 + .byte 0x83,0xe0,0xfe # and eax, 0fffffffeh ; Clear PE bit (bit #0) + .byte 0xf,0x22,0xc0 # mov cr0, eax ; Activate real mode + .byte 0xea # jmp far @jmp_addr +jmp_addr: + .long 0 + +ASM_GLOBAL ASM_PFX(AsmTransferControl32) +ASM_PFX(AsmTransferControl32): + jmp ASM_PFX(AsmTransferControl) + +# dummy +ASM_GLOBAL ASM_PFX(AsmTransferControl16) +ASM_PFX(AsmTransferControl16): +ASM_GLOBAL ASM_PFX(AsmFixAddress16) +ASM_PFX(AsmFixAddress16): + .long 0 +ASM_GLOBAL ASM_PFX(AsmJmpAddr32) +ASM_PFX(AsmJmpAddr32): + .long 0 + diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm new file mode 100644 index 0000000000..710546e114 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm @@ -0,0 +1,71 @@ +;; @file +; This is the assembly code for transferring to control to OS S3 waking vector +; for IA32 platform +; +; Copyright (c) 2006, 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. +; +;; + .586P + .model flat,C + .code + +EXTERNDEF AsmFixAddress16:DWORD +EXTERNDEF AsmJmpAddr32:DWORD + +;----------------------------------------- +;VOID +;AsmTransferControl ( +; IN UINT32 S3WakingVector, +; IN UINT32 AcpiLowMemoryBase +; ); +;----------------------------------------- + +AsmTransferControl PROC + ; S3WakingVector :DWORD + ; AcpiLowMemoryBase :DWORD + push ebp + mov ebp, esp + lea eax, @F + push 28h ; CS + push eax + mov ecx, [ebp + 8] + shrd ebx, ecx, 20 + and ecx, 0fh + mov bx, cx + mov @jmp_addr, ebx + retf +@@: + DB 0b8h, 30h, 0 ; mov ax, 30h as selector + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov eax, cr0 ; Get control register 0 + DB 66h + DB 83h, 0e0h, 0feh ; and eax, 0fffffffeh ; Clear PE bit (bit #0) + DB 0fh, 22h, 0c0h ; mov cr0, eax ; Activate real mode + DB 0eah ; jmp far @jmp_addr +@jmp_addr DD ? + +AsmTransferControl ENDP + +AsmTransferControl32 PROC + jmp AsmTransferControl +AsmTransferControl32 ENDP + +; dummy +AsmTransferControl16 PROC +AsmFixAddress16 DD ? +AsmJmpAddr32 DD ? +AsmTransferControl16 ENDP + + END \ No newline at end of file diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c new file mode 100644 index 0000000000..8221be6c87 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c @@ -0,0 +1,63 @@ +/** @file + Set a IDT entry for debug purpose + + Set a IDT entry for interrupt vector 3 for debug purpose for IA32 platform + +Copyright (c) 2006 - 2010, 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. + +**/ +#include "ScriptExecute.h" +// +// INTERRUPT_GATE_DESCRIPTOR and SetIdtEntry () are used to setup IDT to do debug +// + +#pragma pack(1) + +typedef struct { + UINT16 OffsetLow; + UINT16 SegmentSelector; + UINT16 Attributes; + UINT16 OffsetHigh; +} INTERRUPT_GATE_DESCRIPTOR; + +#define INTERRUPT_GATE_ATTRIBUTE 0x8e00 + +#pragma pack() +/** + Set a IDT entry for interrupt vector 3 for debug purpose. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + +**/ +VOID +SetIdtEntry ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ) +{ + INTERRUPT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR *IdtDescriptor; + UINTN S3DebugBuffer; + + // + // Restore IDT for debug + // + IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile); + IdtEntry = (INTERRUPT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (INTERRUPT_GATE_DESCRIPTOR))); + S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress); + + IdtEntry->OffsetLow = (UINT16)S3DebugBuffer; + IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();; + IdtEntry->Attributes = (UINT16)INTERRUPT_GATE_ATTRIBUTE; + IdtEntry->OffsetHigh = (UINT16)(S3DebugBuffer >> 16); + + AsmWriteIdtr (IdtDescriptor); +} + diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c new file mode 100644 index 0000000000..d4d2a93492 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c @@ -0,0 +1,477 @@ +/** @file + This is the code for Boot Script Executer module. + + This driver is dispatched by Dxe core and the driver will reload itself to ACPI NVS memory + in the entry point. The functionality is to interpret and restore the S3 boot script + +Copyright (c) 2006 - 2011, 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. + +**/ + +#include "ScriptExecute.h" + +EFI_PHYSICAL_ADDRESS mPerfDataMemAddress; +UINT64 mS3BootScriptEntryTick; +UINT64 mScriptStartTick; +UINT64 mScriptEndTick; + +EFI_GUID mBootScriptExecutorImageGuid = { + 0x9a8d3433, 0x9fe8, 0x42b6, 0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b +}; + +/** + The event callback is used to get the base address of boot performance data structure on + LegacyBoot event and ExitBootServices event. + + @param Event The event handle. + @param Context The event context. + +**/ +VOID +EFIAPI +OnBootEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN VarSize; + + VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + Status = gRT->GetVariable ( + L"PerfDataMemAddr", + &gPerformanceProtocolGuid, + NULL, + &VarSize, + &mPerfDataMemAddress + ); + if (EFI_ERROR (Status)) { + mPerfDataMemAddress = 0; + } +} + +/** + Record S3 Script execution time and adjust total S3 resume time for script running. +**/ +VOID +WriteToOsS3PerformanceData ( + VOID + ) +{ + UINT64 Ticker; + UINT64 StartValue; + UINT64 EndValue; + UINT64 Freq; + UINT64 ScriptExecuteTicks; + PERF_HEADER *PerfHeader; + PERF_DATA *PerfData; + + Ticker = GetPerformanceCounter (); + + PerfHeader = (PERF_HEADER *)(UINTN)mPerfDataMemAddress; + if (PerfHeader == NULL) { + return; + } + + Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); + Freq = DivU64x32 (Freq, 1000); + + if (EndValue >= StartValue) { + ScriptExecuteTicks = mScriptEndTick - mScriptStartTick; + PerfHeader->S3Resume += Ticker - mS3BootScriptEntryTick; + } else { + ScriptExecuteTicks = mScriptStartTick - mScriptEndTick; + PerfHeader->S3Resume += mS3BootScriptEntryTick - Ticker; + } + if (PerfHeader->S3EntryNum < PERF_PEI_ENTRY_MAX_NUM) { + PerfData = &PerfHeader->S3Entry[PerfHeader->S3EntryNum]; + PerfData->Duration = (UINT32) DivU64x32 (ScriptExecuteTicks, (UINT32) Freq);; + AsciiStrnCpy (PerfData->Token, "ScriptExec", PERF_TOKEN_LENGTH); + PerfHeader->S3EntryNum++; + } +} + +/** + 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; + + PERF_CODE ( + mS3BootScriptEntryTick = GetPerformanceCounter (); + ); + + // + // 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. + // + PERF_CODE ( + mScriptStartTick = GetPerformanceCounter (); + ); + Status = S3BootScriptExecute (); + PERF_CODE ( + mScriptEndTick = GetPerformanceCounter (); + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AsmWbinvd (); + + // + // 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)) ) { + CpuDeadLoop(); + return EFI_INVALID_PARAMETER; + } + + // + // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. + // + if (PeiS3ResumeState != 0) { + 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; + + // + // 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; + } + + PERF_CODE ( + WriteToOsS3PerformanceData (); + ); + + 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; +} +/** + Entrypoint of Boot script exector driver, this function will be executed in + normal boot phase and invoked by DXE dispatch. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. +**/ +EFI_STATUS +EFIAPI +BootScriptExecutorEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT8 *Buffer; + UINTN BufferSize; + UINTN Pages; + EFI_PHYSICAL_ADDRESS FfsBuffer; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; + EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer; + EFI_STATUS Status; + VOID *DevicePath; + EFI_HANDLE NewImageHandle; + + // + // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry + // point is loaded by DXE code which is the first time loaded. or else, it is already + // be reloaded be itself.This is a work-around + // + Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); + if (EFI_ERROR (Status)) { + + // + // This is the first-time loaded by DXE core. reload itself to NVS mem + // + // + // A workarouond: Here we install a dummy handle + // + NewImageHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &NewImageHandle, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + Status = GetSectionFromAnyFv ( + &gEfiCallerIdGuid, + EFI_SECTION_PE32, + 0, + (VOID **) &Buffer, + &BufferSize + ); + ImageContext.Handle = Buffer; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment); + FfsBuffer = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + Pages, + &FfsBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; + // + // Align buffer on section boundry + // + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + if (EFI_ERROR (Status)) { + gBS->FreePages (FfsBuffer, Pages); + return Status; + } + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + + if (EFI_ERROR (Status)) { + PeCoffLoaderUnloadImage (&ImageContext); + gBS->FreePages (FfsBuffer, Pages); + return Status; + } + // + // Flush the instruction cache so the image data is written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + gBS->FreePages (FfsBuffer, Pages); + return Status; + } + // + // Additional step for BootScript integrity + // Save BootScriptExecutor image + // + Status = SaveLockBox ( + &mBootScriptExecutorImageGuid, + (VOID *)(UINTN)ImageContext.ImageAddress, + (UINTN)ImageContext.ImageSize + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + } else { + // + // the entry point is invoked after reloading. following code only run in ACPI NVS + // + BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE); + + BootScriptExecutorBuffer = 0xFFFFFFFF; + Pages = EFI_SIZE_TO_PAGES(BufferSize); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + Pages, + &BootScriptExecutorBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer; + EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ; + + Status = SaveLockBox ( + &gEfiBootScriptExecutorVariableGuid, + &BootScriptExecutorBuffer, + sizeof(BootScriptExecutorBuffer) + ); + ASSERT_EFI_ERROR (Status); + + // + // Additional step for BootScript integrity + // Save BootScriptExecutor context + // + Status = SaveLockBox ( + &gEfiBootScriptExecutorContextGuid, + EfiBootScriptExecutorVariable, + sizeof(*EfiBootScriptExecutorVariable) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + PERF_CODE ( + EFI_EVENT Event; + + gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnBootEvent, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + + EfiCreateEventLegacyBootEx( + TPL_NOTIFY, + OnBootEvent, + NULL, + &Event + ); + ); + } + + return EFI_SUCCESS; +} + + + diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h new file mode 100644 index 0000000000..6a97b7790e --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h @@ -0,0 +1,88 @@ +/** @file + The header file for Boot Script Executer module. + + This driver is dispatched by Dxe core and the driver will reload itself to ACPI NVS memory + in the entry point. The functionality is to interpret and restore the S3 boot script + +Copyright (c) 2006 - 2011, 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. + +**/ +#ifndef _BOOT_SCRIPT_EXECUTOR_H_ +#define _BOOT_SCRIPT_EXECUTOR_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +/** + 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 +**/ +VOID +AsmTransferControl ( + IN UINT32 S3WakingVector, + IN UINT32 AcpiLowMemoryBase + ); +/** + a 32bit 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 +**/ +VOID +AsmTransferControl32 ( + IN UINT32 S3WakingVector, + IN UINT32 AcpiLowMemoryBase + ); +/** + a 16bit ASM function to transfer control to OS. +**/ +VOID +AsmTransferControl16 ( + VOID + ); +/** + Set a IDT entry for interrupt vector 3 for debug purpose. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + +**/ +VOID +SetIdtEntry ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ); + +extern UINT32 AsmFixAddress16; +extern UINT32 AsmJmpAddr32; + +#endif //_BOOT_SCRIPT_EXECUTOR_H_ diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S new file mode 100644 index 0000000000..7f5bdebfd2 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S @@ -0,0 +1,82 @@ +## @file +# This is the assembly code for transferring to control to OS S3 waking vector +# for X64 platform +# +# Copyright (c) 2006, 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. +# +## + +ASM_GLOBAL ASM_PFX(AsmTransferControl) +ASM_PFX(AsmTransferControl): + # rcx S3WakingVector :DWORD + # rdx AcpiLowMemoryBase :DWORD + lea _AsmTransferControl_al_0000, %eax + movq $0x2800000000, %r8 + orq %r8, %rax + pushq %rax + shrd $20, %ecx, %ebx + andl $0x0f, %ecx + movw %cx, %bx + movl %ebx, jmp_addr + lret +_AsmTransferControl_al_0000: + .byte 0x0b8, 0x30, 0 # mov ax, 30h as selector + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + movq %cr0, %rax + movq %cr4, %rbx + .byte 0x66 + andl $0x7ffffffe, %eax + andb $0xdf, %bl + movq %rax, %cr0 + .byte 0x66 + movl $0x0c0000080, %ecx + rdmsr + andb $0xfe, %ah + wrmsr + movq %rbx, %cr4 + .byte 0x0ea # jmp far jmp_addr +jmp_addr: + .long 0 + +ASM_GLOBAL ASM_PFX(AsmTransferControl32) +ASM_PFX(AsmTransferControl32): + # S3WakingVector :DWORD + # AcpiLowMemoryBase :DWORD + pushq %rbp + movl %esp,%ebp + .byte 0x8d, 0x05 # lea eax, AsmTransferControl16 +ASM_GLOBAL ASM_PFX(AsmFixAddress16) +ASM_PFX(AsmFixAddress16): + .long 0 + pushq $0x28 # CS + pushq %rax + lret + +ASM_GLOBAL ASM_PFX(AsmTransferControl16) +ASM_PFX(AsmTransferControl16): + .byte 0xb8,0x30,0 # mov ax, 30h as selector + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + movw %ax,%ss + movq %cr0, %rax # Get control register 0 + .byte 0x66 + .byte 0x83,0xe0,0xfe # and eax, 0fffffffeh ; Clear PE bit (bit #0) + .byte 0xf,0x22,0xc0 # mov cr0, eax ; Activate real mode + .byte 0xea # jmp far AsmJmpAddr32 +ASM_GLOBAL ASM_PFX(AsmJmpAddr32) +ASM_PFX(AsmJmpAddr32): + .long 0 diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm new file mode 100644 index 0000000000..f3d327df75 --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm @@ -0,0 +1,84 @@ +;; @file +; This is the assembly code for transferring to control to OS S3 waking vector +; for X64 platform +; +; Copyright (c) 2006, 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. +; +;; + + .code + +EXTERNDEF AsmFixAddress16:DWORD +EXTERNDEF AsmJmpAddr32:DWORD + +AsmTransferControl PROC + ; rcx S3WakingVector :DWORD + ; rdx AcpiLowMemoryBase :DWORD + lea eax, @F + mov r8, 2800000000h + or rax, r8 + push rax + shrd ebx, ecx, 20 + and ecx, 0fh + mov bx, cx + mov @jmp_addr, ebx + retf +@@: + DB 0b8h, 30h, 0 ; mov ax, 30h as selector + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + mov rax, cr0 + mov rbx, cr4 + DB 66h + and eax, ((NOT 080000001h) AND 0ffffffffh) + and bl, NOT (1 SHL 5) + mov cr0, rax + DB 66h + mov ecx, 0c0000080h + rdmsr + and ah, NOT 1 + wrmsr + mov cr4, rbx + DB 0eah ; jmp far @jmp_addr +@jmp_addr DD ? +AsmTransferControl ENDP + +AsmTransferControl32 PROC + ; S3WakingVector :DWORD + ; AcpiLowMemoryBase :DWORD + push rbp + mov ebp, esp + DB 8dh, 05h ; lea eax, AsmTransferControl16 +AsmFixAddress16 DD ? + push 28h ; CS + push rax + retf +AsmTransferControl32 ENDP + +AsmTransferControl16 PROC + DB 0b8h, 30h, 0 ; mov ax, 30h as selector + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov rax, cr0 ; Get control register 0 + DB 66h + DB 83h, 0e0h, 0feh ; and eax, 0fffffffeh ; Clear PE bit (bit #0) + DB 0fh, 22h, 0c0h ; mov cr0, eax ; Activate real mode + DB 0eah ; jmp far AsmJmpAddr32 +AsmJmpAddr32 DD ? +AsmTransferControl16 ENDP + + END diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c new file mode 100644 index 0000000000..f70f2f986f --- /dev/null +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c @@ -0,0 +1,67 @@ +/** @file + Set a IDT entry for debug purpose + + Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform + +Copyright (c) 2006 - 2010, 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. + +**/ +#include "ScriptExecute.h" +// +// INTERRUPT_GATE_DESCRIPTOR and SetIdtEntry () are used to setup IDT to do debug +// + +#pragma pack(1) + +typedef struct { + UINT16 Offset15To0; + UINT16 SegmentSelector; + UINT16 Attributes; + UINT16 Offset31To16; + UINT32 Offset63To32; + UINT32 Reserved; +} INTERRUPT_GATE_DESCRIPTOR; + +#define INTERRUPT_GATE_ATTRIBUTE 0x8e00 + +#pragma pack() +/** + Set a IDT entry for interrupt vector 3 for debug purpose. + + @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT + +**/ +VOID +SetIdtEntry ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ) +{ + INTERRUPT_GATE_DESCRIPTOR *IdtEntry; + IA32_DESCRIPTOR *IdtDescriptor; + UINTN S3DebugBuffer; + + // + // Restore IDT for debug + // + IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile); + IdtEntry = (INTERRUPT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (INTERRUPT_GATE_DESCRIPTOR))); + S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress); + + IdtEntry->Offset15To0 = (UINT16)S3DebugBuffer; + IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();; + IdtEntry->Attributes = (UINT16)INTERRUPT_GATE_ATTRIBUTE; + IdtEntry->Offset31To16 = (UINT16)(S3DebugBuffer >> 16); + IdtEntry->Offset63To32 = (UINT32)(S3DebugBuffer >> 32); + IdtEntry->Reserved = 0; + + AsmWriteIdtr (IdtDescriptor); +} +