| /** @file | |
| Implementation for S3 Boot Script Save thunk driver. | |
| This thunk driver consumes PI S3SaveState protocol to produce framework S3BootScriptSave Protocol | |
| Copyright (c) 2010 - 2015, 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" | |
| EFI_HANDLE mHandle; | |
| EFI_BOOT_SCRIPT_SAVE_PROTOCOL mS3ScriptSave = { | |
| BootScriptWrite, | |
| 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. | |
| @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 | |
| BootScriptIoWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINTN Count; | |
| UINT8 *Buffer; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Count = VA_ARG (Marker, UINTN); | |
| Buffer = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Count, | |
| Buffer | |
| ); | |
| } | |
| /** | |
| Internal function to add IO read/write opcode to the table. | |
| @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 | |
| BootScriptIoReadWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINT8 *Data; | |
| UINT8 *DataMask; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Data = VA_ARG (Marker, UINT8 *); | |
| DataMask = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Data, | |
| DataMask | |
| ); | |
| } | |
| /** | |
| Internal function to add memory write opcode to the table. | |
| @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 | |
| BootScriptMemWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINTN Count; | |
| UINT8 *Buffer; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Count = VA_ARG (Marker, UINTN); | |
| Buffer = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Count, | |
| Buffer | |
| ); | |
| } | |
| /** | |
| Internal function to add memory read/write opcode to the table. | |
| @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 | |
| BootScriptMemReadWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINT8 *Data; | |
| UINT8 *DataMask; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Data = VA_ARG (Marker, UINT8 *); | |
| DataMask = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Data, | |
| DataMask | |
| ); | |
| } | |
| /** | |
| Internal function to add PciCfg write opcode to the table. | |
| @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 | |
| BootScriptPciCfgWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINTN Count; | |
| UINT8 *Buffer; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Count = VA_ARG (Marker, UINTN); | |
| Buffer = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Count, | |
| Buffer | |
| ); | |
| } | |
| /** | |
| Internal function to PciCfg read/write opcode to the table. | |
| @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 | |
| BootScriptPciCfgReadWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINT8 *Data; | |
| UINT8 *DataMask; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Data = VA_ARG (Marker, UINT8 *); | |
| DataMask = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE, | |
| Width, | |
| Address, | |
| Data, | |
| DataMask | |
| ); | |
| } | |
| /** | |
| Internal function to add PciCfg2 write opcode to the table. | |
| @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 | |
| BootScriptPciCfg2Write ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINTN Count; | |
| UINT8 *Buffer; | |
| UINT16 Segment; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Count = VA_ARG (Marker, UINTN); | |
| Buffer = VA_ARG (Marker, UINT8 *); | |
| Segment = VA_ARG (Marker, UINT16); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE, | |
| Width, | |
| Segment, | |
| Address, | |
| Count, | |
| Buffer | |
| ); | |
| } | |
| /** | |
| Internal function to PciCfg2 read/write opcode to the table. | |
| @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 | |
| BootScriptPciCfg2ReadWrite ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT16 Segment; | |
| UINT64 Address; | |
| UINT8 *Data; | |
| UINT8 *DataMask; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| Segment = VA_ARG (Marker, UINT16); | |
| Data = VA_ARG (Marker, UINT8 *); | |
| DataMask = VA_ARG (Marker, UINT8 *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE, | |
| Width, | |
| Segment, | |
| Address, | |
| Data, | |
| DataMask | |
| ); | |
| } | |
| /** | |
| Internal function to add smbus execute opcode to the table. | |
| @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 | |
| BootScriptSmbusExecute ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; | |
| EFI_SMBUS_DEVICE_COMMAND Command; | |
| EFI_SMBUS_OPERATION Operation; | |
| BOOLEAN PecCheck; | |
| VOID *Buffer; | |
| UINTN *DataSize; | |
| SlaveAddress.SmbusDeviceAddress = VA_ARG (Marker, UINTN); | |
| Command = VA_ARG (Marker, EFI_SMBUS_DEVICE_COMMAND); | |
| Operation = VA_ARG (Marker, EFI_SMBUS_OPERATION); | |
| PecCheck = VA_ARG (Marker, BOOLEAN); | |
| DataSize = VA_ARG (Marker, UINTN *); | |
| Buffer = VA_ARG (Marker, VOID *); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE, | |
| SlaveAddress, | |
| Command, | |
| Operation, | |
| PecCheck, | |
| DataSize, | |
| Buffer | |
| ); | |
| } | |
| /** | |
| Internal function to add stall opcode to the table. | |
| @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 | |
| BootScriptStall ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| UINT32 Duration; | |
| Duration = VA_ARG (Marker, UINT32); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_STALL_OPCODE, | |
| Duration | |
| ); | |
| } | |
| /** | |
| Internal function to add Save jmp address according to DISPATCH_OPCODE. | |
| We ignore "Context" parameter | |
| @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 | |
| BootScriptDispatch ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| VOID *EntryPoint; | |
| EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_DISPATCH_OPCODE, | |
| EntryPoint | |
| ); | |
| } | |
| /** | |
| 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 | |
| and associated attributes. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation. | |
| @retval EFI_SUCCESS Opcode is added. | |
| **/ | |
| EFI_STATUS | |
| BootScriptMemPoll ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| EFI_BOOT_SCRIPT_WIDTH Width; | |
| UINT64 Address; | |
| UINT8 *BitMask; | |
| UINT8 *BitValue; | |
| UINT64 Duration; | |
| UINT64 LoopTimes; | |
| UINT64 Delay; | |
| Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); | |
| Address = VA_ARG (Marker, UINT64); | |
| BitMask = VA_ARG (Marker, UINT8 *); | |
| BitValue = VA_ARG (Marker, UINT8 *); | |
| Duration = (UINT64)VA_ARG (Marker, UINT64); | |
| LoopTimes = (UINT64)VA_ARG (Marker, UINT64); | |
| // | |
| // Framework version: Duration is used for Stall(), which is Microseconds. | |
| // Total time is: Duration(Microseconds) * LoopTimes. | |
| // PI version: Duration is always 100ns. Delay is LoopTimes. | |
| // Total time is: 100ns * Delay. | |
| // So Delay = Duration(Microseconds) * LoopTimes / 100ns | |
| // = Duration * 1000ns * LoopTimes / 100ns | |
| // = Duration * 10 * LoopTimes | |
| // | |
| Delay = MultU64x64 (MultU64x32 (Duration, 10), LoopTimes); | |
| // | |
| // Framework version: First BitMask, then BitValue | |
| // PI version: First Data, then DataMask | |
| // So we revert their order in function call | |
| // | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, | |
| Width, | |
| Address, | |
| BitValue, | |
| BitMask, | |
| Delay | |
| ); | |
| } | |
| /** | |
| Internal function to add Save jmp address according to DISPATCH_OPCODE2. | |
| The "Context" parameter is not ignored. | |
| @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 | |
| BootScriptDispatch2 ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| VOID *EntryPoint; | |
| VOID *Context; | |
| EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS); | |
| Context = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE, | |
| EntryPoint, | |
| Context | |
| ); | |
| } | |
| /** | |
| Internal function to add the opcode link node to the link | |
| list. | |
| @param Marker The variable argument list to get the opcode | |
| and associated attributes. | |
| @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations. | |
| @retval EFI_SUCCESS The opcode entry is added to the link list | |
| successfully. | |
| **/ | |
| EFI_STATUS | |
| BootScriptInformation ( | |
| IN VA_LIST Marker | |
| ) | |
| { | |
| UINT32 InformationLength; | |
| EFI_PHYSICAL_ADDRESS Information; | |
| InformationLength = VA_ARG (Marker, UINT32); | |
| Information = VA_ARG (Marker, EFI_PHYSICAL_ADDRESS); | |
| return mS3SaveState->Write ( | |
| mS3SaveState, | |
| EFI_BOOT_SCRIPT_INFORMATION_OPCODE, | |
| InformationLength, | |
| (VOID*)(UINTN)Information | |
| ); | |
| } | |
| /** | |
| Adds a record into a specified Framework boot script table. | |
| This function is used to store a boot script record into a given boot | |
| script table. If the table specified by TableName is nonexistent in the | |
| system, a new table will automatically be created and then the script record | |
| will be added into the new table. A boot script table can add new script records | |
| until EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is called. Currently, the only | |
| meaningful table name is EFI_ACPI_S3_RESUME_SCRIPT_TABLE. This function is | |
| responsible for allocating necessary memory for the script. | |
| This function has a variable parameter list. The exact parameter list depends on | |
| the OpCode that is passed into the function. If an unsupported OpCode or illegal | |
| parameter list is passed in, this function returns EFI_INVALID_PARAMETER. | |
| If there are not enough resources available for storing more scripts, this function returns | |
| EFI_OUT_OF_RESOURCES. | |
| @param This A pointer to the EFI_BOOT_SCRIPT_SAVE_PROTOCOL instance. | |
| @param TableName Name of the script table. Currently, the only meaningful value is | |
| EFI_ACPI_S3_RESUME_SCRIPT_TABLE. | |
| @param OpCode The operation code (opcode) number. | |
| @param ... Argument list that is specific to each opcode. | |
| @retval EFI_SUCCESS The operation succeeded. A record was added into the | |
| specified script table. | |
| @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported. | |
| If the opcode is unknow or not supported because of the PCD | |
| Feature Flags. | |
| @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BootScriptWrite ( | |
| IN EFI_BOOT_SCRIPT_SAVE_PROTOCOL *This, | |
| IN UINT16 TableName, | |
| IN UINT16 OpCode, | |
| ... | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VA_LIST Marker; | |
| if (TableName != FRAMEWORK_EFI_ACPI_S3_RESUME_SCRIPT_TABLE) { | |
| // | |
| // Only S3 boot script is supported for now | |
| // | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Build script according to opcode | |
| // | |
| switch (OpCode) { | |
| case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptIoWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptIoReadWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptMemWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptMemReadWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptPciCfgWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptPciCfgReadWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptSmbusExecute (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_STALL_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptStall (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_DISPATCH_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = FrameworkBootScriptDispatch (Marker); | |
| VA_END (Marker); | |
| break; | |
| case FRAMEWORK_EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptDispatch2 (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_INFORMATION_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptInformation (Marker); | |
| VA_END (Marker); | |
| break; | |
| case FRAMEWORK_EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptMemPoll (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptPciCfg2Write (Marker); | |
| VA_END (Marker); | |
| break; | |
| case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE: | |
| VA_START (Marker, OpCode); | |
| Status = BootScriptPciCfg2ReadWrite (Marker); | |
| VA_END (Marker); | |
| break; | |
| default: | |
| Status = EFI_INVALID_PARAMETER; | |
| break; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Closes the specified script table. | |
| This function closes the specified boot script table and returns the base address | |
| of the table. It allocates a new pool to duplicate all the boot scripts in the specified | |
| table. Once this function is called, the specified table will be destroyed after it is | |
| copied into the allocated pool. As a result, any attempts to add a script record into a | |
| closed table will cause a new table to be created. The base address of the allocated pool | |
| will be returned in Address. After using the boot script table, the caller is responsible | |
| for freeing the pool that is allocated by this function. If the boot script table, | |
| such as EFI_ACPI_S3_RESUME_SCRIPT_TABLE, is required to be stored in a nonperturbed | |
| memory region, the caller should copy the table into the nonperturbed memory region by itself. | |
| @param This A pointer to the EFI_BOOT_SCRIPT_SAVE_PROTOCOL instance. | |
| @param TableName Name of the script table. Currently, the only meaningful value is | |
| EFI_ACPI_S3_RESUME_SCRIPT_TABLE. | |
| @param Address A pointer to the physical address where the table begins. | |
| @retval EFI_SUCCESS The table was successfully returned. | |
| @retval EFI_NOT_FOUND The specified table was not created previously. | |
| @retval EFI_OUT_OF_RESOURCE Memory is insufficient to hold the reorganized boot script table. | |
| @retval EFI_UNSUPPORTED the table type is not EFI_ACPI_S3_RESUME_SCRIPT_TABLE | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BootScriptCloseTable ( | |
| IN EFI_BOOT_SCRIPT_SAVE_PROTOCOL *This, | |
| IN UINT16 TableName, | |
| OUT EFI_PHYSICAL_ADDRESS *Address | |
| ) | |
| { | |
| if (TableName != FRAMEWORK_EFI_ACPI_S3_RESUME_SCRIPT_TABLE) { | |
| // | |
| // Only S3 boot script is supported for now | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Here the close table is not implemented. | |
| // | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Register image to memory profile. | |
| @param FileName File name of the image. | |
| @param ImageBase Image base address. | |
| @param ImageSize Image size. | |
| @param FileType File type of the image. | |
| **/ | |
| VOID | |
| RegisterMemoryProfileImage ( | |
| IN EFI_GUID *FileName, | |
| IN PHYSICAL_ADDRESS ImageBase, | |
| IN UINT64 ImageSize, | |
| IN EFI_FV_FILETYPE FileType | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol; | |
| MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; | |
| UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; | |
| if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) { | |
| FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; | |
| Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol); | |
| if (!EFI_ERROR (Status)) { | |
| EfiInitializeFwVolDevicepathNode (FilePath, FileName); | |
| SetDevicePathEndNode (FilePath + 1); | |
| Status = ProfileProtocol->RegisterImage ( | |
| ProfileProtocol, | |
| (EFI_DEVICE_PATH_PROTOCOL *) FilePath, | |
| ImageBase, | |
| ImageSize, | |
| FileType | |
| ); | |
| } | |
| } | |
| } | |
| /** | |
| This routine is entry point of ScriptSave driver. | |
| @param ImageHandle Handle for this drivers loaded image protocol. | |
| @param SystemTable EFI system table. | |
| @retval EFI_OUT_OF_RESOURCES No enough resource | |
| @retval EFI_SUCCESS Succesfully installed the ScriptSave driver. | |
| @retval other Errors occured. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| InitializeScriptSaveOnS3SaveState ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| 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; | |
| // | |
| // 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 RESERVED mem | |
| // | |
| // | |
| // A workaround: Here we install a dummy handle | |
| // | |
| NewImageHandle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &NewImageHandle, | |
| &gEfiCallerIdGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = GetSectionFromAnyFv ( | |
| &gEfiCallerIdGuid, | |
| EFI_SECTION_PE32, | |
| 0, | |
| (VOID **) &Buffer, | |
| &BufferSize | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| ImageContext.Handle = Buffer; | |
| ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; | |
| // | |
| // Get information about the image being loaded | |
| // | |
| Status = PeCoffLoaderGetImageInfo (&ImageContext); | |
| ASSERT_EFI_ERROR (Status); | |
| MemoryAddress = SIZE_4GB - 1; | |
| if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { | |
| PageNumber = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); | |
| } else { | |
| PageNumber = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); | |
| } | |
| Status = gBS->AllocatePages ( | |
| AllocateMaxAddress, | |
| EfiReservedMemoryType, | |
| PageNumber, | |
| &MemoryAddress | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress; | |
| // | |
| // Align buffer on section boundary | |
| // | |
| ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; | |
| ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); | |
| // | |
| // Load the image to our new buffer | |
| // | |
| Status = PeCoffLoaderLoadImage (&ImageContext); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Relocate the image in our new buffer | |
| // | |
| Status = PeCoffLoaderRelocateImage (&ImageContext); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer | |
| // | |
| gBS->FreePool (Buffer); | |
| // | |
| // Flush the instruction cache so the image data is written before we execute it | |
| // | |
| InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); | |
| RegisterMemoryProfileImage ( | |
| &gEfiCallerIdGuid, | |
| ImageContext.ImageAddress, | |
| ImageContext.ImageSize, | |
| EFI_FV_FILETYPE_DRIVER | |
| ); | |
| Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Additional step for BootScriptThunk integrity | |
| // | |
| // | |
| // Allocate BootScriptThunkData | |
| // | |
| BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA)); | |
| ASSERT (BootScriptThunkData != NULL); | |
| 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 RESERVED mem | |
| // | |
| // | |
| // 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 | |
| ); | |
| } | |
| } | |