summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-08-29 22:17:27 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-08-29 22:17:27 +0000
commit64d14edfeb3f0dd31506bec1244a8d53f08789cc (patch)
tree50ed0cb7c743ac5243b8141e4a6864252fc38b74 /MdeModulePkg/Library
parent88d20adc90e556245b375507ef920997dce5e186 (diff)
downloadedk2-platforms-64d14edfeb3f0dd31506bec1244a8d53f08789cc.tar.xz
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
Diffstat (limited to 'MdeModulePkg/Library')
-rw-r--r--MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c1753
-rw-r--r--MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h186
-rw-r--r--MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c1852
-rw-r--r--MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf70
-rw-r--r--MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h102
5 files changed, 3963 insertions, 0 deletions
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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "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.<BR>
+#
+# This program and the accompanying materials are
+# licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __INTERNAL_BOOT_SCRIPT_LIB__
+#define __INTERNAL_BOOT_SCRIPT_LIB__
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/SmmReadyToLock.h>
+
+#include <Library/S3BootScriptLib.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/LockBoxLib.h>
+
+#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__
+