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
This commit is contained in:
jljusten 2011-08-29 22:18:19 +00:00
parent 64d14edfeb
commit be46cd5f85
12 changed files with 1137 additions and 0 deletions

View File

@ -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.<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_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

View File

@ -198,6 +198,10 @@
## Include/Guid/AcpiS3Context.h ## Include/Guid/AcpiS3Context.h
gEfiAcpiS3ContextGuid = { 0xef98d3a, 0x3e33, 0x497a, { 0xa4, 0x1, 0x77, 0xbe, 0x3e, 0xb7, 0x4f, 0x38 }} 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] [Ppis]
## Include/Ppi/AtaController.h ## Include/Ppi/AtaController.h
gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }} gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }}

View File

@ -87,6 +87,8 @@
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf
S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
[LibraryClasses.EBC.PEIM] [LibraryClasses.EBC.PEIM]
IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
@ -325,4 +327,5 @@
MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf
MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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);
}