Home | History | Annotate | Download | only in PiDxeS3BootScriptLib
      1 /** @file
      2   Save the S3 data to S3 boot script.
      3 
      4   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions
      8   of the BSD License which accompanies this distribution.  The
      9   full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 #include "InternalBootScriptLib.h"
     17 
     18 /**
     19 
     20   Data structure usage:
     21 
     22   +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr
     23   | SCRIPT_TABLE_PRIVATE_DATA    |          (mS3BootScriptTablePtr, Before SmmReadyToLock)
     24   |    TableBase                 |---      PcdS3BootScriptTablePrivateSmmDataPtr
     25   |    TableLength               |--|--     (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm)
     26   |    TableMemoryPageNumber     |--|-|----
     27   |    AtRuntime                 |  | |   |
     28   |    InSmm                     |  | |   |
     29   |    BootTimeScriptLength      |--|-|---|---
     30   |    SmmLocked                 |  | |   |  |
     31   |    BackFromS3                |  | |   |  |
     32   +------------------------------+  | |   |  |
     33                                     | |   |  |
     34   +------------------------------+<-- |   |  |
     35   | EFI_BOOT_SCRIPT_TABLE_HEADER |    |   |  |
     36   |    TableLength               |----|-- |  |
     37   +------------------------------+    | | |  |
     38   |     ......                   |    | | |  |
     39   +------------------------------+<---- | |  |
     40   | EFI_BOOT_SCRIPT_TERMINATE    |      | |  |
     41   +------------------------------+<------ |  |
     42                                           |  |
     43                                           |  |
     44   mBootScriptDataBootTimeGuid LockBox:    |  |
     45    Used to restore data after back from S3|  |
     46    to handle potential INSERT boot script |  |
     47    at runtime.                            |  |
     48   +------------------------------+        |  |
     49   | Boot Time Boot Script        |        |  |
     50   | Before SmmReadyToLock        |        |  |
     51   |                              |        |  |
     52   |                              |        |  |
     53   +------------------------------+        |  |
     54   | Boot Time Boot Script        |        |  |
     55   | After SmmReadyToLock InSmm   |        |  |
     56   |                              |        |  |
     57   +------------------------------+<-------|--|
     58                                           |  |
     59                                           |  |
     60   mBootScriptDataGuid LockBox: (IN_PLACE) |  |
     61    Used to restore data at S3 resume.     |  |
     62   +------------------------------+        |  |
     63   | Boot Time Boot Script        |        |  |
     64   | Before SmmReadyToLock        |        |  |
     65   |                              |        |  |
     66   |                              |        |  |
     67   +------------------------------+        |  |
     68   | Boot Time Boot Script        |        |  |
     69   | After SmmReadyToLock InSmm   |        |  |
     70   |                              |        |  |
     71   +------------------------------+<-------|---
     72   | Runtime Boot Script          |        |
     73   | After SmmReadyToLock InSmm   |        |
     74   +------------------------------+        |
     75   |     ......                   |        |
     76   +------------------------------+<--------
     77 
     78 
     79   mBootScriptTableBaseGuid LockBox: (IN_PLACE)
     80   +------------------------------+
     81   | mS3BootScriptTablePtr->      |
     82   |  TableBase                   |
     83   +------------------------------+
     84 
     85 
     86   mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE)
     87    SMM private data with BackFromS3 = TRUE
     88    at runtime. S3 will help restore it to
     89    tell the Library the system is back from S3.
     90   +------------------------------+
     91   | SCRIPT_TABLE_PRIVATE_DATA    |
     92   |    TableBase                 |
     93   |    TableLength               |
     94   |    TableMemoryPageNumber     |
     95   |    AtRuntime                 |
     96   |    InSmm                     |
     97   |    BootTimeScriptLength      |
     98   |    SmmLocked                 |
     99   |    BackFromS3 = TRUE         |
    100   +------------------------------+
    101 
    102 **/
    103 
    104 SCRIPT_TABLE_PRIVATE_DATA        *mS3BootScriptTablePtr;
    105 
    106 //
    107 // Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm.
    108 //
    109 SCRIPT_TABLE_PRIVATE_DATA        *mS3BootScriptTableSmmPtr;
    110 
    111 EFI_GUID                         mBootScriptDataGuid = {
    112   0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }
    113 };
    114 
    115 EFI_GUID                         mBootScriptDataBootTimeGuid = {
    116   0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }
    117 };
    118 
    119 EFI_GUID                         mBootScriptTableBaseGuid = {
    120   0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }
    121 };
    122 
    123 EFI_GUID                         mBootScriptSmmPrivateDataGuid = {
    124   0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 }
    125 };
    126 
    127 /**
    128   This is an internal function to add a terminate node the entry, recalculate the table
    129   length and fill into the table.
    130 
    131   @return the base address of the boot script table.
    132  **/
    133 UINT8*
    134 S3BootScriptInternalCloseTable (
    135   VOID
    136   )
    137 {
    138   UINT8                          *S3TableBase;
    139   EFI_BOOT_SCRIPT_TERMINATE      ScriptTerminate;
    140   EFI_BOOT_SCRIPT_TABLE_HEADER   *ScriptTableInfo;
    141   S3TableBase = mS3BootScriptTablePtr->TableBase;
    142 
    143   if (S3TableBase == NULL) {
    144     //
    145     // the table is not exist
    146     //
    147     return S3TableBase;
    148   }
    149   //
    150   // Append the termination entry.
    151   //
    152   ScriptTerminate.OpCode  = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE;
    153   ScriptTerminate.Length  = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE);
    154   CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE));
    155   //
    156   // fill the table length
    157   //
    158   ScriptTableInfo                = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase);
    159   ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
    160 
    161 
    162 
    163   return S3TableBase;
    164   //
    165   // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to
    166   // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE).
    167   // Because maybe after SmmReadyToLock, we still need add entries into the table,
    168   // and the entry should be added start before this TERMINATE node.
    169   //
    170 }
    171 
    172 /**
    173   This function save boot script data to LockBox.
    174 
    175 **/
    176 VOID
    177 SaveBootScriptDataToLockBox (
    178   VOID
    179   )
    180 {
    181   EFI_STATUS            Status;
    182 
    183   //
    184   // Save whole memory copy into LockBox.
    185   // It will be used to restore data at S3 resume.
    186   //
    187   Status = SaveLockBox (
    188              &mBootScriptDataGuid,
    189              (VOID *)mS3BootScriptTablePtr->TableBase,
    190              EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber)
    191              );
    192   ASSERT_EFI_ERROR (Status);
    193 
    194   Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
    195   ASSERT_EFI_ERROR (Status);
    196 
    197   //
    198   // Just need save TableBase.
    199   // Do not update other field because they will NOT be used in S3.
    200   //
    201   Status = SaveLockBox (
    202              &mBootScriptTableBaseGuid,
    203              (VOID *)&mS3BootScriptTablePtr->TableBase,
    204              sizeof(mS3BootScriptTablePtr->TableBase)
    205              );
    206   ASSERT_EFI_ERROR (Status);
    207 
    208   Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
    209   ASSERT_EFI_ERROR (Status);
    210 }
    211 
    212 /**
    213   This is the Event call back function to notify the Library the system is entering
    214   SmmLocked phase.
    215 
    216   @param  Event   Pointer to this event
    217   @param  Context Event handler private data
    218  **/
    219 VOID
    220 EFIAPI
    221 S3BootScriptEventCallBack (
    222   IN EFI_EVENT  Event,
    223   IN VOID       *Context
    224   )
    225 {
    226   EFI_STATUS   Status;
    227   VOID         *Interface;
    228 
    229   //
    230   // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration.
    231   // Just return if it is not found.
    232   //
    233   Status = gBS->LocateProtocol (
    234                   &gEfiDxeSmmReadyToLockProtocolGuid,
    235                   NULL,
    236                   &Interface
    237                   );
    238   if (EFI_ERROR (Status)) {
    239     return ;
    240   }
    241 
    242   //
    243   // Here we should tell the library that we are entering SmmLocked phase.
    244   // and the memory page number occupied by the table should not grow anymore.
    245   //
    246   if (!mS3BootScriptTablePtr->SmmLocked) {
    247     //
    248     // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table
    249     // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate
    250     // node on every add to boot script table.
    251     //
    252     S3BootScriptInternalCloseTable ();
    253     mS3BootScriptTablePtr->SmmLocked = TRUE;
    254 
    255     //
    256     // Save BootScript data to lockbox
    257     //
    258     SaveBootScriptDataToLockBox ();
    259   }
    260 }
    261 
    262 /**
    263   This is the Event call back function is triggered in SMM to notify the Library
    264   the system is entering SmmLocked phase and set InSmm flag.
    265 
    266   @param  Protocol   Points to the protocol's unique identifier
    267   @param  Interface  Points to the interface instance
    268   @param  Handle     The handle on which the interface was installed
    269 
    270   @retval EFI_SUCCESS SmmEventCallback runs successfully
    271  **/
    272 EFI_STATUS
    273 EFIAPI
    274 S3BootScriptSmmEventCallBack (
    275   IN CONST EFI_GUID  *Protocol,
    276   IN VOID            *Interface,
    277   IN EFI_HANDLE      Handle
    278   )
    279 {
    280   //
    281   // Check if it is already done
    282   //
    283   if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {
    284     return EFI_SUCCESS;
    285   }
    286 
    287   //
    288   // Last chance to call-out, just make sure SmmLocked is set.
    289   //
    290   S3BootScriptEventCallBack (NULL, NULL);
    291 
    292   //
    293   // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.
    294   //
    295   if (mS3BootScriptTableSmmPtr->TableBase == NULL) {
    296     CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));
    297 
    298     //
    299     // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.
    300     // InSmm will only be checked if SmmLocked is TRUE.
    301     //
    302     mS3BootScriptTableSmmPtr->InSmm = TRUE;
    303   }
    304   //
    305   // We should not use ACPI Reserved copy, because it is not safe.
    306   //
    307   mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;
    308 
    309   return EFI_SUCCESS;
    310 }
    311 
    312 /**
    313   This function is to save boot time boot script data to LockBox.
    314 
    315   Because there may be INSERT boot script at runtime in SMM.
    316   The boot time copy will be used to restore data after back from S3.
    317   Otherwise the data inserted may cause some boot time boot script data lost
    318   if only BootScriptData used.
    319 
    320 **/
    321 VOID
    322 SaveBootTimeDataToLockBox (
    323   VOID
    324   )
    325 {
    326   EFI_STATUS    Status;
    327 
    328   //
    329   // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first,
    330   // and then save the data to BootScriptDataBootTime LockBox.
    331   //
    332   Status = RestoreLockBox (
    333              &mBootScriptDataGuid,
    334              NULL,
    335              NULL
    336              );
    337   ASSERT_EFI_ERROR (Status);
    338 
    339   //
    340   // Save BootScriptDataBootTime
    341   // It will be used to restore data after back from S3.
    342   //
    343   Status = SaveLockBox (
    344              &mBootScriptDataBootTimeGuid,
    345              (VOID *) mS3BootScriptTablePtr->TableBase,
    346              mS3BootScriptTablePtr->BootTimeScriptLength
    347              );
    348   ASSERT_EFI_ERROR (Status);
    349 }
    350 
    351 /**
    352   This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime.
    353   S3 resume will help restore it to tell the Library the system is back from S3.
    354 
    355 **/
    356 VOID
    357 SaveSmmPriviateDataToLockBoxAtRuntime (
    358   VOID
    359   )
    360 {
    361   EFI_STATUS    Status;
    362 
    363   //
    364   // Save boot script SMM private data with BackFromS3 = TRUE.
    365   //
    366   mS3BootScriptTablePtr->BackFromS3 = TRUE;
    367   Status = SaveLockBox (
    368              &mBootScriptSmmPrivateDataGuid,
    369              (VOID *) mS3BootScriptTablePtr,
    370              sizeof (SCRIPT_TABLE_PRIVATE_DATA)
    371              );
    372   ASSERT_EFI_ERROR (Status);
    373 
    374   Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
    375   ASSERT_EFI_ERROR (Status);
    376 
    377   //
    378   // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3.
    379   //
    380   mS3BootScriptTablePtr->BackFromS3 = FALSE;
    381 }
    382 
    383 /**
    384   This is the Event call back function is triggered in SMM to notify the Library
    385   the system is entering runtime phase.
    386 
    387   @param[in] Protocol   Points to the protocol's unique identifier
    388   @param[in] Interface  Points to the interface instance
    389   @param[in] Handle     The handle on which the interface was installed
    390 
    391   @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully
    392  **/
    393 EFI_STATUS
    394 EFIAPI
    395 S3BootScriptSmmAtRuntimeCallBack (
    396   IN CONST EFI_GUID     *Protocol,
    397   IN VOID               *Interface,
    398   IN EFI_HANDLE         Handle
    399   )
    400 {
    401   if (!mS3BootScriptTablePtr->AtRuntime) {
    402     mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
    403     SaveBootTimeDataToLockBox ();
    404 
    405     mS3BootScriptTablePtr->AtRuntime = TRUE;
    406     SaveSmmPriviateDataToLockBoxAtRuntime ();
    407   }
    408 
    409   return EFI_SUCCESS;
    410 }
    411 
    412 /**
    413   Library Constructor.
    414   this function just identify it is a smm driver or non-smm driver linked against
    415   with the library
    416 
    417   @param  ImageHandle   The firmware allocated handle for the EFI image.
    418   @param  SystemTable   A pointer to the EFI System Table.
    419 
    420   @retval  RETURN_SUCCESS            Allocate the global memory space to store S3 boot script table private data
    421   @retval  RETURN_OUT_OF_RESOURCES   No enough memory to allocated.
    422 **/
    423 RETURN_STATUS
    424 EFIAPI
    425 S3BootScriptLibInitialize (
    426   IN EFI_HANDLE           ImageHandle,
    427   IN EFI_SYSTEM_TABLE     *SystemTable
    428   )
    429 {
    430   EFI_STATUS                      Status;
    431   SCRIPT_TABLE_PRIVATE_DATA      *S3TablePtr;
    432   SCRIPT_TABLE_PRIVATE_DATA      *S3TableSmmPtr;
    433   VOID                           *Registration;
    434   EFI_SMM_BASE2_PROTOCOL         *SmmBase2;
    435   BOOLEAN                        InSmm;
    436   EFI_SMM_SYSTEM_TABLE2          *Smst;
    437   EFI_PHYSICAL_ADDRESS           Buffer;
    438   EFI_EVENT                      Event;
    439 
    440   S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);
    441   //
    442   // The Boot script private data is not be initialized. create it
    443   //
    444   if (S3TablePtr == 0) {
    445     Buffer = SIZE_4GB - 1;
    446     Status = gBS->AllocatePages (
    447                     AllocateMaxAddress,
    448                     EfiReservedMemoryType,
    449                     EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),
    450                     &Buffer
    451                     );
    452     if (EFI_ERROR (Status)) {
    453       return RETURN_OUT_OF_RESOURCES;
    454     }
    455     S3TablePtr = (VOID *) (UINTN) Buffer;
    456 
    457     Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);
    458     ASSERT_EFI_ERROR (Status);
    459     ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
    460     //
    461     // Create event to notify the library system enter the SmmLocked phase.
    462     //
    463     Event = EfiCreateProtocolNotifyEvent  (
    464               &gEfiDxeSmmReadyToLockProtocolGuid,
    465               TPL_CALLBACK,
    466               S3BootScriptEventCallBack,
    467               NULL,
    468               &Registration
    469               );
    470     ASSERT (Event != NULL);
    471   }
    472   mS3BootScriptTablePtr = S3TablePtr;
    473 
    474   //
    475   // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.
    476   //
    477   Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
    478   if (EFI_ERROR (Status)) {
    479     return RETURN_SUCCESS;
    480   }
    481   Status = SmmBase2->InSmm (SmmBase2, &InSmm);
    482   if (EFI_ERROR (Status)) {
    483     return RETURN_SUCCESS;
    484   }
    485   if (!InSmm) {
    486     return RETURN_SUCCESS;
    487   }
    488   //
    489   // Good, we are in SMM
    490   //
    491   Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);
    492   if (EFI_ERROR (Status)) {
    493     return RETURN_SUCCESS;
    494   }
    495 
    496   S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);
    497   //
    498   // The Boot script private data in SMM is not be initialized. create it
    499   //
    500   if (S3TableSmmPtr == 0) {
    501     Status = Smst->SmmAllocatePool (
    502                      EfiRuntimeServicesData,
    503                      sizeof(SCRIPT_TABLE_PRIVATE_DATA),
    504                      (VOID **) &S3TableSmmPtr
    505                      );
    506     if (EFI_ERROR (Status)) {
    507       return RETURN_OUT_OF_RESOURCES;
    508     }
    509 
    510     Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);
    511     ASSERT_EFI_ERROR (Status);
    512     ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
    513 
    514     //
    515     // Register SmmExitBootServices and SmmLegacyBoot notification.
    516     //
    517     Registration = NULL;
    518     Status = Smst->SmmRegisterProtocolNotify (
    519                      &gEdkiiSmmExitBootServicesProtocolGuid,
    520                      S3BootScriptSmmAtRuntimeCallBack,
    521                      &Registration
    522                      );
    523     ASSERT_EFI_ERROR (Status);
    524 
    525     Registration = NULL;
    526     Status = Smst->SmmRegisterProtocolNotify (
    527                      &gEdkiiSmmLegacyBootProtocolGuid,
    528                      S3BootScriptSmmAtRuntimeCallBack,
    529                      &Registration
    530                      );
    531     ASSERT_EFI_ERROR (Status);
    532   }
    533   mS3BootScriptTableSmmPtr = S3TableSmmPtr;
    534 
    535   //
    536   // Register SmmReadyToLock notification.
    537   //
    538   Registration = NULL;
    539   Status = Smst->SmmRegisterProtocolNotify (
    540                    &gEfiSmmReadyToLockProtocolGuid,
    541                    S3BootScriptSmmEventCallBack,
    542                    &Registration
    543                    );
    544   ASSERT_EFI_ERROR (Status);
    545 
    546   return RETURN_SUCCESS;
    547 }
    548 /**
    549   To get the start address from which a new boot time s3 boot script entry will write into.
    550   If the table is not exist, the functio will first allocate a buffer for the table
    551   If the table buffer is not enough for the new entry, in non-smm mode, the funtion will
    552   invoke reallocate to enlarge buffer.
    553 
    554   @param EntryLength      the new entry length.
    555 
    556   @retval the address from which the a new s3 boot script entry will write into
    557  **/
    558 UINT8*
    559 S3BootScriptGetBootTimeEntryAddAddress (
    560   UINT8  EntryLength
    561   )
    562 {
    563    EFI_PHYSICAL_ADDRESS              S3TableBase;
    564    EFI_PHYSICAL_ADDRESS              NewS3TableBase;
    565    UINT8                            *NewEntryPtr;
    566    UINT32                            TableLength;
    567    UINT16                            PageNumber;
    568    EFI_STATUS                        Status;
    569    EFI_BOOT_SCRIPT_TABLE_HEADER      *ScriptTableInfo;
    570 
    571    S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);
    572    if (S3TableBase == 0) {
    573      //
    574      // The table is not exist. This is the first to add entry.
    575      // Allocate ACPI script table space under 4G memory.
    576      //
    577      S3TableBase = 0xffffffff;
    578      Status = gBS->AllocatePages (
    579                   AllocateMaxAddress,
    580                   EfiReservedMemoryType,
    581                   2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
    582                   (EFI_PHYSICAL_ADDRESS*)&S3TableBase
    583                   );
    584 
    585      if (EFI_ERROR(Status)) {
    586        ASSERT_EFI_ERROR (Status);
    587        return 0;
    588      }
    589      //
    590      // Fill Table Header
    591      //
    592      ScriptTableInfo              = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;
    593      ScriptTableInfo->OpCode      = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
    594      ScriptTableInfo->Length      = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
    595      ScriptTableInfo->Version     = BOOT_SCRIPT_TABLE_VERSION;
    596      ScriptTableInfo->TableLength = 0;   // will be calculate at CloseTable
    597      mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
    598      mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;
    599      mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
    600    }
    601 
    602    // Here we do not count the reserved memory for runtime script table.
    603    PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
    604    TableLength =  mS3BootScriptTablePtr->TableLength;
    605    if ((UINTN) EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (UINTN) (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {
    606      //
    607      // The buffer is too small to hold the table, Reallocate the buffer
    608      //
    609      NewS3TableBase = 0xffffffff;
    610      Status = gBS->AllocatePages (
    611                   AllocateMaxAddress,
    612                   EfiReservedMemoryType,
    613                   2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
    614                   (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase
    615                   );
    616 
    617      if (EFI_ERROR(Status)) {
    618        ASSERT_EFI_ERROR (Status);
    619        return 0;
    620      }
    621 
    622      CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength);
    623      gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber);
    624 
    625      mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase;
    626      mS3BootScriptTablePtr->TableMemoryPageNumber =  (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
    627    }
    628    //
    629    // calculate the the start address for the new entry.
    630    //
    631    NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength;
    632 
    633    //
    634    // update the table lenghth
    635    //
    636    mS3BootScriptTablePtr->TableLength =  TableLength + EntryLength;
    637 
    638    //
    639    // In the boot time, we will not append the termination entry to the boot script
    640    // table until the callers think there is no boot time data that should be added and
    641    // it is caller's responsibility to explicit call the CloseTable.
    642    //
    643    //
    644 
    645    return NewEntryPtr;
    646 }
    647 /**
    648   To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into.
    649   In this case, it should be ensured that there is enough buffer to hold the entry.
    650 
    651   @param EntryLength      the new entry length.
    652 
    653   @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into
    654  **/
    655 UINT8*
    656 S3BootScriptGetRuntimeEntryAddAddress (
    657   UINT8  EntryLength
    658   )
    659 {
    660    UINT8     *NewEntryPtr;
    661 
    662    NewEntryPtr = NULL;
    663    //
    664    // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node.
    665    //
    666    if ((UINTN) (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= (UINTN) EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) {
    667      NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength;
    668      mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;
    669      //
    670      // Append a terminate node on every insert
    671      //
    672      S3BootScriptInternalCloseTable ();
    673    }
    674    return (UINT8*)NewEntryPtr;
    675 }
    676 
    677 /**
    678   This function is to restore boot time boot script data from LockBox.
    679 
    680 **/
    681 VOID
    682 RestoreBootTimeDataFromLockBox (
    683   VOID
    684   )
    685 {
    686   EFI_STATUS    Status;
    687   UINTN         LockBoxLength;
    688 
    689   //
    690   // Restore boot time boot script data from LockBox.
    691   //
    692   LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength;
    693   Status = RestoreLockBox (
    694              &mBootScriptDataBootTimeGuid,
    695              (VOID *) mS3BootScriptTablePtr->TableBase,
    696              &LockBoxLength
    697              );
    698   ASSERT_EFI_ERROR (Status);
    699 
    700   //
    701   // Update the data to BootScriptData LockBox.
    702   //
    703   Status = UpdateLockBox (
    704              &mBootScriptDataGuid,
    705              0,
    706              (VOID *) mS3BootScriptTablePtr->TableBase,
    707              LockBoxLength
    708              );
    709   ASSERT_EFI_ERROR (Status);
    710 
    711   //
    712   // Update TableLength.
    713   //
    714   mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE));
    715 }
    716 
    717 /**
    718   To get the start address from which a new s3 boot script entry will write into.
    719 
    720   @param EntryLength      the new entry length.
    721 
    722   @retval the address from which the a new s3 boot script entry will write into
    723  **/
    724 UINT8*
    725 S3BootScriptGetEntryAddAddress (
    726   UINT8  EntryLength
    727   )
    728 {
    729   UINT8*                         NewEntryPtr;
    730 
    731   if (mS3BootScriptTablePtr->SmmLocked) {
    732     //
    733     // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script.
    734     //
    735     if (!mS3BootScriptTablePtr->InSmm) {
    736       //
    737       // Add DEBUG ERROR, so that we can find it after SmmReadyToLock.
    738       // Do not use ASSERT, because we may have test to invoke this interface.
    739       //
    740       DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n"));
    741       return NULL;
    742     }
    743 
    744     if (mS3BootScriptTablePtr->BackFromS3) {
    745       //
    746       // Back from S3, restore boot time boot script data from LockBox
    747       // and set BackFromS3 flag back to FALSE.
    748       //
    749       RestoreBootTimeDataFromLockBox ();
    750       mS3BootScriptTablePtr->BackFromS3 = FALSE;
    751     }
    752 
    753     NewEntryPtr  = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);
    754   } else {
    755     NewEntryPtr  = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);
    756   }
    757   return NewEntryPtr;
    758 
    759 }
    760 
    761 /**
    762   Sync BootScript LockBox data.
    763 
    764   @param Script           The address from where the boot script has been added or updated.
    765 
    766 **/
    767 VOID
    768 SyncBootScript (
    769   IN UINT8      *Script
    770   )
    771 {
    772   EFI_STATUS  Status;
    773   UINT32      ScriptOffset;
    774   UINT32      TotalScriptLength;
    775 
    776   if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) {
    777     //
    778     // If it is not after SmmReadyToLock in SMM,
    779     // just return.
    780     //
    781     return ;
    782   }
    783 
    784   ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase);
    785 
    786   TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
    787 
    788   //
    789   // Update BootScriptData
    790   // So in S3 resume, the data can be restored correctly.
    791   //
    792   Status = UpdateLockBox (
    793              &mBootScriptDataGuid,
    794              ScriptOffset,
    795              (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),
    796              TotalScriptLength - ScriptOffset
    797              );
    798   ASSERT_EFI_ERROR (Status);
    799 
    800   //
    801   // Now the length field is updated, need sync to lockbox.
    802   // So at S3 resume, the data can be restored correctly.
    803   //
    804   Status = UpdateLockBox (
    805              &mBootScriptDataGuid,
    806              OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),
    807              &TotalScriptLength,
    808              sizeof (TotalScriptLength)
    809              );
    810   ASSERT_EFI_ERROR (Status);
    811 }
    812 
    813 /**
    814   This is an function to close the S3 boot script table. The function could only be called in
    815   BOOT time phase. To comply with the Framework spec definition on
    816   EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things:
    817   1. Closes the specified boot script table
    818   2. It allocates a new memory pool to duplicate all the boot scripts in the specified table.
    819      Once this function is called, the table maintained by the library will be destroyed
    820      after it is copied into the allocated pool.
    821   3. Any attempts to add a script record after calling this function will cause a new table
    822      to be created by the library.
    823   4. The base address of the allocated pool will be returned in Address. Note that after
    824      using the boot script table, the CALLER is responsible for freeing the pool that is allocated
    825      by this function.
    826 
    827   In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is
    828   for Framework Spec compatibility.
    829 
    830   If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out
    831   how to get the script to run at S3 resume because the boot script maintained by the lib will be
    832   destroyed.
    833 
    834   @return the base address of the new copy of the boot script table.
    835   @note this function could only called in boot time phase
    836 
    837 **/
    838 UINT8*
    839 EFIAPI
    840 S3BootScriptCloseTable (
    841   VOID
    842   )
    843 {
    844   UINT8                          *S3TableBase;
    845   UINT32                          TableLength;
    846   UINT8                          *Buffer;
    847   EFI_STATUS                      Status;
    848   EFI_BOOT_SCRIPT_TABLE_HEADER      *ScriptTableInfo;
    849 
    850   S3TableBase =    mS3BootScriptTablePtr->TableBase;
    851   if (S3TableBase == 0) {
    852     return 0;
    853   }
    854   //
    855   // Append the termination record the S3 boot script table
    856   //
    857   S3BootScriptInternalCloseTable();
    858   TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
    859   //
    860   // Allocate the buffer and copy the boot script to the buffer.
    861   //
    862   Status = gBS->AllocatePool (
    863                   EfiBootServicesData,
    864                   (UINTN)TableLength,
    865                   (VOID **) &Buffer
    866                   );
    867   if (EFI_ERROR (Status)) {
    868         return 0;
    869   }
    870   CopyMem (Buffer, S3TableBase, TableLength);
    871 
    872   //
    873   // Destroy the table maintained by the library so that the next write operation
    874   // will write the record to the first entry of the table.
    875   //
    876   // Fill the table header.
    877   ScriptTableInfo                    = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase;
    878   ScriptTableInfo->OpCode      = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
    879   ScriptTableInfo->Length      = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
    880   ScriptTableInfo->TableLength = 0;   // will be calculate at close the table
    881 
    882   mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
    883   return Buffer;
    884 }
    885 /**
    886   Save I/O write to boot script
    887 
    888   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
    889   @param Address The base address of the I/O operations.
    890   @param Count   The number of I/O operations to perform.
    891   @param Buffer  The source buffer from which to write data.
    892 
    893   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
    894   @retval RETURN_SUCCESS           Opcode is added.
    895 **/
    896 RETURN_STATUS
    897 EFIAPI
    898 S3BootScriptSaveIoWrite (
    899   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
    900   IN  UINT64                            Address,
    901   IN  UINTN                             Count,
    902   IN  VOID                              *Buffer
    903   )
    904 
    905 {
    906   UINT8                     Length;
    907   UINT8                    *Script;
    908   UINT8                     WidthInByte;
    909   EFI_BOOT_SCRIPT_IO_WRITE  ScriptIoWrite;
    910 
    911   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
    912   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));
    913 
    914   Script = S3BootScriptGetEntryAddAddress (Length);
    915   if (Script == NULL) {
    916     return RETURN_OUT_OF_RESOURCES;
    917   }
    918   //
    919   // save script data
    920   //
    921   ScriptIoWrite.OpCode  = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;
    922   ScriptIoWrite.Length  = Length;
    923   ScriptIoWrite.Width   = Width;
    924   ScriptIoWrite.Address = Address;
    925   ScriptIoWrite.Count   = (UINT32) Count;
    926   CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
    927   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);
    928 
    929   SyncBootScript (Script);
    930 
    931   return RETURN_SUCCESS;
    932 }
    933 
    934 /**
    935   Adds a record for an I/O modify operation into a S3 boot script table
    936 
    937   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
    938   @param Address The base address of the I/O operations.
    939   @param Data    A pointer to the data to be OR-ed.
    940   @param DataMask  A pointer to the data mask to be AND-ed with the data read from the register
    941 
    942   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
    943   @retval RETURN_SUCCESS           Opcode is added.
    944 **/
    945 RETURN_STATUS
    946 EFIAPI
    947 S3BootScriptSaveIoReadWrite (
    948   IN  S3_BOOT_SCRIPT_LIB_WIDTH         Width,
    949   IN  UINT64                           Address,
    950   IN  VOID                            *Data,
    951   IN  VOID                            *DataMask
    952   )
    953 {
    954   UINT8                 Length;
    955   UINT8                *Script;
    956   UINT8                 WidthInByte;
    957   EFI_BOOT_SCRIPT_IO_READ_WRITE  ScriptIoReadWrite;
    958 
    959   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
    960   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));
    961 
    962   Script = S3BootScriptGetEntryAddAddress (Length);
    963   if (Script == NULL) {
    964     return RETURN_OUT_OF_RESOURCES;
    965   }
    966   //
    967   // Build script data
    968   //
    969   ScriptIoReadWrite.OpCode  = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;
    970   ScriptIoReadWrite.Length  = Length;
    971   ScriptIoReadWrite.Width   = Width;
    972   ScriptIoReadWrite.Address = Address;
    973 
    974   CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
    975   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);
    976   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
    977 
    978   SyncBootScript (Script);
    979 
    980   return RETURN_SUCCESS;
    981 }
    982 /**
    983   Adds a record for a memory write operation into a specified boot script table.
    984 
    985   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
    986   @param Address The base address of the memory operations
    987   @param Count   The number of memory operations to perform.
    988   @param Buffer  The source buffer from which to write the data.
    989 
    990   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
    991   @retval RETURN_SUCCESS           Opcode is added.
    992 **/
    993 RETURN_STATUS
    994 EFIAPI
    995 S3BootScriptSaveMemWrite (
    996   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
    997   IN  UINT64                            Address,
    998   IN  UINTN                             Count,
    999   IN  VOID                              *Buffer
   1000   )
   1001 {
   1002   UINT8                 Length;
   1003   UINT8                *Script;
   1004   UINT8                 WidthInByte;
   1005   EFI_BOOT_SCRIPT_MEM_WRITE  ScriptMemWrite;
   1006 
   1007   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1008   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));
   1009 
   1010   Script = S3BootScriptGetEntryAddAddress (Length);
   1011   if (Script == NULL) {
   1012     return RETURN_OUT_OF_RESOURCES;
   1013   }
   1014   //
   1015   // Build script data
   1016   //
   1017   ScriptMemWrite.OpCode   = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;
   1018   ScriptMemWrite.Length   = Length;
   1019   ScriptMemWrite.Width    = Width;
   1020   ScriptMemWrite.Address  = Address;
   1021   ScriptMemWrite.Count    = (UINT32) Count;
   1022 
   1023   CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
   1024   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);
   1025 
   1026   SyncBootScript (Script);
   1027 
   1028   return RETURN_SUCCESS;
   1029 }
   1030 /**
   1031   Adds a record for a memory modify operation into a specified boot script table.
   1032 
   1033   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
   1034   @param Address   The base address of the memory operations. Address needs alignment if required
   1035   @param Data      A pointer to the data to be OR-ed.
   1036   @param DataMask  A pointer to the data mask to be AND-ed with the data read from the register.
   1037 
   1038   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1039   @retval RETURN_SUCCESS           Opcode is added.
   1040 **/
   1041 RETURN_STATUS
   1042 EFIAPI
   1043 S3BootScriptSaveMemReadWrite (
   1044   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
   1045   IN  UINT64                            Address,
   1046   IN  VOID                              *Data,
   1047   IN  VOID                              *DataMask
   1048   )
   1049 {
   1050   UINT8                 Length;
   1051   UINT8                *Script;
   1052   UINT8                 WidthInByte;
   1053   EFI_BOOT_SCRIPT_MEM_READ_WRITE  ScriptMemReadWrite;
   1054 
   1055   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1056   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));
   1057 
   1058   Script = S3BootScriptGetEntryAddAddress (Length);
   1059   if (Script == NULL) {
   1060     return RETURN_OUT_OF_RESOURCES;
   1061   }
   1062   //
   1063   // Build script data
   1064   //
   1065   ScriptMemReadWrite.OpCode   = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;
   1066   ScriptMemReadWrite.Length   = Length;
   1067   ScriptMemReadWrite.Width    = Width;
   1068   ScriptMemReadWrite.Address  = Address;
   1069 
   1070   CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));
   1071   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);
   1072   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
   1073 
   1074   SyncBootScript (Script);
   1075 
   1076   return RETURN_SUCCESS;
   1077 }
   1078 /**
   1079   Adds a record for a PCI configuration space write operation into a specified boot script table.
   1080 
   1081   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
   1082   @param Address   The address within the PCI configuration space.
   1083   @param Count     The number of PCI operations to perform.
   1084   @param Buffer    The source buffer from which to write the data.
   1085 
   1086   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1087   @retval RETURN_SUCCESS           Opcode is added.
   1088   @note  A known Limitations in the implementation which is 64bits operations are not supported.
   1089 
   1090 **/
   1091 RETURN_STATUS
   1092 EFIAPI
   1093 S3BootScriptSavePciCfgWrite (
   1094   IN  S3_BOOT_SCRIPT_LIB_WIDTH         Width,
   1095   IN  UINT64                           Address,
   1096   IN  UINTN                            Count,
   1097   IN  VOID                            *Buffer
   1098   )
   1099 {
   1100   UINT8                 Length;
   1101   UINT8                *Script;
   1102   UINT8                 WidthInByte;
   1103   EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE  ScriptPciWrite;
   1104 
   1105   if (Width == S3BootScriptWidthUint64 ||
   1106       Width == S3BootScriptWidthFifoUint64 ||
   1107       Width == S3BootScriptWidthFillUint64) {
   1108     return EFI_INVALID_PARAMETER;
   1109   }
   1110 
   1111   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1112   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));
   1113 
   1114   Script = S3BootScriptGetEntryAddAddress (Length);
   1115   if (Script == NULL) {
   1116     return RETURN_OUT_OF_RESOURCES;
   1117   }
   1118   //
   1119   // Build script data
   1120   //
   1121   ScriptPciWrite.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;
   1122   ScriptPciWrite.Length   = Length;
   1123   ScriptPciWrite.Width    = Width;
   1124   ScriptPciWrite.Address  = Address;
   1125   ScriptPciWrite.Count    = (UINT32) Count;
   1126 
   1127   CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite,  sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
   1128   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);
   1129 
   1130   SyncBootScript (Script);
   1131 
   1132   return RETURN_SUCCESS;
   1133 }
   1134 /**
   1135   Adds a record for a PCI configuration space modify operation into a specified boot script table.
   1136 
   1137   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
   1138   @param Address   The address within the PCI configuration space.
   1139   @param Data      A pointer to the data to be OR-ed.The size depends on Width.
   1140   @param DataMask    A pointer to the data mask to be AND-ed.
   1141 
   1142   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1143   @retval RETURN__SUCCESS           Opcode is added.
   1144   @note  A known Limitations in the implementation which is 64bits operations are not supported.
   1145 
   1146 **/
   1147 RETURN_STATUS
   1148 EFIAPI
   1149 S3BootScriptSavePciCfgReadWrite (
   1150   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
   1151   IN  UINT64                            Address,
   1152   IN  VOID                              *Data,
   1153   IN  VOID                              *DataMask
   1154   )
   1155 {
   1156   UINT8                 Length;
   1157   UINT8                *Script;
   1158   UINT8                 WidthInByte;
   1159   EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE  ScriptPciReadWrite;
   1160 
   1161   if (Width == S3BootScriptWidthUint64 ||
   1162       Width == S3BootScriptWidthFifoUint64 ||
   1163       Width == S3BootScriptWidthFillUint64) {
   1164     return EFI_INVALID_PARAMETER;
   1165   }
   1166 
   1167   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1168   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));
   1169 
   1170   Script = S3BootScriptGetEntryAddAddress (Length);
   1171   if (Script == NULL) {
   1172     return RETURN_OUT_OF_RESOURCES;
   1173   }
   1174   //
   1175   // Build script data
   1176   //
   1177   ScriptPciReadWrite.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;
   1178   ScriptPciReadWrite.Length   = Length;
   1179   ScriptPciReadWrite.Width    = Width;
   1180   ScriptPciReadWrite.Address  = Address;
   1181 
   1182   CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
   1183   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);
   1184   CopyMem (
   1185     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),
   1186     DataMask,
   1187     WidthInByte
   1188     );
   1189 
   1190   SyncBootScript (Script);
   1191 
   1192   return RETURN_SUCCESS;
   1193 }
   1194 /**
   1195   Adds a record for a PCI configuration 2 space write operation into a specified boot script table.
   1196 
   1197   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
   1198   @param Segment   The PCI segment number for Address.
   1199   @param Address   The address within the PCI configuration space.
   1200   @param Count     The number of PCI operations to perform.
   1201   @param Buffer    The source buffer from which to write the data.
   1202 
   1203   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1204   @retval RETURN_SUCCESS           Opcode is added.
   1205   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
   1206 
   1207 **/
   1208 RETURN_STATUS
   1209 EFIAPI
   1210 S3BootScriptSavePciCfg2Write (
   1211   IN S3_BOOT_SCRIPT_LIB_WIDTH        Width,
   1212   IN UINT16                          Segment,
   1213   IN UINT64                          Address,
   1214   IN UINTN                           Count,
   1215   IN VOID                           *Buffer
   1216   )
   1217 {
   1218   UINT8                 Length;
   1219   UINT8                *Script;
   1220   UINT8                 WidthInByte;
   1221   EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE  ScriptPciWrite2;
   1222 
   1223   if (Segment != 0 ||
   1224       Width == S3BootScriptWidthUint64 ||
   1225       Width == S3BootScriptWidthFifoUint64 ||
   1226       Width == S3BootScriptWidthFillUint64) {
   1227     return EFI_INVALID_PARAMETER;
   1228   }
   1229 
   1230   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1231   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));
   1232 
   1233   Script = S3BootScriptGetEntryAddAddress (Length);
   1234   if (Script == NULL) {
   1235     return RETURN_OUT_OF_RESOURCES;
   1236   }
   1237   //
   1238   // Build script data
   1239   //
   1240   ScriptPciWrite2.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;
   1241   ScriptPciWrite2.Length   = Length;
   1242   ScriptPciWrite2.Width    = Width;
   1243   ScriptPciWrite2.Address  = Address;
   1244   ScriptPciWrite2.Segment  = Segment;
   1245   ScriptPciWrite2.Count    = (UINT32)Count;
   1246 
   1247   CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
   1248   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);
   1249 
   1250   SyncBootScript (Script);
   1251 
   1252   return RETURN_SUCCESS;
   1253 }
   1254 /**
   1255   Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.
   1256 
   1257   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
   1258   @param Segment   The PCI segment number for Address.
   1259   @param Address   The address within the PCI configuration space.
   1260   @param Data      A pointer to the data to be OR-ed. The size depends on Width.
   1261   @param DataMask    A pointer to the data mask to be AND-ed.
   1262 
   1263   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1264   @retval RETURN_SUCCESS           Opcode is added.
   1265   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
   1266 
   1267 **/
   1268 RETURN_STATUS
   1269 EFIAPI
   1270 S3BootScriptSavePciCfg2ReadWrite (
   1271   IN S3_BOOT_SCRIPT_LIB_WIDTH        Width,
   1272   IN UINT16                          Segment,
   1273   IN UINT64                          Address,
   1274   IN VOID                           *Data,
   1275   IN VOID                           *DataMask
   1276   )
   1277 {
   1278   UINT8                 Length;
   1279   UINT8                *Script;
   1280   UINT8                 WidthInByte;
   1281   EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE  ScriptPciReadWrite2;
   1282 
   1283   if (Segment != 0 ||
   1284       Width == S3BootScriptWidthUint64 ||
   1285       Width == S3BootScriptWidthFifoUint64 ||
   1286       Width == S3BootScriptWidthFillUint64) {
   1287     return EFI_INVALID_PARAMETER;
   1288   }
   1289 
   1290   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1291   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));
   1292 
   1293   Script = S3BootScriptGetEntryAddAddress (Length);
   1294   if (Script == NULL) {
   1295     return RETURN_OUT_OF_RESOURCES;
   1296   }
   1297   //
   1298   // Build script data
   1299   //
   1300   ScriptPciReadWrite2.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;
   1301   ScriptPciReadWrite2.Length   = Length;
   1302   ScriptPciReadWrite2.Width    = Width;
   1303   ScriptPciReadWrite2.Segment  = Segment;
   1304   ScriptPciReadWrite2.Address  = Address;
   1305 
   1306   CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
   1307   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);
   1308   CopyMem (
   1309     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),
   1310     DataMask,
   1311     WidthInByte
   1312     );
   1313 
   1314   SyncBootScript (Script);
   1315 
   1316   return RETURN_SUCCESS;
   1317 }
   1318 
   1319 /**
   1320   Checks the parameter of S3BootScriptSaveSmbusExecute().
   1321 
   1322   This function checks the input parameters of SmbusExecute().  If the input parameters are valid
   1323   for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
   1324   error code based on the input SMBus bus protocol.
   1325 
   1326   @param  SmBusAddress            Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
   1327                                   and PEC.
   1328   @param  Operation               Signifies which particular SMBus hardware protocol instance that
   1329                                   it will use to execute the SMBus transactions. This SMBus
   1330                                   hardware protocol is defined by the SMBus Specification and is
   1331                                   not related to EFI.
   1332   @param  Length                  Signifies the number of bytes that this operation will do. The
   1333                                   maximum number of bytes can be revision specific and operation
   1334                                   specific. This field will contain the actual number of bytes that
   1335                                   are executed for this operation. Not all operations require this
   1336                                   argument.
   1337   @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
   1338                                   Not all operations require this argument. The length of this
   1339                                   buffer is identified by Length.
   1340 
   1341   @retval EFI_SUCCESS             All the parameters are valid for the corresponding SMBus bus
   1342                                   protocol.
   1343   @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
   1344   @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
   1345                                   and EfiSmbusQuickWrite. Length is outside the range of valid
   1346                                   values.
   1347   @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
   1348   @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
   1349 
   1350 **/
   1351 EFI_STATUS
   1352 CheckParameters (
   1353   IN     UINTN                    SmBusAddress,
   1354   IN     EFI_SMBUS_OPERATION      Operation,
   1355   IN OUT UINTN                    *Length,
   1356   IN     VOID                     *Buffer
   1357   )
   1358 {
   1359   EFI_STATUS  Status;
   1360   UINTN       RequiredLen;
   1361   EFI_SMBUS_DEVICE_COMMAND Command;
   1362   BOOLEAN                  PecCheck;
   1363 
   1364   Command      = SMBUS_LIB_COMMAND (SmBusAddress);
   1365   PecCheck     = SMBUS_LIB_PEC (SmBusAddress);
   1366   //
   1367   // Set default value to be 2:
   1368   // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
   1369   //
   1370   RequiredLen = 2;
   1371   Status      = EFI_SUCCESS;
   1372   switch (Operation) {
   1373     case EfiSmbusQuickRead:
   1374     case EfiSmbusQuickWrite:
   1375       if (PecCheck || Command != 0) {
   1376         return EFI_UNSUPPORTED;
   1377       }
   1378       break;
   1379     case EfiSmbusReceiveByte:
   1380     case EfiSmbusSendByte:
   1381       if (Command != 0) {
   1382         return EFI_UNSUPPORTED;
   1383       }
   1384       //
   1385       // Cascade to check length parameter.
   1386       //
   1387     case EfiSmbusReadByte:
   1388     case EfiSmbusWriteByte:
   1389       RequiredLen = 1;
   1390       //
   1391       // Cascade to check length parameter.
   1392       //
   1393     case EfiSmbusReadWord:
   1394     case EfiSmbusWriteWord:
   1395     case EfiSmbusProcessCall:
   1396       if (Buffer == NULL || Length == NULL) {
   1397         return EFI_INVALID_PARAMETER;
   1398       } else if (*Length < RequiredLen) {
   1399         Status = EFI_BUFFER_TOO_SMALL;
   1400       }
   1401       *Length = RequiredLen;
   1402       break;
   1403     case EfiSmbusReadBlock:
   1404     case EfiSmbusWriteBlock:
   1405     case EfiSmbusBWBRProcessCall:
   1406       if ((Buffer == NULL) ||
   1407           (Length == NULL) ||
   1408           (*Length < MIN_SMBUS_BLOCK_LEN) ||
   1409           (*Length > MAX_SMBUS_BLOCK_LEN)) {
   1410         return EFI_INVALID_PARAMETER;
   1411       }
   1412       break;
   1413     default:
   1414       return EFI_INVALID_PARAMETER;
   1415   }
   1416   return Status;
   1417 }
   1418 
   1419 /**
   1420   Adds a record for an SMBus command execution into a specified boot script table.
   1421 
   1422   @param  SmBusAddress  Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.
   1423   @param Operation      Indicates which particular SMBus protocol it will use to execute the SMBus
   1424                         transactions.
   1425   @param Length         A pointer to signify the number of bytes that this operation will do.
   1426   @param Buffer         Contains the value of data to execute to the SMBUS slave device.
   1427 
   1428   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1429   @retval RETURN_SUCCESS           Opcode is added.
   1430 **/
   1431 RETURN_STATUS
   1432 EFIAPI
   1433 S3BootScriptSaveSmbusExecute (
   1434   IN  UINTN                             SmBusAddress,
   1435   IN  EFI_SMBUS_OPERATION               Operation,
   1436   IN  UINTN                             *Length,
   1437   IN  VOID                              *Buffer
   1438   )
   1439 {
   1440   EFI_STATUS            Status;
   1441   UINTN                 BufferLength;
   1442   UINT8                 DataSize;
   1443   UINT8                *Script;
   1444   EFI_BOOT_SCRIPT_SMBUS_EXECUTE  ScriptSmbusExecute;
   1445 
   1446   if (Length == NULL) {
   1447     BufferLength = 0;
   1448   } else {
   1449     BufferLength = *Length;
   1450   }
   1451 
   1452   Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);
   1453   if (EFI_ERROR (Status)) {
   1454     return Status;
   1455   }
   1456 
   1457   DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);
   1458 
   1459   Script = S3BootScriptGetEntryAddAddress (DataSize);
   1460   if (Script == NULL) {
   1461     return RETURN_OUT_OF_RESOURCES;
   1462   }
   1463   //
   1464   // Build script data
   1465   //
   1466   ScriptSmbusExecute.OpCode       = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;
   1467   ScriptSmbusExecute.Length       = DataSize;
   1468   ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;
   1469   ScriptSmbusExecute.Operation    = Operation;
   1470   ScriptSmbusExecute.DataSize     = (UINT32) BufferLength;
   1471 
   1472   CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));
   1473   CopyMem (
   1474     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),
   1475     Buffer,
   1476     BufferLength
   1477     );
   1478 
   1479   SyncBootScript (Script);
   1480 
   1481   return RETURN_SUCCESS;
   1482 }
   1483 /**
   1484   Adds a record for an execution stall on the processor into a specified boot script table.
   1485 
   1486   @param Duration   Duration in microseconds of the stall
   1487 
   1488   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1489   @retval RETURN_SUCCESS           Opcode is added.
   1490 **/
   1491 RETURN_STATUS
   1492 EFIAPI
   1493 S3BootScriptSaveStall (
   1494   IN  UINTN                             Duration
   1495   )
   1496 {
   1497   UINT8                 Length;
   1498   UINT8                *Script;
   1499   EFI_BOOT_SCRIPT_STALL  ScriptStall;
   1500 
   1501   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));
   1502 
   1503   Script = S3BootScriptGetEntryAddAddress (Length);
   1504   if (Script == NULL) {
   1505     return RETURN_OUT_OF_RESOURCES;
   1506   }
   1507   //
   1508   // Build script data
   1509   //
   1510   ScriptStall.OpCode    = EFI_BOOT_SCRIPT_STALL_OPCODE;
   1511   ScriptStall.Length    = Length;
   1512   ScriptStall.Duration  = Duration;
   1513 
   1514   CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));
   1515 
   1516   SyncBootScript (Script);
   1517 
   1518   return RETURN_SUCCESS;
   1519 }
   1520 /**
   1521   Adds a record for dispatching specified arbitrary code into a specified boot script table.
   1522 
   1523   @param EntryPoint   Entry point of the code to be dispatched.
   1524   @param Context      Argument to be passed into the EntryPoint of the code to be dispatched.
   1525 
   1526   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1527   @retval RETURN_SUCCESS           Opcode is added.
   1528 **/
   1529 RETURN_STATUS
   1530 EFIAPI
   1531 S3BootScriptSaveDispatch2 (
   1532   IN  VOID                      *EntryPoint,
   1533   IN  VOID                      *Context
   1534   )
   1535 {
   1536   UINT8                 Length;
   1537   UINT8                 *Script;
   1538   EFI_BOOT_SCRIPT_DISPATCH_2  ScriptDispatch2;
   1539   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
   1540 
   1541   Script = S3BootScriptGetEntryAddAddress (Length);
   1542   if (Script == NULL) {
   1543     return RETURN_OUT_OF_RESOURCES;
   1544   }
   1545   //
   1546   // Build script data
   1547   //
   1548   ScriptDispatch2.OpCode     = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;
   1549   ScriptDispatch2.Length     = Length;
   1550   ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
   1551   ScriptDispatch2.Context =   (EFI_PHYSICAL_ADDRESS)(UINTN)Context;
   1552 
   1553   CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
   1554 
   1555   SyncBootScript (Script);
   1556 
   1557   return RETURN_SUCCESS;
   1558 
   1559 }
   1560 /**
   1561   Adds a record for memory reads of the memory location and continues when the exit criteria is
   1562   satisfied or after a defined duration.
   1563 
   1564   Please aware, below interface is different with PI specification, Vol 5:
   1565   EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.
   1566   "Duration" below is microseconds, while "Delay" in PI specification means
   1567   the number of 100ns units to poll.
   1568 
   1569   @param Width     The width of the memory operations.
   1570   @param Address   The base address of the memory operations.
   1571   @param BitMask   A pointer to the bit mask to be AND-ed with the data read from the register.
   1572   @param BitValue  A pointer to the data value after to be Masked.
   1573   @param Duration  Duration in microseconds of the stall.
   1574   @param LoopTimes The times of the register polling.
   1575 
   1576   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1577   @retval RETURN_SUCCESS           Opcode is added.
   1578 
   1579 **/
   1580 RETURN_STATUS
   1581 EFIAPI
   1582 S3BootScriptSaveMemPoll (
   1583   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
   1584   IN  UINT64                            Address,
   1585   IN  VOID                              *BitMask,
   1586   IN  VOID                              *BitValue,
   1587   IN  UINTN                             Duration,
   1588   IN  UINTN                             LoopTimes
   1589   )
   1590 {
   1591   UINT8                 Length;
   1592   UINT8                *Script;
   1593   UINT8                 WidthInByte;
   1594   EFI_BOOT_SCRIPT_MEM_POLL      ScriptMemPoll;
   1595 
   1596   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1597 
   1598   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));
   1599 
   1600   Script = S3BootScriptGetEntryAddAddress (Length);
   1601   if (Script == NULL) {
   1602     return RETURN_OUT_OF_RESOURCES;
   1603   }
   1604   //
   1605   // Build script data
   1606   //
   1607   ScriptMemPoll.OpCode   = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;
   1608   ScriptMemPoll.Length   = Length;
   1609   ScriptMemPoll.Width    = Width;
   1610   ScriptMemPoll.Address  = Address;
   1611   ScriptMemPoll.Duration = Duration;
   1612   ScriptMemPoll.LoopTimes = LoopTimes;
   1613 
   1614   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);
   1615   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);
   1616   CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));
   1617 
   1618   SyncBootScript (Script);
   1619 
   1620   return RETURN_SUCCESS;
   1621 }
   1622 /**
   1623   Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only
   1624   used for debugging script issues.
   1625 
   1626   @param InformationLength   Length of the data in bytes
   1627   @param Information       Information to be logged in the boot scrpit
   1628 
   1629   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1630   @retval RETURN_SUCCESS           Opcode is added.
   1631 
   1632 **/
   1633 RETURN_STATUS
   1634 EFIAPI
   1635 S3BootScriptSaveInformation (
   1636   IN  UINT32                                InformationLength,
   1637   IN  VOID                                 *Information
   1638   )
   1639 {
   1640   UINT8                 Length;
   1641   UINT8                 *Script;
   1642   EFI_BOOT_SCRIPT_INFORMATION  ScriptInformation;
   1643 
   1644   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
   1645 
   1646   Script = S3BootScriptGetEntryAddAddress (Length);
   1647   if (Script == NULL) {
   1648     return RETURN_OUT_OF_RESOURCES;
   1649   }
   1650   //
   1651   // Build script data
   1652   //
   1653   ScriptInformation.OpCode     = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;
   1654   ScriptInformation.Length     = Length;
   1655 
   1656 
   1657   ScriptInformation.InformationLength = InformationLength;
   1658 
   1659   CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
   1660   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
   1661 
   1662   SyncBootScript (Script);
   1663 
   1664   return RETURN_SUCCESS;
   1665 
   1666 }
   1667 /**
   1668   Store a string in the boot script table. This opcode is a no-op on dispatch and is only
   1669   used for debugging script issues.
   1670 
   1671   @param String            The string to save to boot script table
   1672 
   1673   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1674   @retval RETURN_SUCCESS           Opcode is added.
   1675 
   1676 **/
   1677 RETURN_STATUS
   1678 EFIAPI
   1679 S3BootScriptSaveInformationAsciiString (
   1680   IN  CONST CHAR8               *String
   1681   )
   1682 {
   1683   return S3BootScriptSaveInformation (
   1684            (UINT32) AsciiStrLen (String) + 1,
   1685            (VOID*) String
   1686            );
   1687 }
   1688 /**
   1689   Adds a record for dispatching specified arbitrary code into a specified boot script table.
   1690 
   1691   @param EntryPoint   Entry point of the code to be dispatched.
   1692 
   1693   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1694   @retval RETURN_SUCCESS           Opcode is added.
   1695 **/
   1696 RETURN_STATUS
   1697 EFIAPI
   1698 S3BootScriptSaveDispatch (
   1699   IN  VOID                              *EntryPoint
   1700   )
   1701 {
   1702   UINT8                 Length;
   1703   UINT8                *Script;
   1704   EFI_BOOT_SCRIPT_DISPATCH  ScriptDispatch;
   1705 
   1706   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));
   1707 
   1708   Script = S3BootScriptGetEntryAddAddress (Length);
   1709   if (Script == NULL) {
   1710     return RETURN_OUT_OF_RESOURCES;
   1711   }
   1712   //
   1713   // Build script data
   1714   //
   1715   ScriptDispatch.OpCode     = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;
   1716   ScriptDispatch.Length     = Length;
   1717   ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
   1718 
   1719   CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));
   1720 
   1721   SyncBootScript (Script);
   1722 
   1723   return RETURN_SUCCESS;
   1724 
   1725 }
   1726 /**
   1727   Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a
   1728   defined duration.
   1729 
   1730   @param  Width                 The width of the I/O operations.
   1731   @param  Address               The base address of the I/O operations.
   1732   @param  Data                  The comparison value used for the polling exit criteria.
   1733   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
   1734                                 in Data are ignored when polling the memory address.
   1735   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
   1736                                 granularity so the delay may be longer.
   1737 
   1738  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1739  @retval RETURN_SUCCESS          Opcode is added.
   1740 
   1741 **/
   1742 RETURN_STATUS
   1743 EFIAPI
   1744 S3BootScriptSaveIoPoll (
   1745   IN S3_BOOT_SCRIPT_LIB_WIDTH       Width,
   1746   IN UINT64                     Address,
   1747   IN VOID                      *Data,
   1748   IN VOID                      *DataMask,
   1749   IN UINT64                     Delay
   1750   )
   1751 {
   1752   UINT8                 WidthInByte;
   1753   UINT8                *Script;
   1754   UINT8                 Length;
   1755   EFI_BOOT_SCRIPT_IO_POLL  ScriptIoPoll;
   1756 
   1757 
   1758   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1759   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
   1760 
   1761   Script = S3BootScriptGetEntryAddAddress (Length);
   1762   if (Script == NULL) {
   1763     return RETURN_OUT_OF_RESOURCES;
   1764   }
   1765   //
   1766   // Build script data
   1767   //
   1768   ScriptIoPoll.OpCode   = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;
   1769   ScriptIoPoll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
   1770   ScriptIoPoll.Width    = Width;
   1771   ScriptIoPoll.Address  = Address;
   1772   ScriptIoPoll.Delay    = Delay;
   1773 
   1774   CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));
   1775   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);
   1776   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);
   1777 
   1778   SyncBootScript (Script);
   1779 
   1780   return RETURN_SUCCESS;
   1781 }
   1782 
   1783 /**
   1784   Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
   1785   after a defined duration.
   1786 
   1787   @param  Width                 The width of the I/O operations.
   1788   @param  Address               The address within the PCI configuration space.
   1789   @param  Data                  The comparison value used for the polling exit criteria.
   1790   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
   1791                                 in Data are ignored when polling the memory address
   1792   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
   1793                                 granularity so the delay may be longer.
   1794 
   1795  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1796  @retval RETURN_SUCCESS           Opcode is added.
   1797   @note  A known Limitations in the implementation which is 64bits operations are not supported.
   1798 
   1799 **/
   1800 RETURN_STATUS
   1801 EFIAPI
   1802 S3BootScriptSavePciPoll (
   1803    IN S3_BOOT_SCRIPT_LIB_WIDTH   Width,
   1804    IN UINT64                     Address,
   1805    IN VOID                      *Data,
   1806    IN VOID                      *DataMask,
   1807    IN UINT64                     Delay
   1808 )
   1809 {
   1810   UINT8                   *Script;
   1811   UINT8                    WidthInByte;
   1812   UINT8                    Length;
   1813   EFI_BOOT_SCRIPT_PCI_CONFIG_POLL  ScriptPciPoll;
   1814 
   1815   if (Width == S3BootScriptWidthUint64 ||
   1816       Width == S3BootScriptWidthFifoUint64 ||
   1817       Width == S3BootScriptWidthFillUint64) {
   1818     return EFI_INVALID_PARAMETER;
   1819   }
   1820 
   1821   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1822   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
   1823 
   1824   Script = S3BootScriptGetEntryAddAddress (Length);
   1825   if (Script == NULL) {
   1826     return RETURN_OUT_OF_RESOURCES;
   1827   }
   1828   //
   1829   // Build script data
   1830   //
   1831   ScriptPciPoll.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;
   1832   ScriptPciPoll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
   1833   ScriptPciPoll.Width    = Width;
   1834   ScriptPciPoll.Address  = Address;
   1835   ScriptPciPoll.Delay    = Delay;
   1836 
   1837   CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
   1838   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);
   1839   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);
   1840 
   1841   SyncBootScript (Script);
   1842 
   1843   return RETURN_SUCCESS;
   1844 }
   1845 /**
   1846   Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
   1847   after a defined duration.
   1848 
   1849   @param  Width                 The width of the I/O operations.
   1850   @param  Segment               The PCI segment number for Address.
   1851   @param  Address               The address within the PCI configuration space.
   1852   @param  Data                  The comparison value used for the polling exit criteria.
   1853   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
   1854                                 in Data are ignored when polling the memory address
   1855   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
   1856                                 granularity so the delay may be longer.
   1857 
   1858  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   1859  @retval RETURN_SUCCESS           Opcode is added.
   1860   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
   1861 
   1862 **/
   1863 RETURN_STATUS
   1864 EFIAPI
   1865 S3BootScriptSavePci2Poll (
   1866    IN S3_BOOT_SCRIPT_LIB_WIDTH      Width,
   1867    IN UINT16                        Segment,
   1868    IN UINT64                        Address,
   1869    IN VOID                         *Data,
   1870    IN VOID                         *DataMask,
   1871   IN UINT64                         Delay
   1872 )
   1873 {
   1874   UINT8                    WidthInByte;
   1875   UINT8                   *Script;
   1876   UINT8                    Length;
   1877   EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL  ScriptPci2Poll;
   1878 
   1879   if (Segment != 0 ||
   1880       Width == S3BootScriptWidthUint64 ||
   1881       Width == S3BootScriptWidthFifoUint64 ||
   1882       Width == S3BootScriptWidthFillUint64) {
   1883     return EFI_INVALID_PARAMETER;
   1884   }
   1885 
   1886   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
   1887   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
   1888 
   1889   Script = S3BootScriptGetEntryAddAddress (Length);
   1890   if (Script == NULL) {
   1891     return RETURN_OUT_OF_RESOURCES;
   1892   }
   1893   //
   1894   // Build script data
   1895   //
   1896   ScriptPci2Poll.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;
   1897   ScriptPci2Poll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
   1898   ScriptPci2Poll.Width    = Width;
   1899   ScriptPci2Poll.Segment  = Segment;
   1900   ScriptPci2Poll.Address  = Address;
   1901   ScriptPci2Poll.Delay    = Delay;
   1902 
   1903   CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
   1904   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);
   1905   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);
   1906 
   1907   SyncBootScript (Script);
   1908 
   1909   return RETURN_SUCCESS;
   1910 }
   1911 /**
   1912   Do the calculation of start address from which a new s3 boot script entry will write into.
   1913 
   1914   @param EntryLength      The new entry length.
   1915   @param Position         specifies the position in the boot script table where the opcode will be
   1916                           inserted, either before or after, depending on BeforeOrAfter.
   1917   @param BeforeOrAfter    The flag to indicate to insert the nod before or after the position.
   1918                           This parameter is effective when InsertFlag is TRUE
   1919   @param Script           return out the position from which the a new s3 boot script entry will write into
   1920 **/
   1921 VOID
   1922 S3BootScriptCalculateInsertAddress (
   1923   IN  UINT8     EntryLength,
   1924   IN  VOID     *Position OPTIONAL,
   1925   IN  BOOLEAN   BeforeOrAfter OPTIONAL,
   1926   OUT UINT8   **Script
   1927   )
   1928 {
   1929    UINTN                            TableLength;
   1930    UINT8                            *S3TableBase;
   1931    UINTN                            PositionOffset;
   1932    EFI_BOOT_SCRIPT_COMMON_HEADER     ScriptHeader;
   1933    //
   1934    // The entry inserting to table is already added to the end of the table
   1935    //
   1936    TableLength =  mS3BootScriptTablePtr->TableLength - EntryLength;
   1937    S3TableBase = mS3BootScriptTablePtr->TableBase ;
   1938    //
   1939    // calculate the Position offset
   1940    //
   1941    if (Position != NULL) {
   1942      PositionOffset = (UINTN) ((UINT8 *)Position - S3TableBase);
   1943 
   1944      //
   1945      // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.
   1946      //
   1947      if (!BeforeOrAfter) {
   1948         CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
   1949         PositionOffset += (ScriptHeader.Length);
   1950      }
   1951      //
   1952      // Insert the node before the adjusted Position
   1953      //
   1954      CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
   1955      //
   1956      // calculate the the start address for the new entry.
   1957      //
   1958      *Script = S3TableBase + PositionOffset;
   1959 
   1960    } else {
   1961      if (!BeforeOrAfter) {
   1962        //
   1963        //  Insert the node to the end of the table
   1964        //
   1965        *Script = S3TableBase + TableLength;
   1966      } else {
   1967        //
   1968        // Insert the node to the beginning of the table
   1969        //
   1970        PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
   1971        CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
   1972        *Script = S3TableBase + PositionOffset;
   1973      }
   1974    }
   1975 }
   1976 /**
   1977   Move the last boot script entry to the position
   1978 
   1979   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
   1980                                 in the boot script table specified by Position. If Position is NULL or points to
   1981                                 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
   1982                                 of the table (if FALSE).
   1983   @param  Position              On entry, specifies the position in the boot script table where the opcode will be
   1984                                 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
   1985                                 the position of the inserted opcode in the boot script table.
   1986 
   1987   @retval RETURN_OUT_OF_RESOURCES  The table is not available.
   1988   @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
   1989   @retval RETURN_SUCCESS           Opcode is inserted.
   1990 **/
   1991 RETURN_STATUS
   1992 EFIAPI
   1993 S3BootScriptMoveLastOpcode (
   1994   IN     BOOLEAN                        BeforeOrAfter,
   1995   IN OUT VOID                         **Position OPTIONAL
   1996 )
   1997 {
   1998   UINT8*                Script;
   1999   VOID                  *TempPosition;
   2000   UINTN                 StartAddress;
   2001   UINT32                TableLength;
   2002   EFI_BOOT_SCRIPT_COMMON_HEADER  ScriptHeader;
   2003   BOOLEAN               ValidatePosition;
   2004   UINT8*                LastOpcode;
   2005   UINT8                 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];
   2006 
   2007   ValidatePosition = FALSE;
   2008   TempPosition = (Position == NULL) ? NULL:(*Position);
   2009 
   2010   //
   2011   // Check that the script is initialized and synced without adding an entry to the script.
   2012   //
   2013   Script = S3BootScriptGetEntryAddAddress (0);
   2014   if (Script == NULL) {
   2015     return RETURN_OUT_OF_RESOURCES;
   2016   }
   2017   Script = mS3BootScriptTablePtr->TableBase;
   2018 
   2019   StartAddress  = (UINTN) Script;
   2020   TableLength   = mS3BootScriptTablePtr->TableLength;
   2021   Script        = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
   2022   LastOpcode    = Script;
   2023   //
   2024   // Find the last boot Script Entry which is not the terminate node
   2025   //
   2026   while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
   2027     CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
   2028     if (TempPosition != NULL && TempPosition == Script) {
   2029       //
   2030       // If the position is specified, the position must be pointed to a boot script entry start address.
   2031       //
   2032       ValidatePosition = TRUE;
   2033     }
   2034     if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {
   2035       LastOpcode = Script;
   2036     }
   2037     Script  = Script + ScriptHeader.Length;
   2038   }
   2039   //
   2040   // If the position is specified, but not the start of a boot script entry, it is a invalid input
   2041   //
   2042   if (TempPosition != NULL && !ValidatePosition) {
   2043     return RETURN_INVALID_PARAMETER;
   2044   }
   2045 
   2046   CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
   2047 
   2048   CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);
   2049   //
   2050   // Find the right position to write the node in
   2051   //
   2052   S3BootScriptCalculateInsertAddress (
   2053     ScriptHeader.Length,
   2054     TempPosition,
   2055     BeforeOrAfter,
   2056     &Script
   2057   );
   2058   //
   2059   // Copy the node to Boot script table
   2060   //
   2061   CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);
   2062 
   2063   SyncBootScript (Script);
   2064 
   2065   //
   2066   // return out the Position
   2067   //
   2068   if (Position != NULL) {
   2069     *Position = Script;
   2070   }
   2071   return RETURN_SUCCESS;
   2072 }
   2073 /**
   2074   Create a Label node in the boot script table.
   2075 
   2076   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
   2077                                 in the boot script table specified by Position. If Position is NULL or points to
   2078                                 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
   2079                                 of the table (if FALSE).
   2080   @param  Position              On entry, specifies the position in the boot script table where the opcode will be
   2081                                 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
   2082                                 the position of the inserted opcode in the boot script table.
   2083   @param InformationLength      Length of the label in bytes
   2084   @param Information            Label to be logged in the boot scrpit
   2085 
   2086   @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
   2087   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
   2088   @retval RETURN_SUCCESS           Opcode is added.
   2089 
   2090 **/
   2091 RETURN_STATUS
   2092 EFIAPI
   2093 S3BootScriptLabelInternal (
   2094   IN        BOOLEAN                        BeforeOrAfter,
   2095   IN OUT    VOID                         **Position OPTIONAL,
   2096   IN        UINT32                         InformationLength,
   2097   IN CONST  CHAR8                          *Information
   2098   )
   2099 {
   2100   UINT8                 Length;
   2101   UINT8                 *Script;
   2102   EFI_BOOT_SCRIPT_INFORMATION  ScriptInformation;
   2103 
   2104   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
   2105 
   2106   Script = S3BootScriptGetEntryAddAddress (Length);
   2107   if (Script == NULL) {
   2108     return RETURN_OUT_OF_RESOURCES;
   2109   }
   2110   //
   2111   // Build script data
   2112   //
   2113   ScriptInformation.OpCode     = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;
   2114   ScriptInformation.Length     = Length;
   2115 
   2116 
   2117   ScriptInformation.InformationLength = InformationLength;
   2118 
   2119   CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
   2120   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
   2121 
   2122   SyncBootScript (Script);
   2123 
   2124   return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
   2125 
   2126 }
   2127 /**
   2128   Find a label within the boot script table and, if not present, optionally create it.
   2129 
   2130   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE)
   2131                                 or after (FALSE) the position in the boot script table
   2132                                 specified by Position.
   2133   @param  CreateIfNotFound      Specifies whether the label will be created if the label
   2134                                 does not exists (TRUE) or not (FALSE).
   2135   @param  Position              On entry, specifies the position in the boot script table
   2136                                 where the opcode will be inserted, either before or after,
   2137                                 depending on BeforeOrAfter. On exit, specifies the position
   2138                                 of the inserted opcode in the boot script table.
   2139   @param  Label                 Points to the label which will be inserted in the boot script table.
   2140 
   2141   @retval EFI_SUCCESS           The operation succeeded. A record was added into the
   2142                                 specified script table.
   2143   @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
   2144                                 If the opcode is unknow or not supported because of the PCD
   2145                                 Feature Flags.
   2146   @retval EFI_OUT_OF_RESOURCES  There is insufficient memory to store the boot script.
   2147 
   2148 **/
   2149 RETURN_STATUS
   2150 EFIAPI
   2151 S3BootScriptLabel (
   2152   IN       BOOLEAN                      BeforeOrAfter,
   2153   IN       BOOLEAN                      CreateIfNotFound,
   2154   IN OUT   VOID                       **Position OPTIONAL,
   2155   IN CONST CHAR8                       *Label
   2156   )
   2157 {
   2158   UINT8*                Script;
   2159   UINTN                 StartAddress;
   2160   UINT32                TableLength;
   2161   EFI_BOOT_SCRIPT_COMMON_HEADER  ScriptHeader;
   2162   EFI_BOOT_SCRIPT_TABLE_HEADER   TableHeader;
   2163   UINT32                         LabelLength;
   2164   //
   2165   // Check NULL Label
   2166   //
   2167   if (Label == NULL) {
   2168     return EFI_INVALID_PARAMETER;
   2169   }
   2170   //
   2171   // Check empty Label
   2172   //
   2173   if (Label[0] == '\0') {
   2174     return EFI_INVALID_PARAMETER;
   2175   }
   2176 
   2177   //
   2178   // Check that the script is initialized and synced without adding an entry to the script.
   2179   // The code must search for the label first before it knows if a new entry needs
   2180   // to be added.
   2181   //
   2182   Script = S3BootScriptGetEntryAddAddress (0);
   2183   if (Script == NULL) {
   2184     return RETURN_OUT_OF_RESOURCES;
   2185   }
   2186 
   2187   //
   2188   // Check the header and search for existing label.
   2189   //
   2190   Script = mS3BootScriptTablePtr->TableBase;
   2191   CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
   2192   if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
   2193     return EFI_INVALID_PARAMETER;
   2194   }
   2195   StartAddress  = (UINTN) Script;
   2196   TableLength   = mS3BootScriptTablePtr->TableLength;
   2197   Script    =     Script + TableHeader.Length;
   2198   while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
   2199 
   2200     CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
   2201     if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {
   2202       if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {
   2203         (*Position) = Script;
   2204         return EFI_SUCCESS;
   2205       }
   2206     }
   2207     Script  = Script + ScriptHeader.Length;
   2208   }
   2209   if (CreateIfNotFound) {
   2210     LabelLength = (UINT32)AsciiStrSize(Label);
   2211     return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label);
   2212   } else {
   2213     return EFI_NOT_FOUND;
   2214   }
   2215 }
   2216 
   2217 /**
   2218   Compare two positions in the boot script table and return their relative position.
   2219   @param  Position1             The positions in the boot script table to compare
   2220   @param  Position2             The positions in the boot script table to compare
   2221   @param  RelativePosition      On return, points to the result of the comparison
   2222 
   2223   @retval EFI_SUCCESS           The operation succeeded. A record was added into the
   2224                                 specified script table.
   2225   @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
   2226                                 If the opcode is unknow or not supported because of the PCD
   2227                                 Feature Flags.
   2228   @retval EFI_OUT_OF_RESOURCES  There is insufficient memory to store the boot script.
   2229 
   2230 **/
   2231 RETURN_STATUS
   2232 EFIAPI
   2233 S3BootScriptCompare (
   2234   IN  UINT8                       *Position1,
   2235   IN  UINT8                       *Position2,
   2236   OUT UINTN                       *RelativePosition
   2237   )
   2238 {
   2239   UINT8*                    Script;
   2240   UINT32                    TableLength;
   2241 
   2242   if (RelativePosition == NULL) {
   2243     return EFI_INVALID_PARAMETER;
   2244   }
   2245 
   2246   //
   2247   // Check that the script is initialized and synced without adding an entry to the script.
   2248   //
   2249   Script = S3BootScriptGetEntryAddAddress (0);
   2250   if (Script == NULL) {
   2251     return RETURN_OUT_OF_RESOURCES;
   2252   }
   2253   Script = mS3BootScriptTablePtr->TableBase;
   2254 
   2255   //
   2256   // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up
   2257   //
   2258   TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
   2259   if (Position1 < Script || Position1 > Script+TableLength) {
   2260     return EFI_INVALID_PARAMETER;
   2261   }
   2262   if (Position2 < Script || Position2 > Script+TableLength) {
   2263     return EFI_INVALID_PARAMETER;
   2264   }
   2265   *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1);
   2266 
   2267   return EFI_SUCCESS;
   2268 }
   2269 
   2270