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
diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
new file mode 100644
index 0000000..5a93549
--- /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 0000000..6edb11a
--- /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 0000000..8769509
--- /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 0000000..d942846
--- /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 0000000..babd12e
--- /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__

+