]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Add PiDxeS3BootScriptLib
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 29 Aug 2011 22:17:27 +0000 (22:17 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 29 Aug 2011 22:17:27 +0000 (22:17 +0000)
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

MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c [new file with mode: 0644]
MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h [new file with mode: 0644]
MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c [new file with mode: 0644]
MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf [new file with mode: 0644]
MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dsc

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