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
);\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
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
\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
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