summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Compatibility
diff options
context:
space:
mode:
authorjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>2010-12-22 04:26:08 +0000
committerjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>2010-12-22 04:26:08 +0000
commitd766b22843bc2304cdb834eedc486ea3f1dd3335 (patch)
treebcffab11f221e9fe5a6db611423a4e129d25aaff /EdkCompatibilityPkg/Compatibility
parent23228db3827140cea7be70a20bb62cbcd9636cd7 (diff)
downloadedk2-platforms-d766b22843bc2304cdb834eedc486ea3f1dd3335.tar.xz
Fix boot script thunk issue that we need dispatch in PEI mode for Framework dispatch function, not in DXE mode.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11189 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkCompatibilityPkg/Compatibility')
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf19
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c43
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c227
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h16
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S216
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm216
-rw-r--r--EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c106
-rw-r--r--EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h31
8 files changed, 858 insertions, 16 deletions
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
index 0683366e79..e449308d44 100644
--- a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
@@ -29,31 +29,46 @@
#
# The following information is for reference only and not required by the build tools.
#
-# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
ScriptSave.c
ScriptSave.h
+[Sources.X64]
+ X64/AsmDispatchExecute.asm
+ X64/AsmDispatchExecute.S
+ X64/DispatchExecute.c
+
+[Sources.Ia32]
+ IA32/DispatchExecute.c
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
MdeModulePkg/MdeModulePkg.dec
-
+ EdkCompatibilityPkg/EdkCompatibilityPkg.dec
[LibraryClasses]
UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
+ MemoryAllocationLib
DebugLib
BaseLib
+ PeCoffLib
+ PcdLib
+ DxeServicesLib
+ CacheMaintenanceLib
[Protocols]
gEfiBootScriptSaveProtocolGuid ## PRODUCES
gEfiS3SaveStateProtocolGuid ## CONSUMES
+[Pcd]
+ gEfiEdkCompatibilityPkgTokenSpaceGuid.BootScriptThunkDataPtr
[Depex]
gEfiS3SaveStateProtocolGuid
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c
new file mode 100644
index 0000000000..7a3c9143b6
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c
@@ -0,0 +1,43 @@
+/** @file
+ Execute 32-bit code in Long Mode
+ Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit
+ back to long mode.
+
+ 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.
+
+**/
+#include "ScriptSave.h"
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param Function The 32bit code entry to be executed.
+ @param Param1 The first parameter to pass to 32bit code
+ @param Param2 The second parameter to pass to 32bit code
+ @retval EFI_SUCCESS Execute 32bit code successfully.
+ @retval other Something wrong when execute the 32bit code
+
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ )
+{
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ EFI_STATUS Status;
+
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (Function);
+ Status = EntryFunc ((VOID *)(UINTN)Param1, (VOID *)(UINTN)Param2);
+
+ return Status;
+}
+
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c
index 45b741dcca..530f76591a 100644
--- a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c
@@ -20,6 +20,60 @@ EFI_BOOT_SCRIPT_SAVE_PROTOCOL mS3ScriptSave = {
BootScriptCloseTable
};
EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;
+
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param Function The 32bit code entry to be executed.
+ @param Param1 The first parameter to pass to 32bit code
+ @param Param2 The second parameter to pass to 32bit code
+ @retval EFI_SUCCESS Execute 32bit code successfully.
+ @retval other Something wrong when execute the 32bit code
+
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ );
+
+/**
+ A stub to convert framework boot script dispatch to PI boot script dispatch.
+
+ @param ImageHandle It should be is NULL.
+ @param Context The first parameter to pass to 32bit code
+
+ @return dispatch value.
+
+**/
+EFI_STATUS
+EFIAPI
+FrameworkBootScriptDispatchStub (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ VOID *PeiServices;
+ IA32_DESCRIPTOR Idtr;
+
+ DEBUG ((EFI_D_ERROR, "FrameworkBootScriptDispatchStub - 0x%08x\n", (UINTN)Context));
+
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (Context);
+ AsmReadIdtr (&Idtr);
+ PeiServices = (VOID *)(UINTN)(*(UINT32 *)(Idtr.Base - sizeof (UINT32)));
+
+ //
+ // ECP assumes first parameter is NULL, and second parameter is PeiServices.
+ //
+ Status = Execute32BitCode ((UINT64)(UINTN)EntryFunc, 0, (UINT64)(UINTN)PeiServices);
+
+ return Status;
+}
+
/**
Internal function to add IO write opcode to the table.
@@ -396,6 +450,42 @@ BootScriptDispatch (
}
/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE.
+ We ignore "Context" parameter.
+ We need create thunk stub to convert PEI entrypoint (used in Framework version)
+ to DXE entrypoint (defined in PI spec).
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+FrameworkBootScriptDispatch (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+ VOID *Context;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+
+ //
+ // Register callback
+ //
+ Context = EntryPoint;
+ EntryPoint = (VOID *)(UINTN)FrameworkBootScriptDispatchStub;
+ return mS3SaveState->Write (
+ mS3SaveState,
+ EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE,
+ EntryPoint,
+ Context
+ );
+}
+
+/**
Internal function to add memory pool operation to the table.
@param Marker The variable argument list to get the opcode
@@ -539,9 +629,9 @@ BootScriptWrite (
VA_LIST Marker;
if (TableName != FRAMEWORK_EFI_ACPI_S3_RESUME_SCRIPT_TABLE) {
- //
- // Only S3 boot script is supported for now
- //
+ //
+ // Only S3 boot script is supported for now
+ //
return EFI_OUT_OF_RESOURCES;
}
//
@@ -600,7 +690,7 @@ BootScriptWrite (
case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
VA_START (Marker, OpCode);
- Status = BootScriptDispatch (Marker);
+ Status = FrameworkBootScriptDispatch (Marker);
VA_END (Marker);
break;
@@ -705,24 +795,133 @@ InitializeScriptSaveOnS3SaveState (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
- EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ VOID *FfsBuffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData;
+ EFI_STATUS Status;
+ VOID *DevicePath;
+
//
- // Locate and cache PI S3 Save State Protocol.
+ // 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 (
- &gEfiS3SaveStateProtocolGuid,
- NULL,
- (VOID **) &mS3SaveState
- );
- ASSERT_EFI_ERROR (Status);
+ 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
+ //
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ DevicePath
+ );
+
+ 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;
+ }
+ Status = gBS->AllocatePool (
+ EfiACPIMemoryNVS,
+ BufferSize + ImageContext.SectionAlignment,
+ &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->FreePool (FfsBuffer);
+ return Status;
+ }
- return gBS->InstallProtocolInterface (
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+
+ if (EFI_ERROR (Status)) {
+ PeCoffLoaderUnloadImage (&ImageContext);
+ gBS->FreePool (FfsBuffer);
+ 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)) ((EFI_HANDLE)(UINTN)(ImageContext.ImageAddress), SystemTable);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (FfsBuffer);
+ return Status;
+ }
+ //
+ // Additional step for BootScriptThunk integrity
+ //
+
+ //
+ // Allocate BootScriptThunkData
+ //
+ BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA));
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BootScriptThunkData->BootScriptThunkBase = ImageContext.ImageAddress;
+ BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize;
+ //
+ // Set BootScriptThunkData
+ //
+ PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // the entry point is invoked after reloading. following code only run in ACPI NVS
+ //
+
+ //
+ // Locate and cache PI S3 Save State Protocol.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiS3SaveStateProtocolGuid,
+ NULL,
+ (VOID **) &mS3SaveState
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return gBS->InstallProtocolInterface (
&mHandle,
&gEfiBootScriptSaveProtocolGuid,
EFI_NATIVE_INTERFACE,
&mS3ScriptSave
);
-
+ }
}
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h
index a5a6b4d9e4..b98e83a214 100644
--- a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h
@@ -21,9 +21,25 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/SmbusLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/CacheMaintenanceLib.h>
+
+#include <Guid/BootScriptThunkData.h>
+
#include <IndustryStandard/SmBus.h>
+typedef
+EFI_STATUS
+(EFIAPI *DISPATCH_ENTRYPOINT_FUNC) (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Context
+ );
+
/**
Adds a record into a specified Framework boot script table.
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S
new file mode 100644
index 0000000000..798baca96d
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S
@@ -0,0 +1,216 @@
+#
+# 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.
+#
+#
+# Module Name:
+#
+# AsmDispatchExecute.asm
+#
+# Abstract:
+#
+# This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
+# transit back to long mode.
+#
+#-------------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Procedure: AsmExecute32BitCode
+#
+# Input: None
+#
+# Output: None
+#
+# Prototype: EFI_STATUS
+# AsmExecute32BitCode (
+# IN UINT64 Function,
+# IN UINT64 Param1,
+# IN UINT64 Param2,
+# IN IA32_DESCRIPTOR *InternalGdtr
+# );
+#
+#
+# Description: A thunk function to execute 32-bit code in long mode.
+#
+#----------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)
+ASM_PFX(AsmExecute32BitCode):
+ #
+ # save orignal GDTR and CS
+ #
+ movq %ds, %rax
+ push %rax
+ movq %cs, %rax
+ push %rax
+ subq $0x10, %rsp
+ sgdt (%rsp)
+ #
+ # load internal GDT
+ #
+ lgdt (%r9)
+ #
+ # Save general purpose register and rflag register
+ #
+ pushfq
+ push %rdi
+ push %rsi
+ push %rbp
+ push %rbx
+
+ #
+ # save CR3
+ #
+ movq %cr3, %rax
+ movq %rax, %rbp
+
+ #
+ # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
+ #
+ movq $0x10, %rax # load long mode selector
+ shl $32, %rax
+ lea ReloadCS(%rip), %r9 #Assume the ReloadCS is under 4G
+ orq %r9, %rax
+ push %rax
+ #
+ # Save parameters for 32-bit function call
+ #
+ movq %r8, %rax
+ shl $32, %rax
+ orq %rdx, %rax
+ push %rax
+ #
+ # save the 32-bit function entry and the return address into stack which will be
+ # retrieve in compatibility mode.
+ #
+ lea ReturnBack(%rip), %rax #Assume the ReloadCS is under 4G
+ shl $32, %rax
+ orq %rcx, %rax
+ push %rax
+
+ #
+ # let rax save DS
+ #
+ movq $0x18, %rax
+
+ #
+ # Change to Compatible Segment
+ #
+ movq $8, %rcx # load compatible mode selector
+ shl $32, %rcx
+ lea Compatible(%rip), %rdx # assume address < 4G
+ orq %rdx, %rcx
+ push %rcx
+ retf
+
+Compatible:
+ # reload DS/ES/SS to make sure they are correct referred to current GDT
+ movs %ax, %ds
+ movs %ax, %es
+ movs %ax, %ss
+
+ #
+ # Disable paging
+ #
+ movq %cr0, %rcx
+ btc $31, %ecx
+ movq %rcx, %cr0
+ #
+ # Clear EFER.LME
+ #
+ movl $0xC0000080, %ecx
+ rdmsr
+ btc $8, %eax
+ wrmsr
+
+# Now we are in protected mode
+ #
+ # Call 32-bit function. Assume the function entry address and parameter value is less than 4G
+ #
+ pop %rax # Here is the function entry
+ #
+ # Now the parameter is at the bottom of the stack, then call in to IA32 function.
+ #
+ jmp *%rax
+ReturnBack:
+ pop %rcx # drop param1
+ pop %rcx # drop param2
+
+ #
+ # restore CR4
+ #
+ movq %cr4, %rax
+ bts $5, %eax
+ movq %rax, %cr4
+
+ #
+ # restore CR3
+ #
+ movl %ebp, %eax
+ movq %rax, %cr3
+
+ #
+ # Set EFER.LME to re-enable ia32-e
+ #
+ movl $0xC0000080, %ecx
+ rdmsr
+ bts $8, %eax
+ wrmsr
+ #
+ # Enable paging
+ #
+ movq %cr0, %rax
+ bts $31, %eax
+ mov %rax, %cr0
+# Now we are in compatible mode
+
+ #
+ # Reload cs register
+ #
+ retf
+ReloadCS:
+ #
+ # Now we're in Long Mode
+ #
+ #
+ # Restore C register and eax hold the return status from 32-bit function.
+ # Note: Do not touch rax from now which hold the return value from IA32 function
+ #
+ pop %rbx
+ pop %rbp
+ pop %rsi
+ pop %rdi
+ popfq
+ #
+ # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
+ #
+ lgdt (%rsp)
+ #
+ # drop GDT descriptor in stack
+ #
+ addq $0x10, %rsp
+ #
+ # switch to orignal CS and GDTR
+ #
+ pop %r9 # get CS
+ shl $32, %r9 # rcx[32..47] <- Cs
+ lea @F(%rip), %rcx
+ orq %r9, %rcx
+ push %rcx
+ retf
+@@:
+ #
+ # Reload original DS/ES/SS
+ #
+ pop %rcx
+ movq %rcx, %ds
+ movq %rcx, %es
+ movq %rcx, %ss
+ ret
+
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm
new file mode 100644
index 0000000000..2d5d92056e
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm
@@ -0,0 +1,216 @@
+;
+; 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.
+;
+;
+; Module Name:
+;
+; AsmDispatchExecute.asm
+;
+; Abstract:
+;
+; This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
+; transit back to long mode.
+;
+;-------------------------------------------------------------------------------
+ .code
+;----------------------------------------------------------------------------
+; Procedure: AsmExecute32BitCode
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: EFI_STATUS
+; AsmExecute32BitCode (
+; IN UINT64 Function,
+; IN UINT64 Param1,
+; IN UINT64 Param2,
+; IN IA32_DESCRIPTOR *InternalGdtr
+; );
+;
+;
+; Description: A thunk function to execute 32-bit code in long mode.
+;
+;----------------------------------------------------------------------------
+AsmExecute32BitCode PROC
+ ;
+ ; save orignal GDTR and CS
+ ;
+ mov rax, ds
+ push rax
+ mov rax, cs
+ push rax
+ sub rsp, 10h
+ sgdt fword ptr [rsp]
+ ;
+ ; load internal GDT
+ ;
+ lgdt fword ptr [r9]
+ ;
+ ; Save general purpose register and rflag register
+ ;
+ pushfq
+ push rdi
+ push rsi
+ push rbp
+ push rbx
+
+ ;
+ ; save CR3
+ ;
+ mov rax, cr3
+ mov rbp, rax
+
+ ;
+ ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode
+ ;
+ mov rax, 10h ; load long mode selector
+ shl rax, 32
+ mov r9, OFFSET ReloadCS ;Assume the ReloadCS is under 4G
+ or rax, r9
+ push rax
+ ;
+ ; Save parameters for 32-bit function call
+ ;
+ mov rax, r8
+ shl rax, 32
+ or rax, rdx
+ push rax
+ ;
+ ; save the 32-bit function entry and the return address into stack which will be
+ ; retrieve in compatibility mode.
+ ;
+ mov rax, OFFSET ReturnBack ;Assume the ReloadCS is under 4G
+ shl rax, 32
+ or rax, rcx
+ push rax
+
+ ;
+ ; let rax save DS
+ ;
+ mov rax, 018h
+
+ ;
+ ; Change to Compatible Segment
+ ;
+ mov rcx, 08h ; load compatible mode selector
+ shl rcx, 32
+ mov rdx, OFFSET Compatible ; assume address < 4G
+ or rcx, rdx
+ push rcx
+ retf
+
+Compatible:
+ ; reload DS/ES/SS to make sure they are correct referred to current GDT
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ ;
+ ; Disable paging
+ ;
+ mov rcx, cr0
+ btc ecx, 31
+ mov cr0, rcx
+ ;
+ ; Clear EFER.LME
+ ;
+ mov ecx, 0C0000080h
+ rdmsr
+ btc eax, 8
+ wrmsr
+
+; Now we are in protected mode
+ ;
+ ; Call 32-bit function. Assume the function entry address and parameter value is less than 4G
+ ;
+ pop rax ; Here is the function entry
+ ;
+ ; Now the parameter is at the bottom of the stack, then call in to IA32 function.
+ ;
+ jmp rax
+ReturnBack:
+ pop rcx ; drop param1
+ pop rcx ; drop param2
+
+ ;
+ ; restore CR4
+ ;
+ mov rax, cr4
+ bts eax, 5
+ mov cr4, rax
+
+ ;
+ ; restore CR3
+ ;
+ mov eax, ebp
+ mov cr3, rax
+
+ ;
+ ; Set EFER.LME to re-enable ia32-e
+ ;
+ mov ecx, 0C0000080h
+ rdmsr
+ bts eax, 8
+ wrmsr
+ ;
+ ; Enable paging
+ ;
+ mov rax, cr0
+ bts eax, 31
+ mov cr0, rax
+; Now we are in compatible mode
+
+ ;
+ ; Reload cs register
+ ;
+ retf
+ReloadCS:
+ ;
+ ; Now we're in Long Mode
+ ;
+ ;
+ ; Restore C register and eax hold the return status from 32-bit function.
+ ; Note: Do not touch rax from now which hold the return value from IA32 function
+ ;
+ pop rbx
+ pop rbp
+ pop rsi
+ pop rdi
+ popfq
+ ;
+ ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
+ ;
+ lgdt fword ptr[rsp]
+ ;
+ ; drop GDT descriptor in stack
+ ;
+ add rsp, 10h
+ ;
+ ; switch to orignal CS and GDTR
+ ;
+ pop r9 ; get CS
+ shl r9, 32 ; rcx[32..47] <- Cs
+ mov rcx, OFFSET @F
+ or rcx, r9
+ push rcx
+ retf
+@@:
+ ;
+ ; Reload original DS/ES/SS
+ ;
+ pop rcx
+ mov ds, rcx
+ mov es, rcx
+ mov ss, rcx
+ ret
+AsmExecute32BitCode ENDP
+
+ END
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c
new file mode 100644
index 0000000000..8ef4299901
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c
@@ -0,0 +1,106 @@
+/** @file
+ Execute 32-bit code in Long Mode
+ Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit
+ back to long mode.
+
+ 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.
+
+**/
+#include "ScriptSave.h"
+
+#pragma pack(1)
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+#pragma pack()
+
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x0: reserve */
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x8: compatibility mode */
+ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}}, /* 0x10: for long mode */
+ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}}, /* 0x18: data */
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, /* 0x20: reserve */
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+/**
+ Assembly function to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+ @param Function The 32bit code entry to be executed.
+ @param Param1 The first parameter to pass to 32bit code
+ @param Param2 The second parameter to pass to 32bit code
+ @param InternalGdtr The GDT and GDT descriptor used by this library
+
+ @retval EFI_SUCCESS Execute 32bit code successfully.
+ @retval other Something wrong when execute the 32bit code
+**/
+EFI_STATUS
+AsmExecute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2,
+ IN IA32_DESCRIPTOR *InternalGdtr
+ );
+
+/**
+ Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
+ long mode.
+
+ @param Function The 32bit code entry to be executed.
+ @param Param1 The first parameter to pass to 32bit code
+ @param Param2 The second parameter to pass to 32bit code
+ @retval EFI_SUCCESS Execute 32bit code successfully.
+ @retval other Something wrong when execute the 32bit code
+
+**/
+EFI_STATUS
+Execute32BitCode (
+ IN UINT64 Function,
+ IN UINT64 Param1,
+ IN UINT64 Param2
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Function != 0);
+
+ Status = AsmExecute32BitCode (
+ Function,
+ Param1,
+ Param2,
+ &mGdt
+ );
+ return Status;
+}
+
diff --git a/EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h b/EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h
new file mode 100644
index 0000000000..f0e6f5fee3
--- /dev/null
+++ b/EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h
@@ -0,0 +1,31 @@
+/** @file
+ Define Name, GUID and data format for an EFI PCD that is used to save the image base and size
+ of a code segment which will be loaded and executed by a boot script thunk on S3 boot path.
+
+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.
+
+**/
+
+#ifndef _BOOT_SCRIPT_THUNK_VARIABLE_H_
+#define _BOOT_SCRIPT_THUNK_VARIABLE_H_
+
+//
+// The following structure boosts performance by combining structure all ACPI related variables into one.
+//
+#pragma pack(1)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BootScriptThunkBase;
+ EFI_PHYSICAL_ADDRESS BootScriptThunkLength;
+} BOOT_SCRIPT_THUNK_DATA;
+
+#pragma pack()
+
+#endif