From d766b22843bc2304cdb834eedc486ea3f1dd3335 Mon Sep 17 00:00:00 2001 From: jyao1 Date: Wed, 22 Dec 2010 04:26:08 +0000 Subject: [PATCH] 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 --- .../BootScriptSaveOnS3SaveStateThunk.inf | 19 +- .../IA32/DispatchExecute.c | 43 ++++ .../ScriptSave.c | 231 ++++++++++++++++-- .../ScriptSave.h | 16 ++ .../X64/AsmDispatchExecute.S | 216 ++++++++++++++++ .../X64/AsmDispatchExecute.asm | 216 ++++++++++++++++ .../X64/DispatchExecute.c | 106 ++++++++ .../Include/Guid/BootScriptThunkData.h | 31 +++ EdkCompatibilityPkg/EdkCompatibilityPkg.dsc | 3 +- 9 files changed, 862 insertions(+), 19 deletions(-) create mode 100644 EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c create mode 100644 EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S create mode 100644 EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm create mode 100644 EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c create mode 100644 EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h 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.
+ 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. @@ -395,6 +449,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. @@ -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; - // - // Locate and cache PI S3 Save State Protocol. - // - Status = gBS->LocateProtocol ( - &gEfiS3SaveStateProtocolGuid, - NULL, - (VOID **) &mS3SaveState - ); - ASSERT_EFI_ERROR (Status); + UINT8 *Buffer; + UINTN BufferSize; + VOID *FfsBuffer; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData; + EFI_STATUS Status; + VOID *DevicePath; - return gBS->InstallProtocolInterface ( + // + // 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 + // + 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; + } + + // + // 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 #include #include +#include #include +#include +#include +#include +#include +#include + +#include + #include +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.
+# 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.
+; 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.
+ 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.
+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.dsc b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc index 7c616b75b1..f148ded6eb 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc @@ -69,6 +69,7 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf [LibraryClasses.common.PEIM] MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf @@ -256,7 +257,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 @@ -285,6 +285,7 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S EdkCompatibilityPkg/Compatibility/SmmControl2OnSmmControlThunk/SmmControl2OnSmmControlThunk.inf EdkCompatibilityPkg/Compatibility/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk.inf EdkCompatibilityPkg/Compatibility/FrameworkSmmStatusCodeOnPiSmmStatusCodeThunk/FrameworkSmmStatusCodeOnPiSmmStatusCodeThunk.inf + EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf [Components.IPF] EdkCompatibilityPkg/Foundation/Cpu/Itanium/CpuIa64Lib/CpuIA64Lib.inf