diff options
Diffstat (limited to 'MdeModulePkg/Universal/Acpi')
9 files changed, 1081 insertions, 0 deletions
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.<BR>
+#
+# 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.<BR>
+#
+# 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.<BR>
+;
+; 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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+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 <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/LockBoxLib.h>
+
+#include <Guid/AcpiS3Context.h>
+#include <Guid/BootScriptExecutorVariable.h>
+#include <Guid/EventGroup.h>
+#include <Guid/Performance.h>
+#include <IndustryStandard/Acpi.h>
+/**
+ 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.<BR>
+#
+# 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.<BR>
+;
+; 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.<BR>
+
+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);
+}
+
|