]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Fix boot script thunk issue that we need dispatch in PEI mode for Framework dispatch...
authorjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 22 Dec 2010 04:26:08 +0000 (04:26 +0000)
committerjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 22 Dec 2010 04:26:08 +0000 (04:26 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11189 6f19259b-4bc3-4df7-8a09-765794883524

EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.h
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h [new file with mode: 0644]
EdkCompatibilityPkg/EdkCompatibilityPkg.dsc

index 0683366e79e14511d7db5fc138d170a7f70dd13f..e449308d4462b5c17dc77ee0cf109c6b02b7a1ab 100644 (file)
 #\r
 # The following information is for reference only and not required by the build tools.\r
 #\r
-#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
 #\r
 \r
 [Sources]\r
   ScriptSave.c\r
   ScriptSave.h\r
 \r
+[Sources.X64]\r
+  X64/AsmDispatchExecute.asm\r
+  X64/AsmDispatchExecute.S\r
+  X64/DispatchExecute.c\r
+\r
+[Sources.Ia32]  \r
+  IA32/DispatchExecute.c\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
   IntelFrameworkPkg/IntelFrameworkPkg.dec\r
   MdeModulePkg/MdeModulePkg.dec\r
-\r
+  EdkCompatibilityPkg/EdkCompatibilityPkg.dec\r
 \r
 [LibraryClasses]\r
   UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
   UefiDriverEntryPoint\r
   BaseMemoryLib\r
+  MemoryAllocationLib\r
   DebugLib\r
   BaseLib\r
+  PeCoffLib\r
+  PcdLib\r
+  DxeServicesLib\r
+  CacheMaintenanceLib\r
 \r
 [Protocols]\r
   gEfiBootScriptSaveProtocolGuid          ## PRODUCES\r
   gEfiS3SaveStateProtocolGuid             ## CONSUMES\r
 \r
+[Pcd]\r
+  gEfiEdkCompatibilityPkgTokenSpaceGuid.BootScriptThunkDataPtr\r
 \r
 [Depex]\r
   gEfiS3SaveStateProtocolGuid\r
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/IA32/DispatchExecute.c
new file mode 100644 (file)
index 0000000..7a3c914
--- /dev/null
@@ -0,0 +1,43 @@
+/** @file\r
+  Execute 32-bit code in Long Mode\r
+  Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit\r
+  back to long mode.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "ScriptSave.h"\r
+/**\r
+  Wrapper for a thunk  to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+  long mode.\r
+  \r
+  @param  Function     The 32bit code entry to be executed.\r
+  @param  Param1       The first parameter to pass to 32bit code\r
+  @param  Param2       The second parameter to pass to 32bit code\r
+  @retval EFI_SUCCESS  Execute 32bit code successfully.\r
+  @retval other        Something wrong when execute the 32bit code \r
+              \r
+**/  \r
+EFI_STATUS\r
+Execute32BitCode (\r
+  IN UINT64      Function,\r
+  IN UINT64      Param1,\r
+  IN UINT64      Param2\r
+  )\r
+{\r
+  DISPATCH_ENTRYPOINT_FUNC  EntryFunc;\r
+  EFI_STATUS                 Status;\r
+\r
+  EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (Function);\r
+  Status    = EntryFunc ((VOID *)(UINTN)Param1, (VOID *)(UINTN)Param2);\r
+\r
+  return Status;\r
+}\r
+\r
index 45b741dccadd65309ac83bdd6e858178ba4b90e4..530f76591aea67da5865d875bbc96eef128916ea 100644 (file)
@@ -20,6 +20,60 @@ EFI_BOOT_SCRIPT_SAVE_PROTOCOL mS3ScriptSave = {
                                   BootScriptCloseTable\r
                                  };\r
 EFI_S3_SAVE_STATE_PROTOCOL    *mS3SaveState;\r
+\r
+/**\r
+  Wrapper for a thunk  to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+  long mode.\r
+  \r
+  @param  Function     The 32bit code entry to be executed.\r
+  @param  Param1       The first parameter to pass to 32bit code\r
+  @param  Param2       The second parameter to pass to 32bit code\r
+  @retval EFI_SUCCESS  Execute 32bit code successfully.\r
+  @retval other        Something wrong when execute the 32bit code \r
+              \r
+**/  \r
+EFI_STATUS\r
+Execute32BitCode (\r
+  IN UINT64      Function,\r
+  IN UINT64      Param1,\r
+  IN UINT64      Param2\r
+  );\r
+\r
+/**\r
+  A stub to convert framework boot script dispatch to PI boot script dispatch.\r
+  \r
+  @param  ImageHandle  It should be is NULL.\r
+  @param  Context      The first parameter to pass to 32bit code\r
+\r
+  @return dispatch value.\r
+              \r
+**/  \r
+EFI_STATUS\r
+EFIAPI\r
+FrameworkBootScriptDispatchStub (\r
+  IN EFI_HANDLE ImageHandle,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  DISPATCH_ENTRYPOINT_FUNC  EntryFunc;\r
+  VOID                      *PeiServices;\r
+  IA32_DESCRIPTOR           Idtr;\r
+\r
+  DEBUG ((EFI_D_ERROR, "FrameworkBootScriptDispatchStub - 0x%08x\n", (UINTN)Context));\r
+\r
+  EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (Context);\r
+  AsmReadIdtr (&Idtr);\r
+  PeiServices = (VOID *)(UINTN)(*(UINT32 *)(Idtr.Base - sizeof (UINT32)));\r
+\r
+  //\r
+  // ECP assumes first parameter is NULL, and second parameter is PeiServices.\r
+  //\r
+  Status = Execute32BitCode ((UINT64)(UINTN)EntryFunc, 0, (UINT64)(UINTN)PeiServices);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Internal function to add IO write opcode to the table.\r
 \r
@@ -395,6 +449,42 @@ BootScriptDispatch (
                          );\r
 }\r
 \r
+/**\r
+  Internal function to add Save jmp address according to DISPATCH_OPCODE. \r
+  We ignore "Context" parameter.\r
+  We need create thunk stub to convert PEI entrypoint (used in Framework version)\r
+  to DXE entrypoint (defined in PI spec).\r
+\r
+  @param  Marker                The variable argument list to get the opcode\r
+                                and associated attributes.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource to do operation.\r
+  @retval EFI_SUCCESS           Opcode is added.\r
+\r
+**/\r
+EFI_STATUS\r
+FrameworkBootScriptDispatch (\r
+  IN VA_LIST                       Marker\r
+  )\r
+{\r
+  VOID           *EntryPoint;\r
+  VOID           *Context;\r
+\r
+  EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);\r
+\r
+  //\r
+  // Register callback\r
+  //\r
+  Context    = EntryPoint;\r
+  EntryPoint = (VOID *)(UINTN)FrameworkBootScriptDispatchStub;\r
+  return mS3SaveState->Write (\r
+                         mS3SaveState,\r
+                         EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE,\r
+                         EntryPoint,\r
+                         Context\r
+                         );\r
+}\r
+\r
 /**\r
   Internal function to add memory pool operation to the table. \r
  \r
@@ -539,9 +629,9 @@ BootScriptWrite (
   VA_LIST                   Marker;\r
   \r
   if (TableName != FRAMEWORK_EFI_ACPI_S3_RESUME_SCRIPT_TABLE) {\r
-       //\r
-       // Only S3 boot script is supported for now\r
-       //\r
+    //\r
+    // Only S3 boot script is supported for now\r
+    //\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   //\r
@@ -600,7 +690,7 @@ BootScriptWrite (
 \r
   case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:\r
     VA_START (Marker, OpCode);\r
-    Status = BootScriptDispatch (Marker);\r
+    Status = FrameworkBootScriptDispatch (Marker);\r
     VA_END (Marker);\r
     break;\r
 \r
@@ -705,24 +795,133 @@ InitializeScriptSaveOnS3SaveState (
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\r
-   EFI_STATUS                Status;\r
+  UINT8                                         *Buffer;\r
+  UINTN                                         BufferSize;\r
+  VOID                                          *FfsBuffer;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;\r
+  BOOT_SCRIPT_THUNK_DATA                        *BootScriptThunkData;\r
+  EFI_STATUS                                    Status;\r
+  VOID                                          *DevicePath;\r
+\r
   //\r
-  // Locate and cache PI S3 Save State Protocol.\r
+  // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry\r
+  // point is loaded by DXE code which is the first time loaded. or else, it is already\r
+  // be reloaded be itself.This is a work-around\r
   //\r
-  Status = gBS->LocateProtocol (\r
-                  &gEfiS3SaveStateProtocolGuid, \r
-                  NULL, \r
-                  (VOID **) &mS3SaveState\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
+  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // This is the first-time loaded by DXE core. reload itself to NVS mem\r
+    //\r
+    //\r
+    // A workarouond: Here we install a dummy handle\r
+    //\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &ImageHandle,\r
+                    &gEfiCallerIdGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    DevicePath\r
+                    );\r
+\r
+    Status = GetSectionFromAnyFv  (\r
+               &gEfiCallerIdGuid,\r
+               EFI_SECTION_PE32,\r
+               0,\r
+               (VOID **) &Buffer,\r
+               &BufferSize\r
+               );\r
+    ImageContext.Handle    = Buffer;\r
+    ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+    //\r
+    // Get information about the image being loaded\r
+    //\r
+    Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Status = gBS->AllocatePool (\r
+                    EfiACPIMemoryNVS,\r
+                    BufferSize + ImageContext.SectionAlignment,\r
+                    &FfsBuffer\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
+    //\r
+    // Align buffer on section boundry\r
+    //\r
+    ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+    ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+    //\r
+    // Load the image to our new buffer\r
+    //\r
+    Status = PeCoffLoaderLoadImage (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePool (FfsBuffer);\r
+      return Status;\r
+    }\r
 \r
-  return  gBS->InstallProtocolInterface (\r
+    //\r
+    // Relocate the image in our new buffer\r
+    //\r
+    Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      PeCoffLoaderUnloadImage (&ImageContext);\r
+      gBS->FreePool (FfsBuffer);\r
+      return Status;\r
+    }\r
+    //\r
+    // Flush the instruction cache so the image data is written before we execute it\r
+    //\r
+    InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+    Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) ((EFI_HANDLE)(UINTN)(ImageContext.ImageAddress), SystemTable);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePool (FfsBuffer);\r
+      return Status;\r
+    }\r
+    //\r
+    // Additional step for BootScriptThunk integrity\r
+    //\r
+\r
+    //\r
+    // Allocate BootScriptThunkData\r
+    //\r
+    BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA));\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    BootScriptThunkData->BootScriptThunkBase   = ImageContext.ImageAddress;\r
+    BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize;\r
+    //\r
+    // Set BootScriptThunkData\r
+    //\r
+    PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData); \r
+    return EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // the entry point is invoked after reloading. following code only run in  ACPI NVS\r
+    //\r
+\r
+    //\r
+    // Locate and cache PI S3 Save State Protocol.\r
+    //\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiS3SaveStateProtocolGuid, \r
+                    NULL, \r
+                    (VOID **) &mS3SaveState\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    return gBS->InstallProtocolInterface (\r
                   &mHandle,\r
                   &gEfiBootScriptSaveProtocolGuid,\r
                   EFI_NATIVE_INTERFACE,\r
                   &mS3ScriptSave\r
                   );\r
-\r
+  }\r
 }\r
 \r
 \r
index a5a6b4d9e4f6c781ea000412cb01ada900a47ef4..b98e83a21460cf1f434880804b152d503cfa4033 100644 (file)
 #include <Library/BaseLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
 #include <Library/SmbusLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+\r
+#include <Guid/BootScriptThunkData.h>\r
+\r
 #include <IndustryStandard/SmBus.h>\r
 \r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *DISPATCH_ENTRYPOINT_FUNC) (\r
+  IN EFI_HANDLE ImageHandle,\r
+  IN VOID       *Context\r
+  );\r
+\r
 /**\r
   Adds a record into a specified Framework boot script table.\r
 \r
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.S
new file mode 100644 (file)
index 0000000..798baca
--- /dev/null
@@ -0,0 +1,216 @@
+#\r
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+# Module Name:\r
+# \r
+#    AsmDispatchExecute.asm\r
+#\r
+# Abstract:\r
+# \r
+#   This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then \r
+#   transit back to long mode.\r
+#\r
+#------------------------------------------------------------------------------- \r
+\r
+#----------------------------------------------------------------------------\r
+# Procedure:    AsmExecute32BitCode\r
+#\r
+# Input:        None\r
+#\r
+# Output:       None\r
+#\r
+# Prototype:    EFI_STATUS\r
+#               AsmExecute32BitCode (\r
+#                 IN UINT64           Function,\r
+#                 IN UINT64           Param1,\r
+#                 IN UINT64           Param2,\r
+#                 IN IA32_DESCRIPTOR  *InternalGdtr\r
+#                 );\r
+#\r
+#\r
+# Description:  A thunk function to execute 32-bit code in long mode. \r
+#\r
+#----------------------------------------------------------------------------\r
+\r
+ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)\r
+ASM_PFX(AsmExecute32BitCode):\r
+    #\r
+    # save orignal GDTR and CS\r
+    #\r
+    movq    %ds, %rax\r
+    push    %rax\r
+    movq    %cs, %rax\r
+    push    %rax\r
+    subq    $0x10, %rsp\r
+    sgdt    (%rsp)\r
+    #\r
+    # load internal GDT\r
+    #\r
+    lgdt    (%r9)\r
+    #\r
+    # Save general purpose register and rflag register\r
+    #\r
+    pushfq \r
+    push    %rdi\r
+    push    %rsi\r
+    push    %rbp\r
+    push    %rbx\r
+    \r
+    #\r
+    # save CR3\r
+    #\r
+    movq    %cr3, %rax\r
+    movq    %rax, %rbp\r
+\r
+    #\r
+    # Prepare the CS and return address for the transition from 32-bit to 64-bit mode \r
+    #        \r
+    movq    $0x10, %rax              # load long mode selector    \r
+    shl     $32, %rax\r
+    lea     ReloadCS(%rip), %r9   #Assume the ReloadCS is under 4G\r
+    orq     %r9, %rax\r
+    push    %rax\r
+    #\r
+    # Save parameters for 32-bit function call\r
+    #   \r
+    movq    %r8, %rax\r
+    shl     $32, %rax\r
+    orq     %rdx, %rax\r
+    push    %rax\r
+    #\r
+    # save the 32-bit function entry and the return address into stack which will be \r
+    # retrieve in compatibility mode.\r
+    #\r
+    lea     ReturnBack(%rip), %rax   #Assume the ReloadCS is under 4G \r
+    shl     $32, %rax\r
+    orq     %rcx, %rax\r
+    push    %rax\r
+    \r
+    #\r
+    # let rax save DS\r
+    #\r
+    movq    $0x18, %rax\r
+\r
+    #\r
+    # Change to Compatible Segment\r
+    #\r
+    movq    $8, %rcx               # load compatible mode selector \r
+    shl     $32, %rcx\r
+    lea     Compatible(%rip), %rdx # assume address < 4G\r
+    orq     %rdx, %rcx\r
+    push    %rcx\r
+    retf\r
+\r
+Compatible:\r
+    # reload DS/ES/SS to make sure they are correct referred to current GDT\r
+    movs    %ax, %ds\r
+    movs    %ax, %es\r
+    movs    %ax, %ss\r
+\r
+    #\r
+    # Disable paging\r
+    #\r
+    movq    %cr0, %rcx\r
+    btc     $31, %ecx\r
+    movq    %rcx, %cr0\r
+    #\r
+    # Clear EFER.LME\r
+    #\r
+    movl    $0xC0000080, %ecx\r
+    rdmsr\r
+    btc     $8, %eax\r
+    wrmsr\r
+\r
+# Now we are in protected mode\r
+    #\r
+    # Call 32-bit function. Assume the function entry address and parameter value is less than 4G\r
+    #    \r
+    pop    %rax                 # Here is the function entry\r
+    #  \r
+    # Now the parameter is at the bottom of the stack,  then call in to IA32 function.\r
+    #\r
+    jmp   *%rax\r
+ReturnBack:  \r
+    pop   %rcx                  # drop param1      \r
+    pop   %rcx                  # drop param2      \r
+\r
+    #\r
+    # restore CR4\r
+    #\r
+    movq    %cr4, %rax\r
+    bts     $5, %eax\r
+    movq    %rax, %cr4\r
+\r
+    #\r
+    # restore CR3\r
+    #\r
+    movl    %ebp, %eax\r
+    movq    %rax, %cr3\r
+\r
+    #\r
+    # Set EFER.LME to re-enable ia32-e\r
+    #\r
+    movl    $0xC0000080, %ecx\r
+    rdmsr\r
+    bts     $8, %eax\r
+    wrmsr\r
+    #\r
+    # Enable paging\r
+    #\r
+    movq    %cr0, %rax\r
+    bts     $31, %eax\r
+    mov     %rax, %cr0\r
+# Now we are in compatible mode\r
+\r
+    #\r
+    # Reload cs register \r
+    #   \r
+    retf\r
+ReloadCS:   \r
+    #\r
+    # Now we're in Long Mode\r
+    #\r
+    #\r
+    # Restore C register and eax hold the return status from 32-bit function.\r
+    # Note: Do not touch rax from now which hold the return value from IA32 function\r
+    #\r
+    pop     %rbx\r
+    pop     %rbp\r
+    pop     %rsi\r
+    pop     %rdi\r
+    popfq\r
+    #\r
+    # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.\r
+    #\r
+    lgdt    (%rsp)\r
+    #\r
+    # drop GDT descriptor in stack\r
+    #\r
+    addq    $0x10, %rsp\r
+    #\r
+    # switch to orignal CS and GDTR\r
+    #\r
+    pop     %r9                 # get  CS\r
+    shl     $32, %r9            # rcx[32..47] <- Cs       \r
+    lea     @F(%rip), %rcx\r
+    orq     %r9, %rcx\r
+    push    %rcx\r
+    retf\r
+@@:        \r
+    #\r
+    # Reload original DS/ES/SS\r
+    #\r
+    pop     %rcx\r
+    movq    %rcx, %ds\r
+    movq    %rcx, %es\r
+    movq    %rcx, %ss\r
+    ret\r
+\r
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/AsmDispatchExecute.asm
new file mode 100644 (file)
index 0000000..2d5d920
--- /dev/null
@@ -0,0 +1,216 @@
+;\r
+; Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+; This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution.  The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;\r
+; Module Name:\r
+; \r
+;    AsmDispatchExecute.asm\r
+;\r
+; Abstract:\r
+; \r
+;   This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then \r
+;   transit back to long mode.\r
+;\r
+;------------------------------------------------------------------------------- \r
+    .code\r
+;----------------------------------------------------------------------------\r
+; Procedure:    AsmExecute32BitCode\r
+;\r
+; Input:        None\r
+;\r
+; Output:       None\r
+;\r
+; Prototype:    EFI_STATUS\r
+;               AsmExecute32BitCode (\r
+;                 IN UINT64           Function,\r
+;                 IN UINT64           Param1,\r
+;                 IN UINT64           Param2,\r
+;                 IN IA32_DESCRIPTOR  *InternalGdtr\r
+;                 );\r
+;\r
+;\r
+; Description:  A thunk function to execute 32-bit code in long mode. \r
+;\r
+;----------------------------------------------------------------------------\r
+AsmExecute32BitCode    PROC    \r
+    ;\r
+    ; save orignal GDTR and CS\r
+    ;\r
+    mov     rax, ds\r
+    push    rax\r
+    mov     rax, cs\r
+    push    rax\r
+    sub     rsp, 10h\r
+    sgdt    fword ptr [rsp]\r
+    ;\r
+    ; load internal GDT\r
+    ;\r
+    lgdt    fword ptr [r9]\r
+    ;\r
+    ; Save general purpose register and rflag register\r
+    ;\r
+    pushfq \r
+    push    rdi\r
+    push    rsi\r
+    push    rbp\r
+    push    rbx\r
+    \r
+    ;\r
+    ; save CR3\r
+    ;\r
+    mov     rax, cr3\r
+    mov     rbp, rax\r
+\r
+    ;\r
+    ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode \r
+    ;        \r
+    mov     rax, 10h              ; load long mode selector    \r
+    shl     rax, 32\r
+    mov     r9, OFFSET ReloadCS   ;Assume the ReloadCS is under 4G\r
+    or      rax, r9\r
+    push    rax\r
+    ;\r
+    ; Save parameters for 32-bit function call\r
+    ;   \r
+    mov     rax, r8\r
+    shl     rax, 32\r
+    or      rax, rdx\r
+    push    rax\r
+    ;\r
+    ; save the 32-bit function entry and the return address into stack which will be \r
+    ; retrieve in compatibility mode.\r
+    ;\r
+    mov     rax, OFFSET ReturnBack   ;Assume the ReloadCS is under 4G \r
+    shl     rax, 32\r
+    or      rax, rcx\r
+    push    rax\r
+    \r
+    ;\r
+    ; let rax save DS\r
+    ;\r
+    mov     rax, 018h\r
+\r
+    ;\r
+    ; Change to Compatible Segment\r
+    ;\r
+    mov     rcx, 08h               ; load compatible mode selector \r
+    shl     rcx, 32\r
+    mov     rdx, OFFSET Compatible ; assume address < 4G\r
+    or      rcx, rdx\r
+    push    rcx\r
+    retf\r
+\r
+Compatible:\r
+    ; reload DS/ES/SS to make sure they are correct referred to current GDT\r
+    mov     ds, ax\r
+    mov     es, ax\r
+    mov     ss, ax\r
+\r
+    ;\r
+    ; Disable paging\r
+    ;\r
+    mov     rcx, cr0\r
+    btc     ecx, 31\r
+    mov     cr0, rcx\r
+    ;\r
+    ; Clear EFER.LME\r
+    ;\r
+    mov     ecx, 0C0000080h\r
+    rdmsr\r
+    btc     eax, 8\r
+    wrmsr\r
+\r
+; Now we are in protected mode\r
+    ;\r
+    ; Call 32-bit function. Assume the function entry address and parameter value is less than 4G\r
+    ;    \r
+    pop    rax                 ; Here is the function entry\r
+    ;  \r
+    ; Now the parameter is at the bottom of the stack,  then call in to IA32 function.\r
+    ;\r
+    jmp   rax\r
+ReturnBack:\r
+    pop   rcx                  ; drop param1      \r
+    pop   rcx                  ; drop param2      \r
+\r
+    ;\r
+    ; restore CR4\r
+    ;\r
+    mov     rax, cr4\r
+    bts     eax, 5\r
+    mov     cr4, rax\r
+\r
+    ;\r
+    ; restore CR3\r
+    ;\r
+    mov     eax, ebp\r
+    mov     cr3, rax\r
+\r
+    ;\r
+    ; Set EFER.LME to re-enable ia32-e\r
+    ;\r
+    mov     ecx, 0C0000080h\r
+    rdmsr\r
+    bts     eax, 8\r
+    wrmsr\r
+    ;\r
+    ; Enable paging\r
+    ;\r
+    mov     rax, cr0\r
+    bts     eax, 31\r
+    mov     cr0, rax\r
+; Now we are in compatible mode\r
+\r
+    ;\r
+    ; Reload cs register \r
+    ;   \r
+    retf\r
+ReloadCS:   \r
+    ;\r
+    ; Now we're in Long Mode\r
+    ;\r
+    ;\r
+    ; Restore C register and eax hold the return status from 32-bit function.\r
+    ; Note: Do not touch rax from now which hold the return value from IA32 function\r
+    ;\r
+    pop     rbx\r
+    pop     rbp\r
+    pop     rsi\r
+    pop     rdi\r
+    popfq\r
+    ;\r
+    ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.\r
+    ;\r
+    lgdt    fword ptr[rsp]\r
+    ;\r
+    ; drop GDT descriptor in stack\r
+    ;\r
+    add     rsp, 10h \r
+    ;\r
+    ; switch to orignal CS and GDTR\r
+    ;\r
+    pop     r9                 ; get  CS\r
+    shl     r9,  32            ; rcx[32..47] <- Cs       \r
+    mov     rcx, OFFSET @F          \r
+    or      rcx, r9\r
+    push    rcx\r
+    retf\r
+@@:        \r
+    ;\r
+    ; Reload original DS/ES/SS\r
+    ;\r
+    pop     rcx\r
+    mov     ds, rcx\r
+    mov     es, rcx\r
+    mov     ss, rcx\r
+    ret\r
+AsmExecute32BitCode   ENDP\r
+\r
+    END\r
diff --git a/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c b/EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/X64/DispatchExecute.c
new file mode 100644 (file)
index 0000000..8ef4299
--- /dev/null
@@ -0,0 +1,106 @@
+/** @file\r
+  Execute 32-bit code in Long Mode\r
+  Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit\r
+  back to long mode.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "ScriptSave.h"\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+  struct {\r
+    UINT32  LimitLow    : 16;\r
+    UINT32  BaseLow     : 16;\r
+    UINT32  BaseMid     : 8;\r
+    UINT32  Type        : 4;\r
+    UINT32  System      : 1;\r
+    UINT32  Dpl         : 2;\r
+    UINT32  Present     : 1;\r
+    UINT32  LimitHigh   : 4;\r
+    UINT32  Software    : 1;\r
+    UINT32  Reserved    : 1;\r
+    UINT32  DefaultSize : 1;\r
+    UINT32  Granularity : 1;\r
+    UINT32  BaseHigh    : 8;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} IA32_GDT;\r
+#pragma pack()\r
+\r
+//\r
+// Global Descriptor Table (GDT)\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
+  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, /* 0x0:  reserve */\r
+  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}}, /* 0x8:  compatibility mode */\r
+  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  1, 0,  1,  0}}, /* 0x10: for long mode */\r
+  {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}}, /* 0x18: data */\r
+  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, /* 0x20: reserve */\r
+};\r
+\r
+//\r
+// IA32 Gdt register\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {\r
+  sizeof (mGdtEntries) - 1,\r
+  (UINTN) mGdtEntries\r
+  };\r
+/**\r
+  Assembly function to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+  long mode.\r
+  @param  Function     The 32bit code entry to be executed.\r
+  @param  Param1       The first parameter to pass to 32bit code\r
+  @param  Param2       The second parameter to pass to 32bit code\r
+  @param  InternalGdtr The GDT and GDT descriptor used by this library\r
+  \r
+  @retval EFI_SUCCESS  Execute 32bit code successfully.\r
+  @retval other        Something wrong when execute the 32bit code \r
+**/\r
+EFI_STATUS\r
+AsmExecute32BitCode (\r
+  IN UINT64           Function,\r
+  IN UINT64           Param1,\r
+  IN UINT64           Param2,\r
+  IN IA32_DESCRIPTOR  *InternalGdtr\r
+  );\r
+  \r
+/**\r
+  Wrapper for a thunk  to transition from long mode to compatibility mode to execute 32-bit code and then transit back to\r
+  long mode.\r
+  \r
+  @param  Function     The 32bit code entry to be executed.\r
+  @param  Param1       The first parameter to pass to 32bit code\r
+  @param  Param2       The second parameter to pass to 32bit code\r
+  @retval EFI_SUCCESS  Execute 32bit code successfully.\r
+  @retval other        Something wrong when execute the 32bit code \r
+              \r
+**/  \r
+EFI_STATUS\r
+Execute32BitCode (\r
+  IN UINT64      Function,\r
+  IN UINT64      Param1,\r
+  IN UINT64      Param2\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
\r
+  ASSERT (Function != 0);\r
\r
+  Status = AsmExecute32BitCode (\r
+             Function,\r
+             Param1,\r
+             Param2,\r
+             &mGdt\r
+             );\r
+  return Status;\r
+}\r
+\r
diff --git a/EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h b/EdkCompatibilityPkg/Compatibility/Include/Guid/BootScriptThunkData.h
new file mode 100644 (file)
index 0000000..f0e6f5f
--- /dev/null
@@ -0,0 +1,31 @@
+/** @file\r
+  Define Name, GUID and data format for an EFI PCD that is used to save the image base and size\r
+  of a code segment which will be loaded and executed by a boot script thunk on S3 boot path.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _BOOT_SCRIPT_THUNK_VARIABLE_H_\r
+#define _BOOT_SCRIPT_THUNK_VARIABLE_H_\r
+\r
+//\r
+// The following structure boosts performance by combining structure all ACPI related variables into one.\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS  BootScriptThunkBase;\r
+  EFI_PHYSICAL_ADDRESS  BootScriptThunkLength;\r
+} BOOT_SCRIPT_THUNK_DATA;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
index 7c616b75b14f926f344c67648777b757c77722ec..f148ded6eb51039c64f4c4e245a4724e8895ec0f 100644 (file)
@@ -69,6 +69,7 @@ define GCC_MACRO                 = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S
   CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf\r
   DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf\r
   LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf\r
+  DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
 \r
 [LibraryClasses.common.PEIM]\r
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
@@ -256,7 +257,6 @@ define GCC_MACRO                 = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S
   EdkCompatibilityPkg/Compatibility/LegacyRegion2OnLegacyRegionThunk/LegacyRegion2OnLegacyRegionThunk.inf\r
   EdkCompatibilityPkg/Compatibility/PiSmbiosRecordOnDataHubSmbiosRecordThunk/PiSmbiosRecordOnDataHubSmbiosRecordThunk.inf\r
   EdkCompatibilityPkg/Compatibility/CpuIo2OnCpuIoThunk/CpuIo2OnCpuIoThunk.inf\r
-  EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf\r
 \r
   #\r
   # User needs to turn on the compatibility switches for VFRC and EDK II build tool for Framework HII modules \r
@@ -285,6 +285,7 @@ define GCC_MACRO                 = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S
   EdkCompatibilityPkg/Compatibility/SmmControl2OnSmmControlThunk/SmmControl2OnSmmControlThunk.inf\r
   EdkCompatibilityPkg/Compatibility/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk/PiSmmStatusCodeOnFrameworkSmmStatusCodeThunk.inf\r
   EdkCompatibilityPkg/Compatibility/FrameworkSmmStatusCodeOnPiSmmStatusCodeThunk/FrameworkSmmStatusCodeOnPiSmmStatusCodeThunk.inf\r
+  EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/BootScriptSaveOnS3SaveStateThunk.inf\r
 \r
 [Components.IPF]\r
   EdkCompatibilityPkg/Foundation/Cpu/Itanium/CpuIa64Lib/CpuIA64Lib.inf\r