]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Compatibility/BootScriptSaveOnS3SaveStateThunk/ScriptSave.c
Fix boot script thunk issue that we need dispatch in PEI mode for Framework dispatch...
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / BootScriptSaveOnS3SaveStateThunk / ScriptSave.c
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