From 64d14edfeb3f0dd31506bec1244a8d53f08789cc Mon Sep 17 00:00:00 2001 From: jljusten Date: Mon, 29 Aug 2011 22:17:27 +0000 Subject: MdeModulePkg: Add PiDxeS3BootScriptLib Signed-off-by: jljusten Reviewed-by: mdkinney Reviewed-by: rsun3 Reviewed-by: jyao1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12224 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PiDxeS3BootScriptLib/BootScriptExecute.c | 1753 ++++++++++++++++++ .../BootScriptInternalFormat.h | 186 ++ .../Library/PiDxeS3BootScriptLib/BootScriptSave.c | 1852 ++++++++++++++++++++ .../PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf | 70 + .../PiDxeS3BootScriptLib/InternalBootScriptLib.h | 102 ++ MdeModulePkg/MdeModulePkg.dsc | 1 + 6 files changed, 3964 insertions(+) create mode 100644 MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c create mode 100644 MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h create mode 100644 MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c create mode 100644 MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf create mode 100644 MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h (limited to 'MdeModulePkg') diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c new file mode 100644 index 0000000000..5a93549271 --- /dev/null +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c @@ -0,0 +1,1753 @@ +/** @file + Interpret and execute the S3 data in S3 boot script. + + Copyright (c) 2006 - 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 "InternalBootScriptLib.h" + +/** + Checks the parameter of SmbusExecute(). + + This function checks the input parameters of SmbusExecute(). If the input parameters are valid + for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain + error code based on the input SMBus bus protocol. + + @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, + and PEC. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus + protocol. + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +CheckParameters ( + IN UINTN SmBusAddress, + IN EFI_SMBUS_OPERATION Operation, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN RequiredLen; + EFI_SMBUS_DEVICE_COMMAND Command; + BOOLEAN PecCheck; + + Command = SMBUS_LIB_COMMAND (SmBusAddress); + PecCheck = SMBUS_LIB_PEC (SmBusAddress); + // + // Set default value to be 2: + // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall. + // + RequiredLen = 2; + Status = EFI_SUCCESS; + switch (Operation) { + case EfiSmbusQuickRead: + case EfiSmbusQuickWrite: + if (PecCheck || Command != 0) { + return EFI_UNSUPPORTED; + } + break; + case EfiSmbusReceiveByte: + case EfiSmbusSendByte: + if (Command != 0) { + return EFI_UNSUPPORTED; + } + // + // Cascade to check length parameter. + // + case EfiSmbusReadByte: + case EfiSmbusWriteByte: + RequiredLen = 1; + // + // Cascade to check length parameter. + // + case EfiSmbusReadWord: + case EfiSmbusWriteWord: + case EfiSmbusProcessCall: + if (Buffer == NULL || Length == NULL) { + return EFI_INVALID_PARAMETER; + } else if (*Length < RequiredLen) { + Status = EFI_BUFFER_TOO_SMALL; + } + *Length = RequiredLen; + break; + case EfiSmbusReadBlock: + case EfiSmbusWriteBlock: + if ((Buffer == NULL) || + (Length == NULL) || + (*Length < MIN_SMBUS_BLOCK_LEN) || + (*Length > MAX_SMBUS_BLOCK_LEN)) { + return EFI_INVALID_PARAMETER; + } + break; + case EfiSmbusBWBRProcessCall: + return EFI_UNSUPPORTED; + default: + return EFI_INVALID_PARAMETER; + } + return Status; +} + +/** + Executes an SMBus operation to an SMBus controller. Returns when either the command has been + executed or an error is encountered in doing the operation. + + The SmbusExecute() function provides a standard way to execute an operation as defined in the System + Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus + slave devices accept this transaction or that this function returns with error. + + @param SmbusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, + and PEC. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +SmbusExecute ( + IN UINTN SmbusAddress, + IN EFI_SMBUS_OPERATION Operation, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN WorkBufferLen; + UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN]; + + Status = CheckParameters (SmbusAddress, Operation, Length, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Operation) { + case EfiSmbusQuickRead: + DEBUG ((EFI_D_INFO, "EfiSmbusQuickRead - 0x%08x\n", SmbusAddress)); + SmBusQuickRead (SmbusAddress, &Status); + break; + case EfiSmbusQuickWrite: + DEBUG ((EFI_D_INFO, "EfiSmbusQuickWrite - 0x%08x\n", SmbusAddress)); + SmBusQuickWrite (SmbusAddress, &Status); + break; + case EfiSmbusReceiveByte: + DEBUG ((EFI_D_INFO, "EfiSmbusReceiveByte - 0x%08x\n", SmbusAddress)); + *(UINT8 *) Buffer = SmBusReceiveByte (SmbusAddress, &Status); + break; + case EfiSmbusSendByte: + DEBUG ((EFI_D_INFO, "EfiSmbusReceiveByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer)); + SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status); + break; + case EfiSmbusReadByte: + DEBUG ((EFI_D_INFO, "EfiSmbusReadByte - 0x%08x\n", SmbusAddress)); + *(UINT8 *) Buffer = SmBusReadDataByte (SmbusAddress, &Status); + break; + case EfiSmbusWriteByte: + DEBUG ((EFI_D_INFO, "EfiSmbusWriteByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer)); + SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status); + break; + case EfiSmbusReadWord: + DEBUG ((EFI_D_INFO, "EfiSmbusReadWord - 0x%08x\n", SmbusAddress)); + *(UINT16 *) Buffer = SmBusReadDataWord (SmbusAddress, &Status); + break; + case EfiSmbusWriteWord: + DEBUG ((EFI_D_INFO, "EfiSmbusWriteByte - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer)); + SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status); + break; + case EfiSmbusProcessCall: + DEBUG ((EFI_D_INFO, "EfiSmbusProcessCall - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer)); + *(UINT16 *) Buffer = SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status); + break; + case EfiSmbusReadBlock: + DEBUG ((EFI_D_INFO, "EfiSmbusReadBlock - 0x%08x\n", SmbusAddress)); + WorkBufferLen = SmBusReadBlock (SmbusAddress, WorkBuffer, &Status); + if (!EFI_ERROR (Status)) { + // + // Read block transaction is complete successfully, and then + // check whether the output buffer is large enough. + // + if (*Length >= WorkBufferLen) { + CopyMem (Buffer, WorkBuffer, WorkBufferLen); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *Length = WorkBufferLen; + } + break; + case EfiSmbusWriteBlock: + DEBUG ((EFI_D_INFO, "EfiSmbusWriteBlock - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer)); + SmBusWriteBlock ((SmbusAddress + SMBUS_LIB_ADDRESS (0, 0, (*Length), FALSE)) , Buffer, &Status); + break; + case EfiSmbusBWBRProcessCall: + // + // BUGBUG: Should this case be handled? + // + break; + } + + return Status; +} + +/** + Translates boot script width and address stride to MDE library interface. + + + @param Width Width of the operation. + @param Address Address of the operation. + @param AddressStride Instride for stepping input buffer. + @param BufferStride Outstride for stepping output buffer. + + @retval EFI_SUCCESS Successful translation. + @retval EFI_INVALID_PARAMETER Width or Address is invalid. +**/ +EFI_STATUS +BuildLoopData ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + OUT UINTN *AddressStride, + OUT UINTN *BufferStride + ) +{ + UINTN AlignMask; + + if (Width >= S3BootScriptWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + *AddressStride = (UINT32)(1 << (Width & 0x03)); + *BufferStride = *AddressStride; + + AlignMask = *AddressStride - 1; + if ((Address & AlignMask) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (Width >= S3BootScriptWidthFifoUint8 && Width <= S3BootScriptWidthFifoUint64) { + *AddressStride = 0; + } + + if (Width >= S3BootScriptWidthFillUint8 && Width <= S3BootScriptWidthFillUint64) { + *BufferStride = 0; + } + + return EFI_SUCCESS; +} + +/** + Translates boot script to MDE library interface. + + @param[in] Width Width of the operation. + @param[in] Address Address of the operation. + @param[in] Count Count of the number of accesses to perform. + @param[out] Buffer Pointer to the buffer to read from I/O space. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + Address is outside the legal range of I/O ports. + +**/ +EFI_STATUS +ScriptIoRead ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN AddressStride; + UINTN BufferStride; + PTR Out; + + Out.Buf = (UINT8 *) Buffer; + + if (Address > MAX_IO_ADDRESS) { + return EFI_INVALID_PARAMETER; + } + + Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Loop for each iteration and move the data + // + for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) { + switch (Width) { + + case S3BootScriptWidthUint8: + case S3BootScriptWidthFifoUint8: + case S3BootScriptWidthFillUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8Read - 0x%08x\n", Address)); + *Out.Uint8 = IoRead8 ((UINTN) Address); + break; + + case S3BootScriptWidthUint16: + case S3BootScriptWidthFifoUint16: + case S3BootScriptWidthFillUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16Read - 0x%08x\n", Address)); + *Out.Uint16 = IoRead16 ((UINTN) Address); + break; + + case S3BootScriptWidthUint32: + case S3BootScriptWidthFifoUint32: + case S3BootScriptWidthFillUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32Read - 0x%08x\n", Address)); + *Out.Uint32 = IoRead32 ((UINTN) Address); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + + return EFI_SUCCESS; +} + +/** + Perform a write operation + + @param[in] Width Width of the operation. + @param[in] Address Address of the operation. + @param[in] Count Count of the number of accesses to perform. + @param[in] Buffer Pointer to the buffer to write to I/O space. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + Address is outside the legal range of I/O ports. + +**/ +EFI_STATUS +ScriptIoWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN AddressStride; + UINTN BufferStride; + UINT64 OriginalAddress; + PTR In; + PTR OriginalIn; + + In.Buf = (UINT8 *) Buffer; + + if (Address > MAX_IO_ADDRESS) { + return EFI_INVALID_PARAMETER; + } + + Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Loop for each iteration and move the data + // + OriginalAddress = Address; + OriginalIn.Buf = In.Buf; + for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) { + switch (Width) { + case S3BootScriptWidthUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8)); + IoWrite8 ((UINTN) Address, *In.Uint8); + break; + case S3BootScriptWidthFifoUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8)); + IoWrite8 ((UINTN) OriginalAddress, *In.Uint8); + break; + case S3BootScriptWidthFillUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8)); + IoWrite8 ((UINTN) Address, *OriginalIn.Uint8); + break; + case S3BootScriptWidthUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16)); + IoWrite16 ((UINTN) Address, *In.Uint16); + break; + case S3BootScriptWidthFifoUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16)); + IoWrite16 ((UINTN) OriginalAddress, *In.Uint16); + break; + case S3BootScriptWidthFillUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16)); + IoWrite16 ((UINTN) Address, *OriginalIn.Uint16); + break; + case S3BootScriptWidthUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32)); + IoWrite32 ((UINTN) Address, *In.Uint32); + break; + case S3BootScriptWidthFifoUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32)); + IoWrite32 ((UINTN) OriginalAddress, *In.Uint32); + break; + case S3BootScriptWidthFillUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32)); + IoWrite32 ((UINTN) Address, *OriginalIn.Uint32); + break; + case S3BootScriptWidthUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64)); + IoWrite64 ((UINTN) Address, *In.Uint64); + break; + case S3BootScriptWidthFifoUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64)); + IoWrite64 ((UINTN) OriginalAddress, *In.Uint64); + break; + case S3BootScriptWidthFillUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64)); + IoWrite64 ((UINTN) Address, *OriginalIn.Uint64); + break; + default: + return EFI_INVALID_PARAMETER; + } + } + + + return EFI_SUCCESS; +} +/** + Interprete the IO write entry in S3 boot script and perform the write operation + + @param Script Pointer to the node which is to be interpreted. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + Address is outside the legal range of I/O ports. + +**/ +EFI_STATUS +BootScriptExecuteIoWrite ( + IN UINT8 *Script + ) +{ + S3_BOOT_SCRIPT_LIB_WIDTH Width; + UINT64 Address; + UINTN Count; + VOID *Buffer; + EFI_BOOT_SCRIPT_IO_WRITE IoWrite; + + CopyMem ((VOID*)&IoWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_WRITE)); + Width = (S3_BOOT_SCRIPT_LIB_WIDTH) IoWrite.Width; + Address = IoWrite.Address; + Count = IoWrite.Count; + Buffer = Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE); + + return ScriptIoWrite(Width, Address, Count, Buffer); +} +/** + Perform memory read operation + + @param Width Width of the operation. + @param Address Address of the operation. + @param Count Count of the number of accesses to perform. + @param Buffer Pointer to the buffer read from memory. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count + is not valid for this EFI System. + +**/ +EFI_STATUS +ScriptMemoryRead ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN AddressStride; + UINTN BufferStride; + PTR Out; + + Out.Buf = Buffer; + + Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Loop for each iteration and move the data + // + for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) { + switch (Width) { + case S3BootScriptWidthUint8: + case S3BootScriptWidthFifoUint8: + case S3BootScriptWidthFillUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", (UINTN)Address)); + *Out.Uint8 = MmioRead8 ((UINTN) Address); + break; + + case S3BootScriptWidthUint16: + case S3BootScriptWidthFifoUint16: + case S3BootScriptWidthFillUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", (UINTN)Address)); + *Out.Uint16 = MmioRead16 ((UINTN) Address); + break; + + case S3BootScriptWidthUint32: + case S3BootScriptWidthFifoUint32: + case S3BootScriptWidthFillUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", (UINTN)Address)); + *Out.Uint32 = MmioRead32 ((UINTN) Address); + break; + + case S3BootScriptWidthUint64: + case S3BootScriptWidthFifoUint64: + case S3BootScriptWidthFillUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x\n", (UINTN)Address)); + *Out.Uint64 = MmioRead64 ((UINTN) Address); + break; + + default: + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} +/** + Translates boot script to MDE library interface. + + @param Width Width of the operation. + @param Address Address of the operation. + @param Count Count of the number of accesses to perform. + @param Buffer Pointer to the buffer write to memory. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count + is not valid for this EFI System. + +**/ +EFI_STATUS +ScriptMemoryWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN AddressStride; + UINT64 OriginalAddress; + UINTN BufferStride; + PTR In; + PTR OriginalIn; + + In.Buf = Buffer; + + Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Loop for each iteration and move the data + // + OriginalAddress = Address; + OriginalIn.Buf = In.Buf; + for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) { + switch (Width) { + case S3BootScriptWidthUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8)); + MmioWrite8 ((UINTN) Address, *In.Uint8); + break; + case S3BootScriptWidthFifoUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8)); + MmioWrite8 ((UINTN) OriginalAddress, *In.Uint8); + break; + case S3BootScriptWidthFillUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8)); + MmioWrite8 ((UINTN) Address, *OriginalIn.Uint8); + break; + case S3BootScriptWidthUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16)); + MmioWrite16 ((UINTN) Address, *In.Uint16); + break; + case S3BootScriptWidthFifoUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16)); + MmioWrite16 ((UINTN) OriginalAddress, *In.Uint16); + break; + case S3BootScriptWidthFillUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16)); + MmioWrite16 ((UINTN) Address, *OriginalIn.Uint16); + break; + case S3BootScriptWidthUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32)); + MmioWrite32 ((UINTN) Address, *In.Uint32); + break; + case S3BootScriptWidthFifoUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32)); + MmioWrite32 ((UINTN) OriginalAddress, *In.Uint32); + break; + case S3BootScriptWidthFillUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32)); + MmioWrite32 ((UINTN) Address, *OriginalIn.Uint32); + break; + case S3BootScriptWidthUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64)); + MmioWrite64 ((UINTN) Address, *In.Uint64); + break; + case S3BootScriptWidthFifoUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)OriginalAddress, *In.Uint64)); + MmioWrite64 ((UINTN) OriginalAddress, *In.Uint64); + break; + case S3BootScriptWidthFillUint64: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64)); + MmioWrite64 ((UINTN) Address, *OriginalIn.Uint64); + break; + default: + return EFI_UNSUPPORTED; + } + } + return EFI_SUCCESS; +} +/** + Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_WRITE OP code. + + @param[in] Script Pointer to the node which is to be interpreted. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count + is not valid for this EFI System. + +**/ +EFI_STATUS +BootScriptExecuteMemoryWrite ( + IN UINT8 *Script + ) +{ + VOID *Buffer; + S3_BOOT_SCRIPT_LIB_WIDTH Width; + UINT64 Address; + UINTN Count; + EFI_BOOT_SCRIPT_MEM_WRITE MemWrite; + + CopyMem((VOID*)&MemWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE)); + Width = (S3_BOOT_SCRIPT_LIB_WIDTH)MemWrite.Width; + Address = MemWrite.Address; + Count = MemWrite.Count; + Buffer = Script + sizeof(EFI_BOOT_SCRIPT_MEM_WRITE); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)Address, (UINTN)Count, (UINTN)Width)); + return ScriptMemoryWrite (Width,Address, Count, Buffer); + +} +/** + Translates boot script to MDE library interface for PCI configuration read operation + + @param Width Width of the operation. + @param Address Address of the operation. + @param Buffer Pointer to the buffer reaf from PCI config space + + @retval EFI_SUCCESS The read succeed. + @retval EFI_INVALID_PARAMETER if Width is not defined + +**/ +EFI_STATUS +ScriptPciCfgRead ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + OUT VOID *Buffer + ) +{ + switch (Width) { + case S3BootScriptWidthUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%016lx\n", Address)); + * (UINT8 *) Buffer = PciRead8 (PCI_ADDRESS_ENCODE(Address)); + break; + + case S3BootScriptWidthUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%016lx\n", Address)); + * (UINT16 *) Buffer = PciRead16 (PCI_ADDRESS_ENCODE(Address)); + break; + + case S3BootScriptWidthUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%016lx\n", Address)); + * (UINT32 *) Buffer = PciRead32 (PCI_ADDRESS_ENCODE(Address)); + break; + + default: + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +/** + Translates boot script to MDE library interface for PCI configuration write operation + + @param Width Width of the operation. + @param Address Address of the operation. + @param Buffer Pointer to the buffer reaf from PCI config space + + @retval EFI_SUCCESS The write succeed. + @retval EFI_INVALID_PARAMETER if Width is not defined + +**/ +EFI_STATUS +ScriptPciCfgWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + OUT VOID *Buffer + ) +{ + switch (Width) { + case S3BootScriptWidthUint8: + case S3BootScriptWidthFifoUint8: + case S3BootScriptWidthFillUint8: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%016lx (0x%02x)\n", Address, (UINTN)*(UINT8 *) Buffer)); + PciWrite8 (PCI_ADDRESS_ENCODE(Address), *(UINT8 *) Buffer); + break; + case S3BootScriptWidthUint16: + case S3BootScriptWidthFifoUint16: + case S3BootScriptWidthFillUint16: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%016lx (0x%04x)\n", Address, (UINTN)*(UINT16 *) Buffer)); + PciWrite16 (PCI_ADDRESS_ENCODE(Address), *(UINT16 *) Buffer); + break; + case S3BootScriptWidthUint32: + case S3BootScriptWidthFifoUint32: + case S3BootScriptWidthFillUint32: + DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%016lx (0x%08x)\n", Address, (UINTN)*(UINT32 *) Buffer)); + PciWrite32 (PCI_ADDRESS_ENCODE(Address), *(UINT32 *) Buffer); + break; + default: + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} +/** + Perform pci configure 2 read operation. + + @param Width Width of the operation. + @param Segment Pci segment number + @param Address Address of the operation. + @param Buffer Pointer to the buffer to write to I/O space. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + Address is outside the legal range of I/O ports. + @note A known Limitations in the implementation which is the 'Segment' parameter is assumed as + Zero, or else, assert. +**/ +EFI_STATUS +ScriptPciCfg2Read ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT16 Segment, + IN UINT64 Address, + OUT VOID *Buffer + ) +{ + ASSERT (Segment==0); + + return ScriptPciCfgRead (Width, Address, Buffer); +} +/** + Perform pci configure write operation. + + @param Width Width of the operation. + @param Segment Pci segment number + @param Address Address of the operation. + @param Buffer Pointer to the buffer to write to I/O space. + + @retval EFI_SUCCESS The data was written to the EFI System. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System. + Buffer is NULL. + The Buffer is not aligned for the given Width. + Address is outside the legal range of I/O ports. + @note A known Limitations in the implementation which is the 'Segment' parameter is assumed as + Zero, or else, assert. + +**/ +EFI_STATUS +EFIAPI +ScriptPciCfg2Write ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT16 Segment, + IN UINT64 Address, + OUT VOID *Buffer + ) +{ + ASSERT (Segment==0); + return ScriptPciCfgWrite (Width, Address, Buffer); +} +/** + Perform Pci configuration Write operation. + + @param Script The pointer of typed node in boot script table + + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecutePciCfgWrite ( + IN UINT8 *Script + ) +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINTN DataWidth; + UINTN Index; + UINT64 PciAddress; + UINT8 Reg; + EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE PciConfigWrite; + + CopyMem ((VOID*)&PciConfigWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)); + Status = EFI_SUCCESS; + + PciAddress = PciConfigWrite.Address; + DataWidth = (UINT32)(0x01 << (PciConfigWrite.Width)); + Buffer = Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE); + + DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)PciAddress, (UINTN)PciConfigWrite.Count, (UINTN)DataWidth)); + + for (Index = 0; Index < PciConfigWrite.Count; Index++) { + Status = ScriptPciCfgWrite ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciConfigWrite.Width, + PciAddress, + Buffer + ); + + if ( S3BootScriptWidthFillUint8 != PciConfigWrite.Width || + S3BootScriptWidthFillUint16 != PciConfigWrite.Width || + S3BootScriptWidthFillUint32 != PciConfigWrite.Width || + S3BootScriptWidthFillUint64 != PciConfigWrite.Width){ + Reg = (UINT8) ((UINT8) PciAddress + DataWidth); + PciAddress = (PciAddress & 0xFFFFFFFFFFFFFF00ULL) + Reg; + } + + if (S3BootScriptWidthFifoUint8 != PciConfigWrite.Width || + S3BootScriptWidthFifoUint16 != PciConfigWrite.Width || + S3BootScriptWidthFifoUint32 != PciConfigWrite.Width || + S3BootScriptWidthFifoUint64 != PciConfigWrite.Width) { + Buffer += DataWidth; + } + } + + return Status; +} +/** + Excute the script to perform IO modification operation. + + @param Script The pointer of typed node in boot script table + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteIoReadWrite ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) + +{ + EFI_STATUS Status; + UINT64 Data; + EFI_BOOT_SCRIPT_IO_READ_WRITE IoReadWrite; + + Data = 0; + + CopyMem((VOID*)&IoReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteIoReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)IoReadWrite.Address, (UINT64)AndMask, (UINT64)OrMask)); + + Status = ScriptIoRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width, + IoReadWrite.Address, + 1, + &Data + ); + if (!EFI_ERROR (Status)) { + Data = (Data & AndMask) | OrMask; + Status = ScriptIoWrite ( + (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width, + IoReadWrite.Address, + 1, + &Data + ); + } + return Status; +} +/** + Excute the script to perform memory modification operation. + + @param Script The pointer of typed node in boot script table + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteMemoryReadWrite ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) + +{ + EFI_STATUS Status; + UINT64 Data; + EFI_BOOT_SCRIPT_MEM_READ_WRITE MemReadWrite; + + Data = 0; + + CopyMem((VOID*)&MemReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_READ_WRITE)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)MemReadWrite.Address, (UINT64)AndMask, (UINT64)OrMask)); + + Status = ScriptMemoryRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width, + MemReadWrite.Address, + 1, + &Data + ); + if (!EFI_ERROR (Status)) { + Data = (Data & AndMask) | OrMask; + Status = ScriptMemoryWrite ( + (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width, + MemReadWrite.Address, + 1, + &Data + ); + } + return Status; +} +/** + Excute the script to perform PCI IO modification operation. + + @param Script The pointer of typed node in boot script table + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecutePciCfgReadWrite ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) + +{ + EFI_STATUS Status; + UINT64 Data; + EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE PciCfgReadWrite; + + CopyMem((VOID*)&PciCfgReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)); + + DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)PciCfgReadWrite.Address, (UINT64)AndMask, (UINT64)OrMask)); + + Status = ScriptPciCfgRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width, + PciCfgReadWrite.Address, + &Data + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Data = (Data & AndMask) | OrMask; + + Status = ScriptPciCfgWrite ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width, + PciCfgReadWrite.Address, + &Data + ); + + return Status; +} +/** + To Execute SMBUS command. + + @param Script The pointer of typed node in boot script table + + @retval EFI_SUCCESS The operation was executed successfully + @retval EFI_UNSUPPORTED Cannot locate smbus ppi or occur error of script execution + @retval Others Result of script execution +**/ +EFI_STATUS +BootScriptExecuteSmbusExecute ( + IN UINT8 *Script + ) +{ + UINTN SmBusAddress; + UINTN DataSize; + EFI_BOOT_SCRIPT_SMBUS_EXECUTE SmbusExecuteEntry; + + CopyMem ((VOID*)&SmbusExecuteEntry, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_SMBUS_EXECUTE )); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteSmbusExecute - 0x%08x, 0x%08x\n", (UINTN)SmbusExecuteEntry.SmBusAddress, (UINTN)SmbusExecuteEntry.Operation)); + + SmBusAddress = (UINTN)SmbusExecuteEntry.SmBusAddress; + DataSize = (UINTN) SmbusExecuteEntry.DataSize; + return SmbusExecute ( + SmBusAddress, + (EFI_SMBUS_OPERATION) SmbusExecuteEntry.Operation, + &DataSize, + Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + ); +} +/** + Execute stall operation in boot script table. + + @param Script The pointer of typed node in boot script table + + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteStall ( + IN UINT8 *Script + ) +{ + EFI_BOOT_SCRIPT_STALL Stall; + + CopyMem ((VOID*)&Stall, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_STALL)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteStall - 0x%08x\n", (UINTN)Stall.Duration)); + + MicroSecondDelay ((UINTN) Stall.Duration); + return EFI_SUCCESS; +} +/** + To execute assigned function. + + @param Script The pointer of typed node in boot script table + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteDispatch ( + IN UINT8 *Script + ) +{ + EFI_STATUS Status; + DISPATCH_ENTRYPOINT_FUNC EntryFunc; + EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch; + + CopyMem ((VOID*)&ScriptDispatch, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH)); + EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch.EntryPoint); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch - 0x%08x\n", (UINTN)ScriptDispatch.EntryPoint)); + + Status = EntryFunc (NULL, NULL); + + return Status; +} +/** + Execute dispach2 opertion code which is to invoke a spcified function with one parameter. + + @param Script The pointer of typed node in boot script table + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteDispatch2 ( + IN UINT8 *Script + ) +{ + EFI_STATUS Status; + DISPATCH_ENTRYPOINT_FUNC EntryFunc; + EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2; + + CopyMem ((VOID*)&ScriptDispatch2, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH_2)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch2 - 0x%08x(0x%08x)\n", (UINTN)ScriptDispatch2.EntryPoint, (UINTN)ScriptDispatch2.Context)); + + EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch2.EntryPoint); + + Status = EntryFunc (NULL, (VOID *) (UINTN) ScriptDispatch2.Context); + + return Status; +} +/** + Excute the script to poll memory. + + @param Script The pointer of typed node in boot script table + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_DEVICE_ERROR Data polled from memory does not equal to + the epecting data within the Loop Times. + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteMemPoll ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) +{ + + UINT64 Data; + UINT64 LoopTimes; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_MEM_POLL MemPoll; + + CopyMem ((VOID*)&MemPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_POLL)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteMemPoll - 0x%08x\n", (UINTN)MemPoll.Address)); + + Data = 0; + Status = ScriptMemoryRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width, + MemPoll.Address, + 1, + &Data + ); + if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + + for (LoopTimes = 0; LoopTimes < MemPoll.LoopTimes; LoopTimes++) { + NanoSecondDelay ((UINTN)MemPoll.Duration); + + Data = 0; + Status = ScriptMemoryRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width, + MemPoll.Address, + 1, + &Data + ); + if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + } + + if (LoopTimes < MemPoll.LoopTimes) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } +} +/** + Execute the boot script to interpret the Store arbitrary information. + This opcode is a no-op on dispatch and is only used for debugging script issues. + + @param Script The pointer of node in boot script table + +**/ +VOID +BootScriptExecuteInformation ( + IN UINT8 *Script + ) + +{ + UINT8 Index; + for (Index = 0; Index < 10; Index++); +} +/** + calculate the mask value for 'and' and 'or' operation + @param ScriptHeader The pointer of header of node in boot script table + @param AndMask The Mask value for 'and' operation + @param OrMask The Mask value for 'or' operation + @param Script Pointer to the entry. + +**/ +VOID +CheckAndOrMask ( + IN EFI_BOOT_SCRIPT_COMMON_HEADER *ScriptHeader, + OUT UINT64 *AndMask, + OUT UINT64 *OrMask, + IN UINT8 *Script + ) +{ + UINT8 *DataPtr; + UINTN Size; + + switch (ScriptHeader->OpCode) { + case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE); + break; + + case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE); + break; + case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_MEM_POLL); + break; + + case EFI_BOOT_SCRIPT_IO_POLL_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_IO_POLL); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE: + Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL); + break; + + default: + return; + } + + DataPtr = Script + Size; + + switch (ScriptHeader->Width) { + case S3BootScriptWidthUint8: + *AndMask = (UINT64) *(DataPtr + 1); + *OrMask = (UINT64) (*DataPtr); + break; + + case S3BootScriptWidthUint16: + *AndMask = (UINT64) (*(UINT16 *) (DataPtr + 2)); + *OrMask = (UINT64) (*(UINT16 *) DataPtr); + break; + + case S3BootScriptWidthUint32: + *AndMask = (UINT64) (*(UINT32 *) (DataPtr + 4)); + *OrMask = (UINT64) (*(UINT32 *) DataPtr); + break; + + case S3BootScriptWidthUint64: + *AndMask = (UINT64) (*(UINT64 *) (DataPtr + 8)); + *OrMask = (UINT64) (*(UINT64 *) DataPtr); + break; + + default: + break; + } + + return; +} +/** + Excute the script to poll Io port for some time + + @param Script The pointer of typed node in boot script table + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_DEVICE_ERROR Data polled from memory does not equal to + the epecting data within the Loop Times. + @retval EFI_SUCCESS The operation was executed successfully +**/ +EFI_STATUS +BootScriptExecuteIoPoll ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 LoopTimes; + EFI_BOOT_SCRIPT_IO_POLL IoPoll; + + CopyMem ((VOID*)&IoPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_POLL)); + + DEBUG ((EFI_D_INFO, "BootScriptExecuteIoPoll - 0x%08x\n", (UINTN)IoPoll.Address)); + + Data = 0; + Status = ScriptIoRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width, + IoPoll.Address, + 1, + &Data + ); + if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + for (LoopTimes = 0; LoopTimes < IoPoll.Delay; LoopTimes++) { + NanoSecondDelay (100); + Data = 0; + Status = ScriptIoRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width, + IoPoll.Address, + 1, + &Data + ); + if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + } + + if (LoopTimes < IoPoll.Delay) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } +} +/** + Perform Pci configuration Write operation. + + @param Script The pointer of S3 boot script + + @retval EFI_SUCCESS The operation was executed successfully + +**/ +EFI_STATUS +BootScriptExecutePciCfg2Write ( + IN UINT8 *Script + ) +{ + UINT8 Reg; + UINT8 *Buffer; + UINTN DataWidth; + UINTN Index; + UINT16 Segment; + UINT64 PciAddress; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE PciCfg2Write; + + CopyMem ((VOID*)&PciCfg2Write, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)); + Status = EFI_SUCCESS; + Segment = PciCfg2Write.Segment; + PciAddress = PciCfg2Write.Address; + DataWidth = (UINT32)(0x01 << (PciCfg2Write.Width)); + Buffer = Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE); + + DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2Write - 0x%08x\n", (UINTN)PciAddress)); + + for (Index = 0; Index < PciCfg2Write.Count; Index++) { + Status = ScriptPciCfg2Write ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Write.Width, + Segment, + PciAddress, + Buffer + ); + if (S3BootScriptWidthFillUint8 != PciCfg2Write.Width || + S3BootScriptWidthFillUint16 != PciCfg2Write.Width || + S3BootScriptWidthFillUint32 != PciCfg2Write.Width || + S3BootScriptWidthFillUint64 != PciCfg2Write.Width){ + Reg = (UINT8) ((UINT8) PciAddress + DataWidth); + PciAddress = (PciAddress & 0xFFFFFFFFFFFFFF00ULL) + Reg; + } + + if (S3BootScriptWidthFifoUint8 != PciCfg2Write.Width || + S3BootScriptWidthFifoUint16 != PciCfg2Write.Width || + S3BootScriptWidthFifoUint32 != PciCfg2Write.Width || + S3BootScriptWidthFifoUint64 != PciCfg2Write.Width) { + Buffer += DataWidth; + } + } + return Status; +} + + +/** + Perform pci configuration read & Write operation. + + @param Script The pointer of S3 boot script + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully + +**/ +EFI_STATUS +BootScriptExecutePciCfg2ReadWrite ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) +{ + UINT64 Data; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE PciCfg2ReadWrite; + CopyMem ((VOID*)&PciCfg2ReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)); + + DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2ReadWrite - 0x%08x\n", (UINTN)PciCfg2ReadWrite.Address)); + + Status = ScriptPciCfg2Read ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width, + PciCfg2ReadWrite.Segment, + PciCfg2ReadWrite.Address, + &Data + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Data = (Data & AndMask) | OrMask; + Status = ScriptPciCfg2Write ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width, + PciCfg2ReadWrite.Segment, + PciCfg2ReadWrite.Address, + &Data + ); + return Status; +} +/** + To perform poll pci configure operation. + + @param Script The pointer of S3 boot script + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully + @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to + epecting data within the Loop Times. +**/ +EFI_STATUS +BootScriptPciCfgPoll ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) +{ + UINT64 Data; + UINT64 LoopTimes; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_PCI_CONFIG_POLL PciCfgPoll; + CopyMem ((VOID*)&PciCfgPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)); + + DEBUG ((EFI_D_INFO, "BootScriptPciCfgPoll - 0x%08x\n", (UINTN)PciCfgPoll.Address)); + + Data = 0; + Status = ScriptPciCfgRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width, + PciCfgPoll.Address, + &Data + ); + if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + + for (LoopTimes = 0; LoopTimes < PciCfgPoll.Delay; LoopTimes++) { + NanoSecondDelay (100); + Data = 0; + Status = ScriptPciCfgRead ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width, + PciCfgPoll.Address, + &Data + ); + if ((!EFI_ERROR (Status)) && + (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + } + + if (LoopTimes < PciCfgPoll.Delay) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } +} + +/** + To perform poll pci configure operation. + + @param Script The pointer of S3 Boot Script + @param AndMask Mask value for 'and' operation + @param OrMask Mask value for 'or' operation + + @retval EFI_SUCCESS The operation was executed successfully + @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to + epecting data within the Loop Times. + +**/ +EFI_STATUS +BootScriptPciCfg2Poll ( + IN UINT8 *Script, + IN UINT64 AndMask, + IN UINT64 OrMask + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 LoopTimes; + EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL PciCfg2Poll; + + Data = 0; + CopyMem ((VOID*)&PciCfg2Poll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)); + + DEBUG ((EFI_D_INFO, "BootScriptPciCfg2Poll - 0x%08x\n", (UINTN)PciCfg2Poll.Address)); + + Status = ScriptPciCfg2Read ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width, + PciCfg2Poll.Segment, + PciCfg2Poll.Address, + &Data + ); + if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + + for (LoopTimes = 0; LoopTimes < PciCfg2Poll.Delay; LoopTimes++) { + NanoSecondDelay (100); + + Data = 0; + Status = ScriptPciCfg2Read ( + (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width, + PciCfg2Poll.Segment, + PciCfg2Poll.Address, + &Data + ); + if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) { + return EFI_SUCCESS; + } + } + + if (LoopTimes < PciCfg2Poll.Delay) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } + +} + +/** + Executes the S3 boot script table. + + @retval RETURN_SUCCESS The boot script table was executed successfully. + @retval RETURN_UNSUPPORTED Invalid script table or opcode. + + @note A known Limitations in the implementation: When interpreting the opcode EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE + EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE and EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE, the 'Segment' parameter is assumed as + Zero, or else, assert. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptExecute ( + VOID + ) +{ + EFI_STATUS Status; + UINT8* Script; + UINTN StartAddress; + UINT32 TableLength; + UINT64 AndMask; + UINT64 OrMask; + EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader; + EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader; + Script = mS3BootScriptTablePtr->TableBase; + if (Script != 0) { + CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); + } else { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((EFI_D_INFO, "S3BootScriptExecute:\n")); + if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) { + return EFI_UNSUPPORTED; + } + + DEBUG ((EFI_D_INFO, "TableHeader - 0x%08x\n", Script)); + + StartAddress = (UINTN) Script; + TableLength = TableHeader.TableLength; + Script = Script + TableHeader.Length; + Status = EFI_SUCCESS; + AndMask = 0; + OrMask = 0; + + DEBUG ((EFI_D_INFO, "TableHeader.TableLength - 0x%08x\n", (UINTN)TableLength)); + + while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) { + DEBUG ((EFI_D_INFO, "ExecuteBootScript - %08x\n", (UINTN)Script)); + + CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); + switch (ScriptHeader.OpCode) { + + case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE\n")); + Status = BootScriptExecuteMemoryWrite (Script); + break; + + case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecuteMemoryReadWrite ( + Script, + AndMask, + OrMask + ); + break; + + case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_WRITE_OPCODE\n")); + Status = BootScriptExecuteIoWrite (Script); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE\n")); + Status = BootScriptExecutePciCfgWrite (Script); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecutePciCfgReadWrite ( + Script, + AndMask, + OrMask + ); + break; + case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE\n")); + Status = BootScriptExecutePciCfg2Write (Script); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecutePciCfg2ReadWrite ( + Script, + AndMask, + OrMask + ); + break; + case EFI_BOOT_SCRIPT_DISPATCH_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_OPCODE\n")); + Status = BootScriptExecuteDispatch (Script); + break; + + case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE\n")); + Status = BootScriptExecuteDispatch2 (Script); + break; + + case EFI_BOOT_SCRIPT_INFORMATION_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_INFORMATION_OPCODE\n")); + BootScriptExecuteInformation (Script); + break; + + case S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE: + DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE\n")); + return EFI_SUCCESS; + + case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecuteIoReadWrite ( + Script, + AndMask, + OrMask + ); + break; + + case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE\n")); + Status = BootScriptExecuteSmbusExecute (Script); + break; + + case EFI_BOOT_SCRIPT_STALL_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_STALL_OPCODE\n")); + Status = BootScriptExecuteStall (Script); + break; + + case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_POLL_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecuteMemPoll (Script, AndMask, OrMask); + + break; + + case EFI_BOOT_SCRIPT_IO_POLL_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_POLL_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptExecuteIoPoll (Script, AndMask, OrMask); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptPciCfgPoll (Script, AndMask, OrMask); + break; + + case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE: + DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE\n")); + CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script); + Status = BootScriptPciCfg2Poll (Script, AndMask, OrMask); + break; + + case S3_BOOT_SCRIPT_LIB_LABEL_OPCODE: + // + // For label + // + DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_LABEL_OPCODE\n")); + break; + default: + DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", EFI_UNSUPPORTED)); + return EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status)); + return Status; + } + + Script = Script + ScriptHeader.Length; + } + + DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status)); + + return Status; +} + diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h new file mode 100644 index 0000000000..6edb11adf3 --- /dev/null +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h @@ -0,0 +1,186 @@ +/** @file + This file declares the internal Framework Boot Script format used by + the PI implementation of Script Saver and Executor. + + Copyright (c) 2006, 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_INTERNAL_FORMAT_H_ +#define _BOOT_SCRIPT_INTERNAL_FORMAT_H_ + +#pragma pack(1) + +// +// Boot Script Opcode Header Structure Definitions +// + +typedef struct { + UINT16 OpCode; + UINT8 Length; +} EFI_BOOT_SCRIPT_GENERIC_HEADER; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT16 Version; + UINT32 TableLength; + UINT16 Reserved[2]; +} EFI_BOOT_SCRIPT_TABLE_HEADER; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; +} EFI_BOOT_SCRIPT_COMMON_HEADER; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT32 Count; + UINT64 Address; +} EFI_BOOT_SCRIPT_IO_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; +} EFI_BOOT_SCRIPT_IO_READ_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT32 Count; + UINT64 Address; +} EFI_BOOT_SCRIPT_MEM_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; +} EFI_BOOT_SCRIPT_MEM_READ_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT32 Count; + UINT64 Address; +} EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT32 Count; + UINT64 Address; + UINT16 Segment; +} EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; +} EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; + UINT16 Segment; +} EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT64 SmBusAddress; + UINT32 Operation; + UINT32 DataSize; +} EFI_BOOT_SCRIPT_SMBUS_EXECUTE; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT64 Duration; +} EFI_BOOT_SCRIPT_STALL; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + EFI_PHYSICAL_ADDRESS EntryPoint; +} EFI_BOOT_SCRIPT_DISPATCH; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + EFI_PHYSICAL_ADDRESS EntryPoint; + EFI_PHYSICAL_ADDRESS Context; +} EFI_BOOT_SCRIPT_DISPATCH_2; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; + UINT64 Duration; + UINT64 LoopTimes; +} EFI_BOOT_SCRIPT_MEM_POLL; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 InformationLength; + EFI_PHYSICAL_ADDRESS Information; +} EFI_BOOT_SCRIPT_INFORMATION; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; + UINT64 Delay; +} EFI_BOOT_SCRIPT_IO_POLL; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; + UINT64 Delay; +} EFI_BOOT_SCRIPT_PCI_CONFIG_POLL; + +typedef struct { + UINT16 OpCode; + UINT8 Length; + UINT32 Width; + UINT64 Address; + UINT16 Segment; + UINT64 Delay; +} EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL; + +typedef struct { + UINT16 OpCode; + UINT8 Length; +} EFI_BOOT_SCRIPT_TERMINATE; + + +#pragma pack() + +#define BOOT_SCRIPT_NODE_MAX_LENGTH 1024 + +#endif diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c new file mode 100644 index 0000000000..8769509f76 --- /dev/null +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c @@ -0,0 +1,1852 @@ +/** @file + Save the S3 data to S3 boot script. + + Copyright (c) 2006 - 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 "InternalBootScriptLib.h" + +/** + + Data structure usage: + + +------------------------------+<-- PcdS3BootScriptTablePrivateDataPtr + | SCRIPT_TABLE_PRIVATE_DATA | + | TableBase |--- + | TableLength |--|-- + | AtRuntime | | | + | InSmm | | | + +------------------------------+ | | + | | + +------------------------------+<-- | + | EFI_BOOT_SCRIPT_TABLE_HEADER | | + | TableLength |----|-- + +------------------------------+ | | + | ...... | | | + +------------------------------+<---- | + | EFI_BOOT_SCRIPT_TERMINATE | | + +------------------------------+<------ + +**/ + +SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; +EFI_EVENT mEnterRuntimeEvent; +// +// Allocate local copy in SMM because we can not use mS3BootScriptTablePtr when we AtRuntime in InSmm. +// +SCRIPT_TABLE_PRIVATE_DATA mS3BootScriptTable; +UINTN mLockBoxLength; + +EFI_GUID mBootScriptDataGuid = { + 0xaea6b965, 0xdcf5, 0x4311, 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 +}; + +EFI_GUID mBootScriptHeaderDataGuid = { + 0x1810ab4a, 0x2314, 0x4df6, 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 +}; + +/** + This is an internal function to add a terminate node the entry, recalculate the table + length and fill into the table. + + @return the base address of the boot script tble. + **/ +UINT8* +S3BootScriptInternalCloseTable ( + VOID + ) +{ + UINT8 *S3TableBase; + EFI_BOOT_SCRIPT_TERMINATE ScriptTerminate; + EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo; + S3TableBase = mS3BootScriptTablePtr->TableBase; + + if (S3TableBase == NULL) { + // + // the table is not exist + // + return S3TableBase; + } + // + // Append the termination entry. + // + ScriptTerminate.OpCode = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE; + ScriptTerminate.Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE); + CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE)); + // + // fill the table length + // + ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase); + ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE); + + + + return S3TableBase; + // + // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to + // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). Because + // maybe in runtime, we still need add entries into the table, and the runtime entry should be + // added start before this TERMINATE node. + // +} + +/** + This function save boot script data to LockBox. + 1. BootSriptPrivate data, BootScript data - Image and DispatchContext are handled by platform. + 2. BootScriptExecutor, BootScriptExecutor context + - ACPI variable - (PI version) sould be handled by SMM driver. S3 Page table is handled here. + - ACPI variable - framework version is already handled by Framework CPU driver. +**/ +VOID +SaveBootScriptDataToLockBox ( + VOID + ) +{ + EFI_STATUS Status; + // + // mS3BootScriptTablePtr->TableLength does not include EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime. + // Save all info here, just in case that no one will add boot script entry in SMM. + // + Status = SaveLockBox ( + &mBootScriptDataGuid, + (VOID *)mS3BootScriptTablePtr->TableBase, + mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + // + // Just need save TableBase. + // Do not update other field because they will NOT be used in S3. + // + Status = SaveLockBox ( + &mBootScriptHeaderDataGuid, + (VOID *)&mS3BootScriptTablePtr->TableBase, + sizeof(mS3BootScriptTablePtr->TableBase) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptHeaderDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); +} + +/** + This is the Event call back function to notify the Library the system is entering + run time phase. + + @param Event Pointer to this event + @param Context Event hanlder private data + **/ +VOID +EFIAPI +S3BootScriptEventCallBack ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Interface; + + // + // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration. + // Just return if it is not found. + // + Status = gBS->LocateProtocol ( + &gEfiDxeSmmReadyToLockProtocolGuid, + NULL, + &Interface + ); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Here we should tell the library that we are enter into runtime phase. and + // the memory page number occupied by the table should not grow anymore. + // + if (!mS3BootScriptTablePtr->AtRuntime) { + // + // In boot time, we need not write the terminate node when adding a node to boot scipt table + // or else, that will impact the performance. However, in runtime, we should append terminate + // node on every add to boot script table + // + S3BootScriptInternalCloseTable (); + mS3BootScriptTablePtr->AtRuntime = TRUE; + + // + // Save BootScript data to lockbox + // + SaveBootScriptDataToLockBox (); + } +} +/** + This is the Event call back function is triggered in SMM to notify the Library the system is entering + run time phase and set InSmm flag. + + @param Protocol Points to the protocol's unique identifier + @param Interface Points to the interface instance + @param Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmEventCallback runs successfully + **/ +EFI_STATUS +EFIAPI +S3BootScriptSmmEventCallBack ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + // + // Check if it is already done + // + if (mS3BootScriptTablePtr == &mS3BootScriptTable) { + return EFI_SUCCESS; + } + + // + // Last chance to call-out, just make sure AtRuntime is set + // + S3BootScriptEventCallBack (NULL, NULL); + + // + // Save a local copy + // + CopyMem (&mS3BootScriptTable, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr)); + // + // We should not use ACPINvs copy, because it is not safe. + // + mS3BootScriptTablePtr = &mS3BootScriptTable; + + // + // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. + // InSmm will only be checked if AtRuntime is TRUE. + // + mS3BootScriptTablePtr->InSmm = TRUE; + + // + // Record LockBoxLength + // + mLockBoxLength = mS3BootScriptTable.TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE); + + return EFI_SUCCESS; +} + +/** + Library Constructor. + this function just identify it is a smm driver or non-smm driver linked against + with the library + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval RETURN_SUCCESS Allocate the global memory space to store S3 boot script table private data + @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptLibInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SCRIPT_TABLE_PRIVATE_DATA *S3TablePtr; + VOID *Registration; + EFI_SMM_BASE2_PROTOCOL *SmmBase2; + BOOLEAN InSmm; + EFI_SMM_SYSTEM_TABLE2 *Smst; + EFI_PHYSICAL_ADDRESS Buffer; + + S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr); + // + // The Boot script private data is not be initialized. create it + // + if (S3TablePtr == 0) { + Buffer = SIZE_4GB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)), + &Buffer + ); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + S3TablePtr = (VOID *) (UINTN) Buffer; + + PcdSet64 (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr); + ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); + // + // create event to notify the library system enter the runtime phase + // + mEnterRuntimeEvent = EfiCreateProtocolNotifyEvent ( + &gEfiDxeSmmReadyToLockProtocolGuid, + TPL_CALLBACK, + S3BootScriptEventCallBack, + NULL, + &Registration + ); + ASSERT (mEnterRuntimeEvent != NULL); + } + mS3BootScriptTablePtr = S3TablePtr; + + // + // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver. + // + Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + Status = SmmBase2->InSmm (SmmBase2, &InSmm); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + if (!InSmm) { + return RETURN_SUCCESS; + } + // + // Good, we are in SMM + // + Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + + // + // Then register event after lock + // + Registration = NULL; + Status = Smst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + S3BootScriptSmmEventCallBack, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + return RETURN_SUCCESS; +} +/** + To get the start address from which a new boot time s3 boot script entry will write into. + If the table is not exist, the functio will first allocate a buffer for the table + If the table buffer is not enough for the new entry, in non-smm mode, the funtion will + invoke reallocate to enlarge buffer. + + @param EntryLength the new entry length. + + @retval the address from which the a new s3 boot script entry will write into + **/ +UINT8* +S3BootScriptGetBootTimeEntryAddAddress ( + UINT8 EntryLength + ) +{ + EFI_PHYSICAL_ADDRESS S3TableBase; + EFI_PHYSICAL_ADDRESS NewS3TableBase; + UINT8 *NewEntryPtr; + UINT32 TableLength; + UINT16 PageNumber; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo; + + S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase); + if (S3TableBase == 0) { + // The table is not exist. This is the first to add entry. + // Allocate ACPI script table space under 4G memory. We need it to save + // some settings done by CSM, which runs after normal script table closed + // + S3TableBase = 0xffffffff; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), + (EFI_PHYSICAL_ADDRESS*)&S3TableBase + ); + + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + // + // Fill Table Header + // + ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase; + ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE; + ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER); + ScriptTableInfo->TableLength = 0; // will be calculate at CloseTable + mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER); + mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase; + mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); + } + + // Here we do not count the reserved memory for runtime script table. + PageNumber = (UINT16)(mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); + TableLength = mS3BootScriptTablePtr->TableLength; + if ((UINT32)(PageNumber * EFI_PAGE_SIZE) < (TableLength + EntryLength)) { + // + // The buffer is too small to hold the table, Reallocate the buffer + // + NewS3TableBase = 0xffffffff; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), + (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase + ); + + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + + CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength); + gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber); + + mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase; + mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); + } + // + // calculate the the start address for the new entry. + // + NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength; + + // + // update the table lenghth + // + mS3BootScriptTablePtr->TableLength = TableLength + EntryLength; + + // + // In the boot time, we will not append the termination entry to the boot script + // table until the callers think there is no boot time data that should be added and + // it is caller's responsibility to explicit call the CloseTable. + // + // + + return NewEntryPtr; +} +/** + To get the start address from which a new runtime s3 boot script entry will write into. + In this case, it should be ensured that there is enough buffer to hold the entry. + + @param EntryLength the new entry length. + + @retval the address from which the a new s3 runtime script entry will write into + **/ +UINT8* +S3BootScriptGetRuntimeEntryAddAddress ( + UINT8 EntryLength + ) +{ + UINT8 *NewEntryPtr; + + NewEntryPtr = NULL; + // + // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node. + // + if (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE) <= EFI_PAGES_TO_SIZE((UINT32)(mS3BootScriptTablePtr->TableMemoryPageNumber))) { + NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; + mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength; + // + // Append a terminate node on every insert + // + S3BootScriptInternalCloseTable (); + } + return (UINT8*)NewEntryPtr; +} +/** + To get the start address from which a new s3 boot script entry will write into. + + @param EntryLength the new entry length. + + @retval the address from which the a new s3 runtime script entry will write into + **/ +UINT8* +S3BootScriptGetEntryAddAddress ( + UINT8 EntryLength + ) +{ + UINT8* NewEntryPtr; + EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader; + EFI_STATUS Status; + + if (mS3BootScriptTablePtr->AtRuntime) { + // + // We need check InSmm when AtRuntime, because after SmmReadyToLock, only SMM driver is allowed to write boot script. + // + if (!mS3BootScriptTablePtr->InSmm) { + // + // Add DEBUG ERROR, so that we can find it at boot time. + // Do not use ASSERT, because we may have test invoke this interface. + // + DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script after ReadyToLock!!!\n")); + return NULL; + } + + // + // NOTE: OS will restore ACPINvs data. After S3, the table length in mS3BootScriptTable (SMM) is different with + // table length in BootScriptTable header (ACPINvs). + // So here we need sync them. We choose ACPINvs table length, because we want to override the boot script saved + // in SMM every time. + // + ASSERT (mS3BootScriptTablePtr == &mS3BootScriptTable); + CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); + if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) { + // + // Restore it to use original value + // + RestoreLockBox (&mBootScriptDataGuid, NULL, NULL); + // + // Copy it again to get original value + // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length. + // + mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)); + } + + NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength); + // + // Now the length field is updated, need sync to lockbox. + // So in S3 resume, the data can be restored correctly. + // + CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); + Status = UpdateLockBox ( + &mBootScriptDataGuid, + OFFSET_OF(EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), + &TableHeader.TableLength, + sizeof(TableHeader.TableLength) + ); + ASSERT_EFI_ERROR (Status); + } else { + NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength); + } + return NewEntryPtr; + +} + +/** + Sync BootScript LockBox data. +**/ +VOID +SyncBootScript ( + VOID + ) +{ + EFI_STATUS Status; + + if (!mS3BootScriptTablePtr->AtRuntime || !mS3BootScriptTablePtr->InSmm) { + return ; + } + // + // Update Terminate + // So in S3 resume, the data can be restored correctly. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE), + (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)), + sizeof(EFI_BOOT_SCRIPT_TERMINATE) + ); + ASSERT_EFI_ERROR (Status); +} + +/** + This is an function to close the S3 boot script table. The function could only be called in + BOOT time phase. To comply with the Framework spec definition on + EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things: + 1. Closes the specified boot script table + 2. It allocates a new memory pool to duplicate all the boot scripts in the specified table. + Once this function is called, the table maintained by the library will be destroyed + after it is copied into the allocated pool. + 3. Any attempts to add a script record after calling this function will cause a new table + to be created by the library. + 4. The base address of the allocated pool will be returned in Address. Note that after + using the boot script table, the CALLER is responsible for freeing the pool that is allocated + by this function. + + In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is + for Framework Spec compatibility. + + If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out + how to get the script to run on an S3 resume because the boot script maintained by the lib will be + destroyed. + + @return the base address of the new copy of the boot script tble. + @note this function could only called in boot time phase + +**/ +UINT8* +EFIAPI +S3BootScriptCloseTable ( + VOID + ) +{ + UINT8 *S3TableBase; + UINT32 TableLength; + UINT8 *Buffer; + EFI_STATUS Status; + EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo; + + S3TableBase = mS3BootScriptTablePtr->TableBase; + if (S3TableBase == 0) { + return 0; + } + // + // Append the termination record the S3 boot script table + // + S3BootScriptInternalCloseTable(); + TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE); + // + // Allocate the buffer and copy the boot script to the buffer. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + (UINTN)TableLength, + (VOID **) &Buffer + ); + if (EFI_ERROR (Status)) { + return 0; + } + CopyMem (Buffer, S3TableBase, TableLength); + + // + // Destroy the table maintained by the library so that the next write operation + // will write the record to the first entry of the table. + // + // Fill the table header. + ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase; + ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE; + ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER); + ScriptTableInfo->TableLength = 0; // will be calculate at close the table + + mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER); + return Buffer; +} +/** + Save I/O write to boot script + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The base address of the I/O operations. + @param Count The number of I/O operations to perform. + @param Buffer The source buffer from which to write data. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveIoWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) + +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_IO_WRITE ScriptIoWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // save script data + // + ScriptIoWrite.OpCode = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE; + ScriptIoWrite.Length = Length; + ScriptIoWrite.Width = Width; + ScriptIoWrite.Address = Address; + ScriptIoWrite.Count = (UINT32) Count; + CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count); + + SyncBootScript (); + + return RETURN_SUCCESS; +} + +/** + Adds a record for an I/O modify operation into a S3 boot script table + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The base address of the I/O operations. + @param Data A pointer to the data to be OR-ed. + @param DataMask A pointer to the data mask to be AND-ed with the data read from the register + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveIoReadWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE; + ScriptIoReadWrite.Length = Length; + ScriptIoReadWrite.Width = Width; + ScriptIoReadWrite.Address = Address; + + CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a memory write operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The base address of the memory operations + @param Count The number of memory operations to perform. + @param Buffer The source buffer from which to write the data. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveMemWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptMemWrite.OpCode = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE; + ScriptMemWrite.Length = Length; + ScriptMemWrite.Width = Width; + ScriptMemWrite.Address = Address; + ScriptMemWrite.Count = (UINT32) Count; + + CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a memory modify operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The base address of the memory operations. Address needs alignment if required + @param Data A pointer to the data to be OR-ed. + @param DataMask A pointer to the data mask to be AND-ed with the data read from the register. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveMemReadWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE; + ScriptMemReadWrite.Length = Length; + ScriptMemReadWrite.Width = Width; + ScriptMemReadWrite.Address = Address; + + CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a PCI configuration space write operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The address within the PCI configuration space. + @param Count The number of PCI operations to perform. + @param Buffer The source buffer from which to write the data. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePciCfgWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPciWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE; + ScriptPciWrite.Length = Length; + ScriptPciWrite.Width = Width; + ScriptPciWrite.Address = Address; + ScriptPciWrite.Count = (UINT32) Count; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a PCI configuration space modify operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Address The address within the PCI configuration space. + @param Data A pointer to the data to be OR-ed.The size depends on Width. + @param DataMask A pointer to the data mask to be AND-ed. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN__SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePciCfgReadWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE; + ScriptPciReadWrite.Length = Length; + ScriptPciReadWrite.Width = Width; + ScriptPciReadWrite.Address = Address; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte); + CopyMem ( + (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte), + DataMask, + WidthInByte + ); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a PCI configuration space modify operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Segment The PCI segment number for Address. + @param Address The address within the PCI configuration space. + @param Count The number of PCI operations to perform. + @param Buffer The source buffer from which to write the data. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePciCfg2Write ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT16 Segment, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPciWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE; + ScriptPciWrite2.Length = Length; + ScriptPciWrite2.Width = Width; + ScriptPciWrite2.Address = Address; + ScriptPciWrite2.Segment = Segment; + ScriptPciWrite2.Count = (UINT32)Count; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for a PCI configuration space modify operation into a specified boot script table. + + @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH. + @param Segment The PCI segment number for Address. + @param Address The address within the PCI configuration space. + @param Data A pointer to the data to be OR-ed. The size depends on Width. + @param DataMask A pointer to the data mask to be AND-ed. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePciCfg2ReadWrite ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT16 Segment, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE; + ScriptPciReadWrite2.Length = Length; + ScriptPciReadWrite2.Width = Width; + ScriptPciReadWrite2.Segment = Segment; + ScriptPciReadWrite2.Address = Address; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)); + CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte); + CopyMem ( + (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte), + DataMask, + WidthInByte + ); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for an SMBus command execution into a specified boot script table. + + @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC. + @param Operation Indicates which particular SMBus protocol it will use to execute the SMBus + transactions. + @param Length A pointer to signify the number of bytes that this operation will do. + @param Buffer Contains the value of data to execute to the SMBUS slave device. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveSmbusExecute ( + IN UINTN SmBusAddress, + IN EFI_SMBUS_OPERATION Operation, + IN UINTN *Length, + IN VOID *Buffer + ) +{ + UINT8 DataSize; + UINT8 *Script; + EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute; + + DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + (*Length)); + + Script = S3BootScriptGetEntryAddAddress (DataSize); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptSmbusExecute.OpCode = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE; + ScriptSmbusExecute.Length = DataSize; + ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress; + ScriptSmbusExecute.Operation = Operation; + ScriptSmbusExecute.DataSize = (UINT32) *Length; + + CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)); + CopyMem ( + (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)), + Buffer, + (*Length) + ); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for an execution stall on the processor into a specified boot script table. + + @param Duration Duration in microseconds of the stall + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveStall ( + IN UINTN Duration + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_STALL ScriptStall; + + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE; + ScriptStall.Length = Length; + ScriptStall.Duration = Duration; + + CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL)); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for an execution stall on the processor into a specified boot script table. + + @param EntryPoint Entry point of the code to be dispatched. + @param Context Argument to be passed into the EntryPoint of the code to be dispatched. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveDispatch2 ( + IN VOID *EntryPoint, + IN VOID *Context + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2; + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE; + ScriptDispatch2.Length = Length; + ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint; + ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context; + + CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2)); + + SyncBootScript (); + + return RETURN_SUCCESS; + +} +/** + Adds a record for memory reads of the memory location and continues when the exit criteria is + satisfied or after a defined duration. + + @param Width The width of the memory operations. + @param Address The base address of the memory operations. + @param BitMask A pointer to the bit mask to be AND-ed with the data read from the register. + @param BitValue A pointer to the data value after to be Masked. + @param Duration Duration in microseconds of the stall. + @param LoopTimes The times of the register polling. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveMemPoll ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *BitMask, + IN VOID *BitValue, + IN UINTN Duration, + IN UINTN LoopTimes + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE; + ScriptMemPoll.Length = Length; + ScriptMemPoll.Width = Width; + ScriptMemPoll.Address = Address; + ScriptMemPoll.Duration = Duration; + ScriptMemPoll.LoopTimes = LoopTimes; + + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte); + CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL)); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only + used for debugging script issues. + + @param InformationLength Length of the data in bytes + @param Information Information to be logged in the boot scrpit + + @retval RETURN_UNSUPPORTED If entering runtime, this method will not support. + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveInformation ( + IN UINT32 InformationLength, + IN VOID *Information + ) +{ + RETURN_STATUS Status; + UINT8 Length; + UINT8 *Script; + EFI_PHYSICAL_ADDRESS Buffer; + EFI_BOOT_SCRIPT_INFORMATION ScriptInformation; + + if (mS3BootScriptTablePtr->AtRuntime) { + return RETURN_UNSUPPORTED; + } + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION)); + + Buffer = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(InformationLength), + &Buffer + ); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptInformation.OpCode = EFI_BOOT_SCRIPT_INFORMATION_OPCODE; + ScriptInformation.Length = Length; + + + ScriptInformation.InformationLength = InformationLength; + + CopyMem ((VOID *)(UINTN)Buffer, Information,(UINTN) InformationLength); + ScriptInformation.Information = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer; + + CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION)); + return RETURN_SUCCESS; + +} +/** + Store a string in the boot script table. This opcode is a no-op on dispatch and is only + used for debugging script issues. + + @param String The string to save to boot script table + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveInformationAsciiString ( + IN CONST CHAR8 *String + ) +{ + return S3BootScriptSaveInformation ( + (UINT32) AsciiStrLen (String) + 1, + (VOID*) String + ); +} +/** + Adds a record for dispatching specified arbitrary code into a specified boot script table. + + @param EntryPoint Entry point of the code to be dispatched. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveDispatch ( + IN VOID *EntryPoint + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch; + + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE; + ScriptDispatch.Length = Length; + ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint; + + CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH)); + + SyncBootScript (); + + return RETURN_SUCCESS; + +} +/** + Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a + defined duration. + + @param Width The width of the I/O operations. + @param Address The base address of the I/O operations. + @param Data The comparison value used for the polling exit criteria. + @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero + in Data are ignored when polling the memory address. + @param Delay The number of 100ns units to poll. Note that timer available may be of poorer + granularity so the delay may be longer. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveIoPoll ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask, + IN UINT64 Delay + ) +{ + UINT8 WidthInByte; + UINT8 *Script; + UINT8 Length; + EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll; + + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE; + ScriptIoPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2)); + ScriptIoPoll.Width = Width; + ScriptIoPoll.Address = Address; + ScriptIoPoll.Delay = Delay; + + CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL)); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte); + + SyncBootScript (); + + return RETURN_SUCCESS; +} + +/** + Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or + after a defined duration. + + @param Width The width of the I/O operations. + @param Address The address within the PCI configuration space. + @param Data The comparison value used for the polling exit criteria. + @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero + in Data are ignored when polling the memory address + @param Delay The number of 100ns units to poll. Note that timer available may be of poorer + granularity so the delay may be longer. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePciPoll ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask, + IN UINT64 Delay +) +{ + UINT8 *Script; + UINT8 WidthInByte; + UINT8 Length; + EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE; + ScriptPciPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2)); + ScriptPciPoll.Width = Width; + ScriptPciPoll.Address = Address; + ScriptPciPoll.Delay = Delay; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or + after a defined duration. + + @param Width The width of the I/O operations. + @param Segment The PCI segment number for Address. + @param Address The address within the PCI configuration space. + @param Data The comparison value used for the polling exit criteria. + @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero + in Data are ignored when polling the memory address + @param Delay The number of 100ns units to poll. Note that timer available may be of poorer + granularity so the delay may be longer. + + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + @note A known Limitations in the implementation: When interpreting the opcode EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE + EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE and EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE, the 'Segment' parameter is assumed as + Zero, or else, assert. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSavePci2Poll ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT16 Segment, + IN UINT64 Address, + IN VOID *Data, + IN VOID *DataMask, + IN UINT64 Delay +) +{ + UINT8 WidthInByte; + UINT8 *Script; + UINT8 Length; + EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll; + + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2)); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Build script data + // + ScriptPci2Poll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE; + ScriptPci2Poll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2)); + ScriptPci2Poll.Width = Width; + ScriptPci2Poll.Segment = Segment; + ScriptPci2Poll.Address = Address; + ScriptPci2Poll.Delay = Delay; + + CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte); + CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte); + + SyncBootScript (); + + return RETURN_SUCCESS; +} +/** + Do the calculation of start address from which a new s3 boot script entry will write into. + + @param EntryLength The new entry length. + @param Position specifies the position in the boot script table where the opcode will be + inserted, either before or after, depending on BeforeOrAfter. + @param BeforeOrAfter The flag to indicate to insert the nod before or after the position. + This parameter is effective when InsertFlag is TRUE + @param Script return out the position from which the a new s3 boot script entry will write into +**/ +VOID +S3BootScriptCalculateInsertAddress ( + IN UINT8 EntryLength, + IN VOID *Position OPTIONAL, + IN BOOLEAN BeforeOrAfter OPTIONAL, + OUT UINT8 **Script + ) +{ + UINTN TableLength; + UINT8 *S3TableBase; + UINTN PositionOffset; + EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader; + // + // The entry inserting to table is already added to the end of the table + // + TableLength = mS3BootScriptTablePtr->TableLength - EntryLength; + S3TableBase = mS3BootScriptTablePtr->TableBase ; + // + // calculate the Position offset + // + if (Position != NULL) { + PositionOffset = (UINTN) ((UINT8 *)Position - S3TableBase); + + // + // If the BeforeOrAfter is FALSE, that means to insert the node right after the node. + // + if (!BeforeOrAfter) { + CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); + PositionOffset += (ScriptHeader.Length); + } + // + // Insert the node before the adjusted Position + // + CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset); + // + // calculate the the start address for the new entry. + // + *Script = S3TableBase + PositionOffset; + + } else { + if (!BeforeOrAfter) { + // + // Insert the node to the end of the table + // + *Script = S3TableBase + TableLength; + } else { + // + // Insert the node to the beginning of the table + // + PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER); + CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset); + *Script = S3TableBase + PositionOffset; + } + } +} +/** + Move the last boot script entry to the position + + @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position + in the boot script table specified by Position. If Position is NULL or points to + NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end + of the table (if FALSE). + @param Position On entry, specifies the position in the boot script table where the opcode will be + inserted, either before or after, depending on BeforeOrAfter. On exit, specifies + the position of the inserted opcode in the boot script table. + + @retval RETURN_OUT_OF_RESOURCES The table is not available. + @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table. + @retval RETURN_SUCCESS Opcode is inserted. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptMoveLastOpcode ( + IN BOOLEAN BeforeOrAfter, + IN OUT VOID **Position OPTIONAL +) +{ + UINT8* Script; + VOID *TempPosition; + UINTN StartAddress; + UINT32 TableLength; + EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader; + BOOLEAN ValidatePosition; + UINT8* LastOpcode; + UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH]; + + ValidatePosition = FALSE; + TempPosition = (Position == NULL) ? NULL:(*Position); + Script = mS3BootScriptTablePtr->TableBase; + if (Script == 0) { + return EFI_OUT_OF_RESOURCES; + } + StartAddress = (UINTN) Script; + TableLength = mS3BootScriptTablePtr->TableLength; + Script = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER); + LastOpcode = Script; + // + // Find the last boot Script Entry which is not the terminate node + // + while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) { + CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); + if (TempPosition != NULL && TempPosition == Script) { + // + // If the position is specified, the position must be pointed to a boot script entry start address. + // + ValidatePosition = TRUE; + } + if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) { + LastOpcode = Script; + } + Script = Script + ScriptHeader.Length; + } + // + // If the position is specified, but not the start of a boot script entry, it is a invalid input + // + if (TempPosition != NULL && !ValidatePosition) { + return RETURN_INVALID_PARAMETER; + } + + CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); + + CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length); + // + // Find the right position to write the node in + // + S3BootScriptCalculateInsertAddress ( + ScriptHeader.Length, + TempPosition, + BeforeOrAfter, + &Script + ); + // + // Copy the node to Boot script table + // + CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length); + // + // return out the Position + // + if (Position != NULL) { + *Position = Script; + } + return RETURN_SUCCESS; +} +/** + Create a Label node in the boot script table. + + @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position + in the boot script table specified by Position. If Position is NULL or points to + NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end + of the table (if FALSE). + @param Position On entry, specifies the position in the boot script table where the opcode will be + inserted, either before or after, depending on BeforeOrAfter. On exit, specifies + the position of the inserted opcode in the boot script table. + @param InformationLength Length of the label in bytes + @param Information Label to be logged in the boot scrpit + + @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table. + @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. + @retval RETURN_SUCCESS Opcode is added. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptLabelInternal ( + IN BOOLEAN BeforeOrAfter, + IN OUT VOID **Position OPTIONAL, + IN UINT32 InformationLength, + IN CONST CHAR8 *Information + ) +{ + UINT8 Length; + UINT8 *Script; + VOID *Buffer; + EFI_BOOT_SCRIPT_INFORMATION ScriptInformation; + + Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength); + + Script = S3BootScriptGetEntryAddAddress (Length); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + Buffer = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION); + // + // Build script data + // + ScriptInformation.OpCode = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE; + ScriptInformation.Length = Length; + + + ScriptInformation.InformationLength = InformationLength; + + AsciiStrnCpy (Buffer, Information,(UINTN) InformationLength); + ScriptInformation.Information = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer; + + CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION)); + + return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position); + +} +/** + Find a label within the boot script table and, if not present, optionally create it. + + @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) + or after (FALSE) the position in the boot script table + specified by Position. + @param CreateIfNotFound Specifies whether the label will be created if the label + does not exists (TRUE) or not (FALSE). + @param Position On entry, specifies the position in the boot script table + where the opcode will be inserted, either before or after, + depending on BeforeOrAfter. On exit, specifies the position + of the inserted opcode in the boot script table. + @param Label Points to the label which will be inserted in the boot script table. + + @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. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptLabel ( + IN BOOLEAN BeforeOrAfter, + IN BOOLEAN CreateIfNotFound, + IN OUT VOID **Position OPTIONAL, + IN CONST CHAR8 *Label + ) +{ + UINT8* Script; + UINTN StartAddress; + UINT32 TableLength; + EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader; + EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader; + UINT32 LabelLength; + // + // Assume Label is not NULL + // + if (Label == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check that the script is initialized without adding an entry to the script. + // The code must search for the label first befor it knows if a new entry needs + // to be added. + // + Script = S3BootScriptGetEntryAddAddress (0); + if (Script == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // Check the header and search for existing label. + // + Script = mS3BootScriptTablePtr->TableBase; + CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); + if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) { + return EFI_INVALID_PARAMETER; + } + StartAddress = (UINTN) Script; + TableLength = mS3BootScriptTablePtr->TableLength; + Script = Script + TableHeader.Length; + while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) { + + CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); + if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) { + if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) { + (*Position) = Script; + return EFI_SUCCESS; + } + } + Script = Script + ScriptHeader.Length; + } + if (CreateIfNotFound) { + LabelLength = (UINT32)AsciiStrSize(Label); + return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label); + } else { + return EFI_NOT_FOUND; + } +} + +/** + Compare two positions in the boot script table and return their relative position. + @param Position1 The positions in the boot script table to compare + @param Position2 The positions in the boot script table to compare + @param RelativePosition On return, points to the result of the comparison + + @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. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptCompare ( + IN UINT8 *Position1, + IN UINT8 *Position2, + OUT UINTN *RelativePosition + ) +{ + UINT8* Script; + UINT32 TableLength; + + Script = mS3BootScriptTablePtr->TableBase; + if (Script == NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (RelativePosition == NULL) { + return EFI_INVALID_PARAMETER; + } + TableLength = ((EFI_BOOT_SCRIPT_TABLE_HEADER*)Script)->TableLength; + // + // If in boot time, TableLength does not include the termination node. so add it up + // + if (!mS3BootScriptTablePtr->AtRuntime) { + TableLength += sizeof(EFI_BOOT_SCRIPT_TERMINATE); + } + if (Position1 < Script || Position1 > Script+TableLength) { + return EFI_INVALID_PARAMETER; + } + if (Position2 < Script || Position2 > Script+TableLength) { + return EFI_INVALID_PARAMETER; + } + *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1); + + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf b/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf new file mode 100644 index 0000000000..d942846166 --- /dev/null +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf @@ -0,0 +1,70 @@ +## @file +# S3 boot script Library which could be used for multi phases. +# +# Copyright (c) 2006 - 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeS3BootScriptLib + FILE_GUID = 57F9967B-26CD-4262-837A-55B8AA158254 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = S3BootScriptLib|SEC PEIM PEI_CORE DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION + + + CONSTRUCTOR = S3BootScriptLibInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + BootScriptSave.c + BootScriptExecute.c + InternalBootScriptLib.h + BootScriptInternalFormat.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + BaseLib + BaseMemoryLib + TimerLib + DebugLib + PcdLib + UefiLib + SmbusLib + PciLib + IoLib + LockBoxLib + +[Guids] + gEfiEventExitBootServicesGuid # ALWAYS_CONSUMED + +[Protocols] + gEfiSmmBase2ProtocolGuid # ALWAYS_CONSUMED + gEfiDxeSmmReadyToLockProtocolGuid # ALWAYS_CONSUMED + gEfiSmmReadyToLockProtocolGuid # ALWAYS_CONSUMED + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptRuntimeTableReservePageNumber ## CONSUMES + +[Depex] + gPcdProtocolGuid \ No newline at end of file diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h b/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h new file mode 100644 index 0000000000..babd12e43c --- /dev/null +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h @@ -0,0 +1,102 @@ +/** @file + Support for S3 boot script lib. This file defined some internal macro and internal + data structure + + Copyright (c) 2006 - 2011, 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 __INTERNAL_BOOT_SCRIPT_LIB__ +#define __INTERNAL_BOOT_SCRIPT_LIB__ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BootScriptInternalFormat.h" + +#define MAX_IO_ADDRESS 0xFFFF + +#define PCI_ADDRESS_ENCODE(A) (UINTN)PCI_LIB_ADDRESS( \ + (((A)& 0xff000000) >> 24), (((A) &0x00ff0000) >> 16), (((A) & 0xff00) >> 8), ((RShiftU64 ((A), 32) & 0xfff) | ((A)& 0xff)) \ + ) + + + +typedef union { + UINT8 volatile *Buf; + UINT8 volatile *Uint8; + UINT16 volatile *Uint16; + UINT32 volatile *Uint32; + UINT64 volatile *Uint64; + UINTN volatile Uint; +} PTR; + + +// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0. +// +#define MIN_SMBUS_BLOCK_LEN 1 +#define MAX_SMBUS_BLOCK_LEN 32 + +// +// The boot script private data. +// +typedef struct { + UINT8 *TableBase; + UINT32 TableLength; // Record the actual memory length + UINT16 TableMemoryPageNumber; // Record the page number Allocated for the table + BOOLEAN AtRuntime; // Record if current state is after SmmReadyToLock + BOOLEAN InSmm; // Record if this library is in SMM. +} SCRIPT_TABLE_PRIVATE_DATA; + +typedef +EFI_STATUS +(EFIAPI *DISPATCH_ENTRYPOINT_FUNC) ( + IN EFI_HANDLE ImageHandle, + IN VOID *Context + ); + +extern SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; + +// +// Define Opcode for Label which is implementation specific and no standard spec define. +// +#define S3_BOOT_SCRIPT_LIB_LABEL_OPCODE 0xFE + +/// +/// The opcode indicate the start of the boot script table. +/// +#define S3_BOOT_SCRIPT_LIB_TABLE_OPCODE 0xAA +/// +/// The opcode indicate the end of the boot script table. +/// +#define S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE 0xFF + + +#endif //__INTERNAL_BOOT_SCRIPT_LIB__ + diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 89fa0b405d..859b2664f7 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -241,6 +241,7 @@ MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf + MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf MdeModulePkg/Universal/CapsulePei/CapsulePei.inf MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf -- cgit v1.2.3