diff options
author | vanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-04-13 07:11:03 +0000 |
---|---|---|
committer | vanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-04-13 07:11:03 +0000 |
commit | bf41aa2b4a17f98339610d7d0697349d3f49b599 (patch) | |
tree | 73f3947c00d3db0e8d4f3d05c1dc3a4b5a009c02 | |
parent | c3aac4b5adab43ba587a518899bd035d30d94a73 (diff) | |
download | edk2-bf41aa2b4a17f98339610d7d0697349d3f49b599.tar.gz |
sync patch r11189, r11194, r11200, r11201, r11020, r11227 from main trunk.
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/branches/UDK2010@11535 6f19259b-4bc3-4df7-8a09-765794883524
10 files changed, 873 insertions, 19 deletions
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf index ca72cf0eab..dab9c601fc 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 de4f38ff6c..3a3b8c8be5 100644 --- a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c +++ b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c @@ -2,8 +2,8 @@ Implementation for S3 Boot Script Save thunk driver.
This thunk driver consumes PI S3SaveState protocol to produce framework S3BootScriptSave Protocol
- Copyright (c) 2010 Intel Corporation
- All rights reserved. This program and the accompanying materials
+ Copyright (c) 2010 - 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
@@ -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,140 @@ InitializeScriptSaveOnS3SaveState ( IN EFI_SYSTEM_TABLE *SystemTable
)
{
- EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData;
+ EFI_STATUS Status;
+ VOID *DevicePath;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ UINTN PageNumber;
+ EFI_HANDLE NewImageHandle;
+
//
- // 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
+ //
+ 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;
+ }
+
+ MemoryAddress = SIZE_4GB - 1;
+ PageNumber = EFI_SIZE_TO_PAGES (BufferSize + ImageContext.SectionAlignment);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ PageNumber,
+ &MemoryAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
+ //
+ // 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 (MemoryAddress, PageNumber);
+ return Status;
+ }
- return gBS->InstallProtocolInterface (
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+
+ if (EFI_ERROR (Status)) {
+ PeCoffLoaderUnloadImage (&ImageContext);
+ gBS->FreePages (MemoryAddress, PageNumber);
+ 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 (MemoryAddress, PageNumber);
+ return Status;
+ }
+ //
+ // Additional step for BootScriptThunk integrity
+ //
+
+ //
+ // Allocate BootScriptThunkData
+ //
+ BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA));
+ if (BootScriptThunkData == NULL) {
+ 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 3eaaafcfc1..16ed0293fc 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..167e7d4cc1 --- /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
+ .byte 0xcb # retf
+
+Compatible:
+ # reload DS/ES/SS to make sure they are correct referred to current GDT
+ movw %ax, %ds
+ movw %ax, %es
+ movw %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
+ #
+ .byte 0xcb # 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 ReturnToLongMode(%rip), %rcx
+ orq %r9, %rcx
+ push %rcx
+ .byte 0xcb # retf
+ReturnToLongMode:
+ #
+ # 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
diff --git a/EdkCompatibilityPkg/EdkCompatibilityPkg.dec b/EdkCompatibilityPkg/EdkCompatibilityPkg.dec index a0f1127949..be7e79b6f1 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dec +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dec @@ -58,6 +58,7 @@ [Guids]
gEfiSmmBaseThunkCommunicationGuid = { 0x6568a3d6, 0x15f, 0x4b4a, { 0x9c, 0x89, 0x1d, 0x14, 0x63, 0x14, 0x13, 0xa } }
gEfiBootStateGuid = { 0x60b5e939, 0xfcf, 0x4227, { 0xba, 0x83, 0x6b, 0xbe, 0xd4, 0x5b, 0xc0, 0xe3 } }
+ gEfiEdkCompatibilityPkgTokenSpaceGuid = { 0x2354d320, 0x3eb3, 0x4c81, { 0x99, 0xf4, 0xcc, 0x4a, 0xe1, 0x43, 0x46, 0x3e }}
[Ppis]
gEcpPeiPciCfgPpiGuid = { 0xb0ee53d4, 0xa049, 0x4a79, { 0xb2, 0xff, 0x19, 0xd9, 0xfa, 0xef, 0xaa, 0x94 }}
@@ -66,3 +67,6 @@ gEfiPrintProtocolGuid = { 0xdf2d868e, 0x32fc, 0x4cf0, {0x8e, 0x6b, 0xff, 0xd9, 0x5d, 0x13, 0x43, 0xd0} }
gEfiSmmBaseHelperReadyProtocolGuid = { 0x910dca07, 0x1f94, 0x4ee7, { 0xaf, 0x2f, 0xff, 0x72, 0xf3, 0x15, 0x43, 0x53 } }
+[PcdsDynamic]
+ gEfiEdkCompatibilityPkgTokenSpaceGuid.BootScriptThunkDataPtr|0x0|UINT64|0x30000001
+
diff --git a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc index 11372476be..dfce92fde4 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc @@ -70,6 +70,7 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
[LibraryClasses.common.PEIM]
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
@@ -258,7 +259,6 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S EdkCompatibilityPkg/Compatibility/LegacyRegion2OnLegacyRegionThunk/LegacyRegion2OnLegacyRegionThunk.inf
EdkCompatibilityPkg/Compatibility/PiSmbiosRecordOnDataHubSmbiosRecordThunk/PiSmbiosRecordOnDataHubSmbiosRecordThunk.inf
EdkCompatibilityPkg/Compatibility/CpuIo2OnCpuIoThunk/CpuIo2OnCpuIoThunk.inf
- EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
#
# User needs to turn on the compatibility switches for VFRC and EDK II build tool for Framework HII modules
@@ -286,6 +286,7 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S EdkCompatibilityPkg/Compatibility/SmmAccess2OnSmmAccessThunk/SmmAccess2OnSmmAccessThunk.inf
EdkCompatibilityPkg/Compatibility/SmmControl2OnSmmControlThunk/SmmControl2OnSmmControlThunk.inf
EdkCompatibilityPkg/Compatibility/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk.inf
+ EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
[Components.IPF]
EdkCompatibilityPkg/Foundation/Cpu/Itanium/CpuIa64Lib/CpuIA64Lib.inf
|