Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17166 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2091 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2091 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Save the S3 data to S3 boot script. 
 | |
|  
 | |
|   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions
 | |
|   of the BSD License which accompanies this distribution.  The
 | |
|   full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| #include "InternalBootScriptLib.h"
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Data structure usage:
 | |
| 
 | |
|   +------------------------------+<-- PcdS3BootScriptTablePrivateDataPtr
 | |
|   | SCRIPT_TABLE_PRIVATE_DATA    |
 | |
|   |    TableBase                 |---
 | |
|   |    TableLength               |--|--
 | |
|   |    AtRuntime                 |  | |
 | |
|   |    InSmm                     |  | |
 | |
|   +------------------------------+  | |
 | |
|                                     | |
 | |
|   +------------------------------+<-- |
 | |
|   | EFI_BOOT_SCRIPT_TABLE_HEADER |    |
 | |
|   |    TableLength               |----|--
 | |
|   +------------------------------+    | |
 | |
|   |     ......                   |    | |
 | |
|   +------------------------------+<---- |
 | |
|   | EFI_BOOT_SCRIPT_TERMINATE    |      |
 | |
|   +------------------------------+<------
 | |
| 
 | |
| **/
 | |
| 
 | |
| SCRIPT_TABLE_PRIVATE_DATA        *mS3BootScriptTablePtr;
 | |
| EFI_EVENT                        mEnterRuntimeEvent;
 | |
| //
 | |
| // Allocate SMM copy because we can not use mS3BootScriptTablePtr when we AtRuntime in InSmm.
 | |
| //
 | |
| SCRIPT_TABLE_PRIVATE_DATA        *mS3BootScriptTableSmmPtr;
 | |
| UINTN                            mLockBoxLength;
 | |
| 
 | |
| EFI_GUID                         mBootScriptDataGuid = {
 | |
|   0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }
 | |
| };
 | |
| 
 | |
| EFI_GUID                         mBootScriptDataOrgGuid = {
 | |
|   0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }
 | |
| };
 | |
| 
 | |
| EFI_GUID                         mBootScriptHeaderDataGuid = {
 | |
|   0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   This is an internal function to add a terminate node the entry, recalculate the table 
 | |
|   length and fill into the table. 
 | |
|   
 | |
|   @return the base address of the boot script table.   
 | |
|  **/
 | |
| UINT8*
 | |
| S3BootScriptInternalCloseTable (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT8                          *S3TableBase;
 | |
|   EFI_BOOT_SCRIPT_TERMINATE      ScriptTerminate;
 | |
|   EFI_BOOT_SCRIPT_TABLE_HEADER   *ScriptTableInfo;
 | |
|   S3TableBase = mS3BootScriptTablePtr->TableBase;
 | |
|   
 | |
|   if (S3TableBase == NULL) {
 | |
|     //
 | |
|     // the table is not exist
 | |
|     //
 | |
|     return S3TableBase;
 | |
|   }
 | |
|   //
 | |
|   // Append the termination entry.
 | |
|   //
 | |
|   ScriptTerminate.OpCode  = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE;
 | |
|   ScriptTerminate.Length  = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE);
 | |
|   CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE));
 | |
|   //
 | |
|   // fill the table length
 | |
|   //
 | |
|   ScriptTableInfo                = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase);
 | |
|   ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
 | |
|   
 | |
|  
 | |
|   
 | |
|   return S3TableBase;
 | |
|   //
 | |
|   // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to 
 | |
|   // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). Because 
 | |
|   // maybe in runtime, we still need add entries into the table, and the runtime entry should be
 | |
|   // added start before this TERMINATE node.
 | |
|   //
 | |
| }  
 | |
| 
 | |
| /**
 | |
|   This function save boot script data to LockBox.
 | |
|   1. BootSriptPrivate data, BootScript data - Image and DispatchContext are handled by platform.
 | |
|   2. BootScriptExecutor, BootScriptExecutor context
 | |
|   - ACPI variable - (PI version) sould be handled by SMM driver. S3 Page table is handled here.
 | |
|   - ACPI variable - framework version is already handled by Framework CPU driver.
 | |
| **/
 | |
| VOID
 | |
| SaveBootScriptDataToLockBox (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   //
 | |
|   // mS3BootScriptTablePtr->TableLength does not include EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime.
 | |
|   // Save all info here, just in case that no one will add boot script entry in SMM.
 | |
|   //
 | |
|   Status = SaveLockBox (
 | |
|              &mBootScriptDataGuid,
 | |
|              (VOID *)mS3BootScriptTablePtr->TableBase,
 | |
|              mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE)
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // We need duplicate the original copy, because it may have INSERT boot script at runtime in SMM.
 | |
|   // If so, we should use original copy to restore data after OS rewrites the ACPINvs region.
 | |
|   // Or the data inserted may cause some original boot script data lost.
 | |
|   //
 | |
|   Status = SaveLockBox (
 | |
|              &mBootScriptDataOrgGuid,
 | |
|              (VOID *)mS3BootScriptTablePtr->TableBase,
 | |
|              mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE)
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Just need save TableBase.
 | |
|   // Do not update other field because they will NOT be used in S3.
 | |
|   //
 | |
|   Status = SaveLockBox (
 | |
|              &mBootScriptHeaderDataGuid,
 | |
|              (VOID *)&mS3BootScriptTablePtr->TableBase,
 | |
|              sizeof(mS3BootScriptTablePtr->TableBase)
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = SetLockBoxAttributes (&mBootScriptHeaderDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This is the Event call back function to notify the Library the system is entering
 | |
|   run time phase.
 | |
|   
 | |
|   @param  Event   Pointer to this event
 | |
|   @param  Context Event handler private data 
 | |
|  **/
 | |
| VOID
 | |
| EFIAPI
 | |
| S3BootScriptEventCallBack (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   VOID         *Interface;
 | |
| 
 | |
|   //
 | |
|   // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration.
 | |
|   // Just return if it is not found.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiDxeSmmReadyToLockProtocolGuid,
 | |
|                   NULL,
 | |
|                   &Interface
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Here we should tell the library that we are enter into runtime phase. and 
 | |
|   // the memory page number occupied by the table should not grow anymore.
 | |
|   //
 | |
|   if (!mS3BootScriptTablePtr->AtRuntime) {
 | |
|     //
 | |
|     // In boot time, we need not write the terminate node when adding a node to boot scipt table
 | |
|     // or else, that will impact the performance. However, in runtime, we should append terminate
 | |
|     // node on every add to boot script table
 | |
|     //
 | |
|     S3BootScriptInternalCloseTable ();
 | |
|     mS3BootScriptTablePtr->AtRuntime = TRUE;
 | |
| 
 | |
|     //
 | |
|     // Save BootScript data to lockbox
 | |
|     //
 | |
|     SaveBootScriptDataToLockBox ();
 | |
|   }
 | |
| } 
 | |
| /**
 | |
|   This is the Event call back function is triggered in SMM to notify the Library the system is entering
 | |
|   run time phase and set InSmm flag.
 | |
|   
 | |
|   @param  Protocol   Points to the protocol's unique identifier
 | |
|   @param  Interface  Points to the interface instance
 | |
|   @param  Handle     The handle on which the interface was installed
 | |
| 
 | |
|   @retval EFI_SUCCESS SmmEventCallback runs successfully
 | |
|  **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSmmEventCallBack (
 | |
|   IN CONST EFI_GUID  *Protocol,
 | |
|   IN VOID            *Interface,
 | |
|   IN EFI_HANDLE      Handle
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Check if it is already done
 | |
|   //
 | |
|   if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Last chance to call-out, just make sure AtRuntime is set
 | |
|   //
 | |
|   S3BootScriptEventCallBack (NULL, NULL);
 | |
| 
 | |
|   //
 | |
|   // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.
 | |
|   //
 | |
|   if (mS3BootScriptTableSmmPtr->TableBase == NULL) {
 | |
|     CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));
 | |
|   }
 | |
|   //
 | |
|   // We should not use ACPINvs copy, because it is not safe.
 | |
|   //
 | |
|   mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;
 | |
| 
 | |
|   //
 | |
|   // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.
 | |
|   // InSmm will only be checked if AtRuntime is TRUE.
 | |
|   //
 | |
|   mS3BootScriptTablePtr->InSmm = TRUE;
 | |
| 
 | |
|   //
 | |
|   // Record LockBoxLength
 | |
|   //
 | |
|   mLockBoxLength = mS3BootScriptTableSmmPtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Library Constructor.
 | |
|   this function just identify it is a smm driver or non-smm driver linked against 
 | |
|   with the library   
 | |
| 
 | |
|   @param  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable   A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval  RETURN_SUCCESS            Allocate the global memory space to store S3 boot script table private data
 | |
|   @retval  RETURN_OUT_OF_RESOURCES   No enough memory to allocated.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptLibInitialize (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   SCRIPT_TABLE_PRIVATE_DATA      *S3TablePtr;
 | |
|   SCRIPT_TABLE_PRIVATE_DATA      *S3TableSmmPtr;
 | |
|   VOID                           *Registration;
 | |
|   EFI_SMM_BASE2_PROTOCOL         *SmmBase2;
 | |
|   BOOLEAN                        InSmm;
 | |
|   EFI_SMM_SYSTEM_TABLE2          *Smst;
 | |
|   EFI_PHYSICAL_ADDRESS           Buffer;
 | |
| 
 | |
|   S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);
 | |
|   //
 | |
|   // The Boot script private data is not be initialized. create it
 | |
|   //
 | |
|   if (S3TablePtr == 0) {
 | |
|     Buffer = SIZE_4GB - 1;
 | |
|     Status = gBS->AllocatePages (
 | |
|                     AllocateMaxAddress,
 | |
|                     EfiACPIMemoryNVS,
 | |
|                     EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),
 | |
|                     &Buffer
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return RETURN_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     S3TablePtr = (VOID *) (UINTN) Buffer;
 | |
| 
 | |
|     PcdSet64 (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr); 
 | |
|     ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));  
 | |
|     //
 | |
|     // create event to notify the library system enter the runtime phase
 | |
|     //
 | |
|     mEnterRuntimeEvent = EfiCreateProtocolNotifyEvent  (
 | |
|                           &gEfiDxeSmmReadyToLockProtocolGuid,
 | |
|                           TPL_CALLBACK,
 | |
|                           S3BootScriptEventCallBack,
 | |
|                           NULL,
 | |
|                           &Registration
 | |
|                           );
 | |
|     ASSERT (mEnterRuntimeEvent != NULL);
 | |
|   } 
 | |
|   mS3BootScriptTablePtr = S3TablePtr;
 | |
| 
 | |
|   //
 | |
|   // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return RETURN_SUCCESS;
 | |
|   }
 | |
|   Status = SmmBase2->InSmm (SmmBase2, &InSmm);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return RETURN_SUCCESS;
 | |
|   }
 | |
|   if (!InSmm) {
 | |
|     return RETURN_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Good, we are in SMM
 | |
|   //
 | |
|   Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return RETURN_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);
 | |
|   //
 | |
|   // The Boot script private data in SMM is not be initialized. create it
 | |
|   //
 | |
|   if (S3TableSmmPtr == 0) {
 | |
|     Status = Smst->SmmAllocatePool (
 | |
|                      EfiRuntimeServicesData,
 | |
|                      sizeof(SCRIPT_TABLE_PRIVATE_DATA),
 | |
|                      (VOID **) &S3TableSmmPtr
 | |
|                      );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return RETURN_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     PcdSet64 (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);
 | |
|     ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
 | |
|   }
 | |
|   mS3BootScriptTableSmmPtr = S3TableSmmPtr;
 | |
| 
 | |
|   //
 | |
|   // Then register event after lock
 | |
|   //
 | |
|   Registration = NULL;
 | |
|   Status = Smst->SmmRegisterProtocolNotify (
 | |
|                    &gEfiSmmReadyToLockProtocolGuid,
 | |
|                    S3BootScriptSmmEventCallBack,
 | |
|                    &Registration
 | |
|                    );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   To get the start address from which a new boot time s3 boot script entry will write into.
 | |
|   If the table is not exist, the functio will first allocate a buffer for the table
 | |
|   If the table buffer is not enough for the new entry, in non-smm mode, the funtion will 
 | |
|   invoke reallocate to enlarge buffer.
 | |
|   
 | |
|   @param EntryLength      the new entry length.
 | |
|   
 | |
|   @retval the address from which the a new s3 boot script entry will write into 
 | |
|  **/
 | |
| UINT8*
 | |
| S3BootScriptGetBootTimeEntryAddAddress (
 | |
|   UINT8  EntryLength
 | |
|   )
 | |
| {
 | |
|    EFI_PHYSICAL_ADDRESS              S3TableBase;
 | |
|    EFI_PHYSICAL_ADDRESS              NewS3TableBase;
 | |
|    UINT8                            *NewEntryPtr;
 | |
|    UINT32                            TableLength;
 | |
|    UINT16                            PageNumber;
 | |
|    EFI_STATUS                        Status;
 | |
|    EFI_BOOT_SCRIPT_TABLE_HEADER      *ScriptTableInfo;
 | |
|    
 | |
|    S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);
 | |
|    if (S3TableBase == 0) {
 | |
|      // The table is not exist. This is the first to add entry. 
 | |
|      // Allocate ACPI script table space under 4G memory. We need it to save
 | |
|      // some settings done by CSM, which runs after normal script table closed
 | |
|      //
 | |
|      S3TableBase = 0xffffffff;
 | |
|      Status = gBS->AllocatePages (
 | |
|                   AllocateMaxAddress,
 | |
|                   EfiACPIMemoryNVS,
 | |
|                   2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
 | |
|                   (EFI_PHYSICAL_ADDRESS*)&S3TableBase
 | |
|                   );
 | |
|      
 | |
|      if (EFI_ERROR(Status)) {
 | |
|        ASSERT_EFI_ERROR (Status);
 | |
|        return 0;
 | |
|      }
 | |
|      //
 | |
|      // Fill Table Header
 | |
|      //
 | |
|      ScriptTableInfo              = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;
 | |
|      ScriptTableInfo->OpCode      = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
 | |
|      ScriptTableInfo->Length      = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|      ScriptTableInfo->Version     = BOOT_SCRIPT_TABLE_VERSION;
 | |
|      ScriptTableInfo->TableLength = 0;   // will be calculate at CloseTable
 | |
|      mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|      mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;
 | |
|      mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
 | |
|    }
 | |
|      
 | |
|    // Here we do not count the reserved memory for runtime script table.
 | |
|    PageNumber   = (UINT16)(mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));   
 | |
|    TableLength =  mS3BootScriptTablePtr->TableLength;
 | |
|    if ((UINT32)(PageNumber * EFI_PAGE_SIZE) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {
 | |
|      // 
 | |
|      // The buffer is too small to hold the table, Reallocate the buffer
 | |
|      //
 | |
|      NewS3TableBase = 0xffffffff;
 | |
|      Status = gBS->AllocatePages (
 | |
|                   AllocateMaxAddress,
 | |
|                   EfiACPIMemoryNVS,
 | |
|                   2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
 | |
|                   (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase
 | |
|                   );
 | |
|    
 | |
|      if (EFI_ERROR(Status)) {
 | |
|        ASSERT_EFI_ERROR (Status);
 | |
|        return 0;
 | |
|      }
 | |
|      
 | |
|      CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength);
 | |
|      gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber);
 | |
|          
 | |
|      mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase;
 | |
|      mS3BootScriptTablePtr->TableMemoryPageNumber =  (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); 
 | |
|    }
 | |
|    //
 | |
|    // calculate the the start address for the new entry. 
 | |
|    //
 | |
|    NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength;
 | |
|    
 | |
|    //
 | |
|    // update the table lenghth
 | |
|    //
 | |
|    mS3BootScriptTablePtr->TableLength =  TableLength + EntryLength;
 | |
|    
 | |
|    //
 | |
|    // In the boot time, we will not append the termination entry to the boot script
 | |
|    // table until the callers think there is no boot time data that should be added and 
 | |
|    // it is caller's responsibility to explicit call the CloseTable. 
 | |
|    //
 | |
|    //
 | |
|   
 | |
|    return NewEntryPtr;    
 | |
| }
 | |
| /**
 | |
|   To get the start address from which a new runtime s3 boot script entry will write into.
 | |
|   In this case, it should be ensured that there is enough buffer to hold the entry.
 | |
|   
 | |
|   @param EntryLength      the new entry length.
 | |
|   
 | |
|   @retval the address from which the a new s3 runtime script entry will write into
 | |
|  **/
 | |
| UINT8*
 | |
| S3BootScriptGetRuntimeEntryAddAddress (
 | |
|   UINT8  EntryLength
 | |
|   )
 | |
| {
 | |
|    UINT8     *NewEntryPtr;
 | |
|    
 | |
|    NewEntryPtr = NULL;   
 | |
|    //
 | |
|    // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node. 
 | |
|    //
 | |
|    if (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE) <= EFI_PAGES_TO_SIZE((UINT32)(mS3BootScriptTablePtr->TableMemoryPageNumber))) {
 | |
|      NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength;   
 | |
|      mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;
 | |
|      //
 | |
|      // Append a terminate node on every insert
 | |
|      //
 | |
|      S3BootScriptInternalCloseTable ();
 | |
|    }
 | |
|    return (UINT8*)NewEntryPtr;    
 | |
| }
 | |
| /**
 | |
|   To get the start address from which a new s3 boot script entry will write into.
 | |
|   
 | |
|   @param EntryLength      the new entry length.
 | |
|   
 | |
|   @retval the address from which the a new s3 runtime script entry will write into 
 | |
|  **/ 
 | |
| UINT8* 
 | |
| S3BootScriptGetEntryAddAddress (
 | |
|   UINT8  EntryLength
 | |
|   )
 | |
| {
 | |
|   UINT8*                         NewEntryPtr;
 | |
|   EFI_BOOT_SCRIPT_TABLE_HEADER   TableHeader;
 | |
|   EFI_STATUS                     Status;
 | |
|   UINTN                          OrgLockBoxLength;
 | |
| 
 | |
|   if (mS3BootScriptTablePtr->AtRuntime) {
 | |
|     //
 | |
|     // We need check InSmm when AtRuntime, because after SmmReadyToLock, only SMM driver is allowed to write boot script.
 | |
|     //
 | |
|     if (!mS3BootScriptTablePtr->InSmm) {
 | |
|       //
 | |
|       // Add DEBUG ERROR, so that we can find it at boot time.
 | |
|       // Do not use ASSERT, because we may have test invoke this interface.
 | |
|       //
 | |
|       DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script after ReadyToLock!!!\n"));
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // NOTE: OS will restore ACPINvs data. After S3, the table length in mS3BootScriptTableSmmPtr (SMM) is different with
 | |
|     // table length in BootScriptTable header (ACPINvs).
 | |
|     // So here we need sync them. We choose ACPINvs table length, because we want to override the boot script saved
 | |
|     // in SMM every time.
 | |
|     //
 | |
|     ASSERT (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr);
 | |
|     CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
 | |
|     if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) {
 | |
|       //
 | |
|       // Restore it to use original value
 | |
|       //
 | |
|       OrgLockBoxLength = mLockBoxLength;
 | |
|       Status = RestoreLockBox (
 | |
|                  &mBootScriptDataOrgGuid,
 | |
|                  (VOID *)mS3BootScriptTablePtr->TableBase,
 | |
|                  &OrgLockBoxLength
 | |
|                  );
 | |
|      ASSERT_EFI_ERROR (Status);
 | |
|      ASSERT (OrgLockBoxLength == mLockBoxLength);
 | |
| 
 | |
|       //
 | |
|       // Update the current BootScriptData into LockBox as well
 | |
|       //
 | |
|       Status = UpdateLockBox (
 | |
|                  &mBootScriptDataGuid,
 | |
|                  0,
 | |
|                  (VOID *)mS3BootScriptTablePtr->TableBase,
 | |
|                  OrgLockBoxLength
 | |
|                  );
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|       //
 | |
|       // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length.
 | |
|       //
 | |
|       mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE));
 | |
|     }
 | |
| 
 | |
|     NewEntryPtr  = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);
 | |
| 
 | |
|     if (EntryLength != 0) {
 | |
|       //
 | |
|       // Now the length field is updated, need sync to lockbox.
 | |
|       // So in S3 resume, the data can be restored correctly.
 | |
|       //
 | |
|       CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
 | |
|       Status = UpdateLockBox (
 | |
|                  &mBootScriptDataGuid,
 | |
|                  OFFSET_OF(EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),
 | |
|                  &TableHeader.TableLength,
 | |
|                  sizeof(TableHeader.TableLength)
 | |
|                  );
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|     }
 | |
|   } else {   
 | |
|     NewEntryPtr  = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);
 | |
|   }  
 | |
|   return NewEntryPtr;
 | |
|   
 | |
| }  
 | |
| 
 | |
| /**
 | |
|   Sync BootScript LockBox data.
 | |
| 
 | |
|   @param Script           The address from where the boot script has been added or updated.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SyncBootScript (
 | |
|   IN UINT8      *Script
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       ScriptOffset;
 | |
| 
 | |
|   ScriptOffset = (UINTN) (Script - mS3BootScriptTablePtr->TableBase);
 | |
| 
 | |
|   if (!mS3BootScriptTablePtr->AtRuntime || !mS3BootScriptTablePtr->InSmm || ScriptOffset >= mLockBoxLength) {
 | |
|     //
 | |
|     // If it is not at runtime in SMM or in the range that needs to be synced in LockBox, just return.
 | |
|     //
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update BootScriptData
 | |
|   // So in S3 resume, the data can be restored correctly.
 | |
|   //
 | |
|   Status = UpdateLockBox (
 | |
|              &mBootScriptDataGuid,
 | |
|              ScriptOffset,
 | |
|              (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),
 | |
|              mLockBoxLength - ScriptOffset
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| }
 | |
| 
 | |
| /** 
 | |
|   This is an function to close the S3 boot script table. The function could only be called in 
 | |
|   BOOT time phase. To comply with the Framework spec definition on 
 | |
|   EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things:
 | |
|   1. Closes the specified boot script table
 | |
|   2. It allocates a new memory pool to duplicate all the boot scripts in the specified table. 
 | |
|      Once this function is called, the table maintained by the library will be destroyed 
 | |
|      after it is copied into the allocated pool.
 | |
|   3. Any attempts to add a script record after calling this function will cause a new table 
 | |
|      to be created by the library.
 | |
|   4. The base address of the allocated pool will be returned in Address. Note that after 
 | |
|      using the boot script table, the CALLER is responsible for freeing the pool that is allocated
 | |
|      by this function. 
 | |
| 
 | |
|   In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is 
 | |
|   for Framework Spec compatibility.
 | |
|   
 | |
|   If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out 
 | |
|   how to get the script to run on an S3 resume because the boot script maintained by the lib will be 
 | |
|   destroyed.
 | |
|  
 | |
|   @return the base address of the new copy of the boot script table.   
 | |
|   @note this function could only called in boot time phase
 | |
| 
 | |
| **/
 | |
| UINT8*
 | |
| EFIAPI
 | |
| S3BootScriptCloseTable (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT8                          *S3TableBase;
 | |
|   UINT32                          TableLength;
 | |
|   UINT8                          *Buffer;
 | |
|   EFI_STATUS                      Status;
 | |
|   EFI_BOOT_SCRIPT_TABLE_HEADER      *ScriptTableInfo;
 | |
|   
 | |
|   S3TableBase =    mS3BootScriptTablePtr->TableBase;    
 | |
|   if (S3TableBase == 0) {
 | |
|     return 0; 
 | |
|   }
 | |
|   //
 | |
|   // Append the termination record the S3 boot script table
 | |
|   //
 | |
|   S3BootScriptInternalCloseTable();
 | |
|   TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
 | |
|   //
 | |
|   // Allocate the buffer and copy the boot script to the buffer. 
 | |
|   //
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   (UINTN)TableLength,
 | |
|                   (VOID **) &Buffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|         return 0; 
 | |
|   }
 | |
|   CopyMem (Buffer, S3TableBase, TableLength);
 | |
|   
 | |
|   //
 | |
|   // Destroy the table maintained by the library so that the next write operation 
 | |
|   // will write the record to the first entry of the table.
 | |
|   //
 | |
|   // Fill the table header.
 | |
|   ScriptTableInfo                    = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase;
 | |
|   ScriptTableInfo->OpCode      = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
 | |
|   ScriptTableInfo->Length      = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|   ScriptTableInfo->TableLength = 0;   // will be calculate at close the table
 | |
|   
 | |
|   mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|   return Buffer;
 | |
| }
 | |
| /**
 | |
|   Save I/O write to boot script 
 | |
| 
 | |
|   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address The base address of the I/O operations.
 | |
|   @param Count   The number of I/O operations to perform.
 | |
|   @param Buffer  The source buffer from which to write data.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveIoWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
 | |
|   IN  UINT64                            Address,
 | |
|   IN  UINTN                             Count,
 | |
|   IN  VOID                              *Buffer
 | |
|   )
 | |
| 
 | |
| {
 | |
|   UINT8                     Length;
 | |
|   UINT8                    *Script;
 | |
|   UINT8                     WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_IO_WRITE  ScriptIoWrite;
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // save script data
 | |
|   //
 | |
|   ScriptIoWrite.OpCode  = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;
 | |
|   ScriptIoWrite.Length  = Length;
 | |
|   ScriptIoWrite.Width   = Width;
 | |
|   ScriptIoWrite.Address = Address;
 | |
|   ScriptIoWrite.Count   = (UINT32) Count;
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Adds a record for an I/O modify operation into a S3 boot script table
 | |
| 
 | |
|   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address The base address of the I/O operations.
 | |
|   @param Data    A pointer to the data to be OR-ed.
 | |
|   @param DataMask  A pointer to the data mask to be AND-ed with the data read from the register
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveIoReadWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH         Width,
 | |
|   IN  UINT64                           Address,
 | |
|   IN  VOID                            *Data,
 | |
|   IN  VOID                            *DataMask
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_IO_READ_WRITE  ScriptIoReadWrite;
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptIoReadWrite.OpCode  = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;
 | |
|   ScriptIoReadWrite.Length  = Length;
 | |
|   ScriptIoReadWrite.Width   = Width;
 | |
|   ScriptIoReadWrite.Address = Address;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a memory write operation into a specified boot script table.
 | |
| 
 | |
|   @param Width   The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address The base address of the memory operations
 | |
|   @param Count   The number of memory operations to perform.
 | |
|   @param Buffer  The source buffer from which to write the data.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveMemWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
 | |
|   IN  UINT64                            Address,
 | |
|   IN  UINTN                             Count,
 | |
|   IN  VOID                              *Buffer
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_MEM_WRITE  ScriptMemWrite;
 | |
|   
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptMemWrite.OpCode   = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;
 | |
|   ScriptMemWrite.Length   = Length;
 | |
|   ScriptMemWrite.Width    = Width;
 | |
|   ScriptMemWrite.Address  = Address;
 | |
|   ScriptMemWrite.Count    = (UINT32) Count;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a memory modify operation into a specified boot script table.
 | |
| 
 | |
|   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address   The base address of the memory operations. Address needs alignment if required
 | |
|   @param Data      A pointer to the data to be OR-ed.
 | |
|   @param DataMask  A pointer to the data mask to be AND-ed with the data read from the register.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveMemReadWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
 | |
|   IN  UINT64                            Address,
 | |
|   IN  VOID                              *Data,
 | |
|   IN  VOID                              *DataMask
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_MEM_READ_WRITE  ScriptMemReadWrite;
 | |
|  
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   } 
 | |
|   //
 | |
|   // Build script data
 | |
|   //    
 | |
|   ScriptMemReadWrite.OpCode   = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;
 | |
|   ScriptMemReadWrite.Length   = Length;
 | |
|   ScriptMemReadWrite.Width    = Width;
 | |
|   ScriptMemReadWrite.Address  = Address;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a PCI configuration space write operation into a specified boot script table.
 | |
| 
 | |
|   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address   The address within the PCI configuration space.
 | |
|   @param Count     The number of PCI operations to perform.
 | |
|   @param Buffer    The source buffer from which to write the data.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePciCfgWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH         Width,
 | |
|   IN  UINT64                           Address,
 | |
|   IN  UINTN                            Count,
 | |
|   IN  VOID                            *Buffer
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE  ScriptPciWrite;
 | |
| 
 | |
|   if (Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   } 
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptPciWrite.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;
 | |
|   ScriptPciWrite.Length   = Length;
 | |
|   ScriptPciWrite.Width    = Width;
 | |
|   ScriptPciWrite.Address  = Address;
 | |
|   ScriptPciWrite.Count    = (UINT32) Count;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite,  sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a PCI configuration space modify operation into a specified boot script table.
 | |
| 
 | |
|   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Address   The address within the PCI configuration space.
 | |
|   @param Data      A pointer to the data to be OR-ed.The size depends on Width.
 | |
|   @param DataMask    A pointer to the data mask to be AND-ed.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN__SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePciCfgReadWrite (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
 | |
|   IN  UINT64                            Address,
 | |
|   IN  VOID                              *Data,
 | |
|   IN  VOID                              *DataMask
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE  ScriptPciReadWrite;
 | |
| 
 | |
|   if (Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   // 
 | |
|   ScriptPciReadWrite.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;
 | |
|   ScriptPciReadWrite.Length   = Length;
 | |
|   ScriptPciReadWrite.Width    = Width;
 | |
|   ScriptPciReadWrite.Address  = Address;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);
 | |
|   CopyMem (
 | |
|     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),
 | |
|     DataMask,
 | |
|     WidthInByte
 | |
|     );
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a PCI configuration 2 space write operation into a specified boot script table.
 | |
| 
 | |
|   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Segment   The PCI segment number for Address.
 | |
|   @param Address   The address within the PCI configuration space.
 | |
|   @param Count     The number of PCI operations to perform.
 | |
|   @param Buffer    The source buffer from which to write the data.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePciCfg2Write (
 | |
|   IN S3_BOOT_SCRIPT_LIB_WIDTH        Width,
 | |
|   IN UINT16                          Segment,
 | |
|   IN UINT64                          Address,
 | |
|   IN UINTN                           Count,
 | |
|   IN VOID                           *Buffer
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE  ScriptPciWrite2;
 | |
| 
 | |
|   if (Segment != 0 ||
 | |
|       Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptPciWrite2.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;
 | |
|   ScriptPciWrite2.Length   = Length;
 | |
|   ScriptPciWrite2.Width    = Width;
 | |
|   ScriptPciWrite2.Address  = Address;
 | |
|   ScriptPciWrite2.Segment  = Segment;
 | |
|   ScriptPciWrite2.Count    = (UINT32)Count;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.
 | |
| 
 | |
|   @param Width     The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
 | |
|   @param Segment   The PCI segment number for Address.
 | |
|   @param Address   The address within the PCI configuration space.
 | |
|   @param Data      A pointer to the data to be OR-ed. The size depends on Width.
 | |
|   @param DataMask    A pointer to the data mask to be AND-ed.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePciCfg2ReadWrite (
 | |
|   IN S3_BOOT_SCRIPT_LIB_WIDTH        Width,
 | |
|   IN UINT16                          Segment,
 | |
|   IN UINT64                          Address,
 | |
|   IN VOID                           *Data,
 | |
|   IN VOID                           *DataMask
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE  ScriptPciReadWrite2;
 | |
| 
 | |
|   if (Segment != 0 ||
 | |
|       Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptPciReadWrite2.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;
 | |
|   ScriptPciReadWrite2.Length   = Length;
 | |
|   ScriptPciReadWrite2.Width    = Width;
 | |
|   ScriptPciReadWrite2.Segment  = Segment;
 | |
|   ScriptPciReadWrite2.Address  = Address;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);
 | |
|   CopyMem (
 | |
|     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),
 | |
|     DataMask,
 | |
|     WidthInByte
 | |
|     );
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Checks the parameter of S3BootScriptSaveSmbusExecute().
 | |
| 
 | |
|   This function checks the input parameters of SmbusExecute().  If the input parameters are valid
 | |
|   for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
 | |
|   error code based on the input SMBus bus protocol.
 | |
| 
 | |
|   @param  SmBusAddress            Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, 
 | |
|                                   and PEC.
 | |
|   @param  Operation               Signifies which particular SMBus hardware protocol instance that
 | |
|                                   it will use to execute the SMBus transactions. This SMBus
 | |
|                                   hardware protocol is defined by the SMBus Specification and is
 | |
|                                   not related to EFI.
 | |
|   @param  Length                  Signifies the number of bytes that this operation will do. The
 | |
|                                   maximum number of bytes can be revision specific and operation
 | |
|                                   specific. This field will contain the actual number of bytes that
 | |
|                                   are executed for this operation. Not all operations require this
 | |
|                                   argument.
 | |
|   @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
 | |
|                                   Not all operations require this argument. The length of this
 | |
|                                   buffer is identified by Length.
 | |
| 
 | |
|   @retval EFI_SUCCESS             All the parameters are valid for the corresponding SMBus bus
 | |
|                                   protocol. 
 | |
|   @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
 | |
|   @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
 | |
|                                   and EfiSmbusQuickWrite. Length is outside the range of valid
 | |
|                                   values.
 | |
|   @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
 | |
|   @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CheckParameters (
 | |
|   IN     UINTN                    SmBusAddress,
 | |
|   IN     EFI_SMBUS_OPERATION      Operation,
 | |
|   IN OUT UINTN                    *Length,
 | |
|   IN     VOID                     *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       RequiredLen;
 | |
|   EFI_SMBUS_DEVICE_COMMAND Command;
 | |
|   BOOLEAN                  PecCheck;
 | |
|  
 | |
|   Command      = SMBUS_LIB_COMMAND (SmBusAddress);
 | |
|   PecCheck     = SMBUS_LIB_PEC (SmBusAddress);
 | |
|   //
 | |
|   // Set default value to be 2:
 | |
|   // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall. 
 | |
|   //
 | |
|   RequiredLen = 2;
 | |
|   Status      = EFI_SUCCESS;
 | |
|   switch (Operation) {
 | |
|     case EfiSmbusQuickRead:
 | |
|     case EfiSmbusQuickWrite:
 | |
|       if (PecCheck || Command != 0) {
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|       break;
 | |
|     case EfiSmbusReceiveByte:
 | |
|     case EfiSmbusSendByte:
 | |
|       if (Command != 0) {
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|       //
 | |
|       // Cascade to check length parameter.
 | |
|       //
 | |
|     case EfiSmbusReadByte:
 | |
|     case EfiSmbusWriteByte:
 | |
|       RequiredLen = 1;
 | |
|       //
 | |
|       // Cascade to check length parameter.
 | |
|       //
 | |
|     case EfiSmbusReadWord:
 | |
|     case EfiSmbusWriteWord:
 | |
|     case EfiSmbusProcessCall:
 | |
|       if (Buffer == NULL || Length == NULL) {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       } else if (*Length < RequiredLen) {
 | |
|         Status = EFI_BUFFER_TOO_SMALL;
 | |
|       }
 | |
|       *Length = RequiredLen;
 | |
|       break;
 | |
|     case EfiSmbusReadBlock:
 | |
|     case EfiSmbusWriteBlock:
 | |
|     case EfiSmbusBWBRProcessCall:
 | |
|       if ((Buffer == NULL) || 
 | |
|           (Length == NULL) || 
 | |
|           (*Length < MIN_SMBUS_BLOCK_LEN) ||
 | |
|           (*Length > MAX_SMBUS_BLOCK_LEN)) {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
|       break;
 | |
|     default:
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Adds a record for an SMBus command execution into a specified boot script table.
 | |
| 
 | |
|   @param  SmBusAddress  Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.
 | |
|   @param Operation      Indicates which particular SMBus protocol it will use to execute the SMBus
 | |
|                         transactions.
 | |
|   @param Length         A pointer to signify the number of bytes that this operation will do.
 | |
|   @param Buffer         Contains the value of data to execute to the SMBUS slave device.
 | |
|   
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveSmbusExecute (
 | |
|   IN  UINTN                             SmBusAddress, 
 | |
|   IN  EFI_SMBUS_OPERATION               Operation,
 | |
|   IN  UINTN                             *Length,
 | |
|   IN  VOID                              *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   UINTN                 BufferLength;
 | |
|   UINT8                 DataSize;
 | |
|   UINT8                *Script;
 | |
|   EFI_BOOT_SCRIPT_SMBUS_EXECUTE  ScriptSmbusExecute;
 | |
| 
 | |
|   if (Length == NULL) {
 | |
|     BufferLength = 0;
 | |
|   } else {
 | |
|     BufferLength = *Length;
 | |
|   }
 | |
| 
 | |
|   Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (DataSize);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptSmbusExecute.OpCode       = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;
 | |
|   ScriptSmbusExecute.Length       = DataSize;
 | |
|   ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;
 | |
|   ScriptSmbusExecute.Operation    = Operation;
 | |
|   ScriptSmbusExecute.DataSize     = (UINT32) BufferLength;
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));
 | |
|   CopyMem (
 | |
|     (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),
 | |
|     Buffer,
 | |
|     BufferLength
 | |
|     );
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for an execution stall on the processor into a specified boot script table.
 | |
| 
 | |
|   @param Duration   Duration in microseconds of the stall
 | |
|   
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveStall (
 | |
|   IN  UINTN                             Duration
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   EFI_BOOT_SCRIPT_STALL  ScriptStall;
 | |
| 
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptStall.OpCode    = EFI_BOOT_SCRIPT_STALL_OPCODE;
 | |
|   ScriptStall.Length    = Length;
 | |
|   ScriptStall.Duration  = Duration;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for dispatching specified arbitrary code into a specified boot script table.
 | |
| 
 | |
|   @param EntryPoint   Entry point of the code to be dispatched.
 | |
|   @param Context      Argument to be passed into the EntryPoint of the code to be dispatched.
 | |
|   
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveDispatch2 (
 | |
|   IN  VOID                      *EntryPoint,
 | |
|   IN  VOID                      *Context
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                 *Script;
 | |
|   EFI_BOOT_SCRIPT_DISPATCH_2  ScriptDispatch2;
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptDispatch2.OpCode     = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;
 | |
|   ScriptDispatch2.Length     = Length;
 | |
|   ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
 | |
|   ScriptDispatch2.Context =   (EFI_PHYSICAL_ADDRESS)(UINTN)Context;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| 
 | |
| }
 | |
| /**
 | |
|   Adds a record for memory reads of the memory location and continues when the exit criteria is
 | |
|   satisfied or after a defined duration.
 | |
| 
 | |
|   Please aware, below interface is different with PI specification, Vol 5:
 | |
|   EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.
 | |
|   "Duration" below is microseconds, while "Delay" in PI specification means
 | |
|   the number of 100ns units to poll.
 | |
| 
 | |
|   @param Width     The width of the memory operations.
 | |
|   @param Address   The base address of the memory operations.
 | |
|   @param BitMask   A pointer to the bit mask to be AND-ed with the data read from the register.
 | |
|   @param BitValue  A pointer to the data value after to be Masked.
 | |
|   @param Duration  Duration in microseconds of the stall.
 | |
|   @param LoopTimes The times of the register polling.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveMemPoll (
 | |
|   IN  S3_BOOT_SCRIPT_LIB_WIDTH          Width,
 | |
|   IN  UINT64                            Address,
 | |
|   IN  VOID                              *BitMask,
 | |
|   IN  VOID                              *BitValue,
 | |
|   IN  UINTN                             Duration,
 | |
|   IN  UINTN                             LoopTimes
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   UINT8                 WidthInByte; 
 | |
|   EFI_BOOT_SCRIPT_MEM_POLL      ScriptMemPoll; 
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptMemPoll.OpCode   = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;
 | |
|   ScriptMemPoll.Length   = Length;
 | |
|   ScriptMemPoll.Width    = Width;  
 | |
|   ScriptMemPoll.Address  = Address;
 | |
|   ScriptMemPoll.Duration = Duration;
 | |
|   ScriptMemPoll.LoopTimes = LoopTimes;
 | |
| 
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL)); 
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only
 | |
|   used for debugging script issues.
 | |
|   
 | |
|   @param InformationLength   Length of the data in bytes
 | |
|   @param Information       Information to be logged in the boot scrpit
 | |
|  
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveInformation (
 | |
|   IN  UINT32                                InformationLength, 
 | |
|   IN  VOID                                 *Information
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                 *Script;
 | |
|   EFI_BOOT_SCRIPT_INFORMATION  ScriptInformation;
 | |
| 
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
 | |
| 
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptInformation.OpCode     = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;
 | |
|   ScriptInformation.Length     = Length;
 | |
| 
 | |
| 
 | |
|   ScriptInformation.InformationLength = InformationLength;  
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| 
 | |
| }
 | |
| /**
 | |
|   Store a string in the boot script table. This opcode is a no-op on dispatch and is only
 | |
|   used for debugging script issues.
 | |
|   
 | |
|   @param String            The string to save to boot script table
 | |
|   
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveInformationAsciiString (
 | |
|   IN  CONST CHAR8               *String
 | |
|   )
 | |
| {
 | |
|   return S3BootScriptSaveInformation (      
 | |
|            (UINT32) AsciiStrLen (String) + 1, 
 | |
|            (VOID*) String
 | |
|            );
 | |
| }
 | |
| /**
 | |
|   Adds a record for dispatching specified arbitrary code into a specified boot script table.
 | |
| 
 | |
|   @param EntryPoint   Entry point of the code to be dispatched.
 | |
|   
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveDispatch (
 | |
|   IN  VOID                              *EntryPoint
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                *Script;
 | |
|   EFI_BOOT_SCRIPT_DISPATCH  ScriptDispatch;
 | |
|   
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }  
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptDispatch.OpCode     = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;
 | |
|   ScriptDispatch.Length     = Length;
 | |
|   ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
 | |
|   
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH)); 
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| 
 | |
| }
 | |
| /**
 | |
|   Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a
 | |
|   defined duration.
 | |
|   
 | |
|   @param  Width                 The width of the I/O operations. 
 | |
|   @param  Address               The base address of the I/O operations.
 | |
|   @param  Data                  The comparison value used for the polling exit criteria.
 | |
|   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
 | |
|                                 in Data are ignored when polling the memory address.
 | |
|   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
 | |
|                                 granularity so the delay may be longer.
 | |
| 
 | |
|  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|  @retval RETURN_SUCCESS          Opcode is added.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSaveIoPoll (
 | |
|   IN S3_BOOT_SCRIPT_LIB_WIDTH       Width,
 | |
|   IN UINT64                     Address,
 | |
|   IN VOID                      *Data,
 | |
|   IN VOID                      *DataMask, 
 | |
|   IN UINT64                     Delay   
 | |
|   )
 | |
| {
 | |
|   UINT8                 WidthInByte;  
 | |
|   UINT8                *Script;
 | |
|   UINT8                 Length;
 | |
|   EFI_BOOT_SCRIPT_IO_POLL  ScriptIoPoll;
 | |
|   
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));  
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
 | |
|  
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   } 
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptIoPoll.OpCode   = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;
 | |
|   ScriptIoPoll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
 | |
|   ScriptIoPoll.Width    = Width;  
 | |
|   ScriptIoPoll.Address  = Address;
 | |
|   ScriptIoPoll.Delay    = Delay;
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));  
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
 | |
|   after a defined duration.
 | |
| 
 | |
|   @param  Width                 The width of the I/O operations. 
 | |
|   @param  Address               The address within the PCI configuration space.
 | |
|   @param  Data                  The comparison value used for the polling exit criteria.
 | |
|   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
 | |
|                                 in Data are ignored when polling the memory address
 | |
|   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
 | |
|                                 granularity so the delay may be longer.
 | |
| 
 | |
|  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|  @retval RETURN_SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePciPoll (
 | |
|    IN S3_BOOT_SCRIPT_LIB_WIDTH   Width,
 | |
|    IN UINT64                     Address,
 | |
|    IN VOID                      *Data,
 | |
|    IN VOID                      *DataMask,
 | |
|    IN UINT64                     Delay
 | |
| )
 | |
| {
 | |
|   UINT8                   *Script;
 | |
|   UINT8                    WidthInByte;  
 | |
|   UINT8                    Length;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG_POLL  ScriptPciPoll;
 | |
| 
 | |
|   if (Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptPciPoll.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;
 | |
|   ScriptPciPoll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
 | |
|   ScriptPciPoll.Width    = Width;  
 | |
|   ScriptPciPoll.Address  = Address;
 | |
|   ScriptPciPoll.Delay    = Delay;
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
 | |
|   after a defined duration.
 | |
| 
 | |
|   @param  Width                 The width of the I/O operations. 
 | |
|   @param  Segment               The PCI segment number for Address.
 | |
|   @param  Address               The address within the PCI configuration space.
 | |
|   @param  Data                  The comparison value used for the polling exit criteria.
 | |
|   @param  DataMask              Mask used for the polling criteria. The bits in the bytes below Width which are zero
 | |
|                                 in Data are ignored when polling the memory address
 | |
|   @param  Delay                 The number of 100ns units to poll. Note that timer available may be of poorer
 | |
|                                 granularity so the delay may be longer.
 | |
| 
 | |
|  @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|  @retval RETURN_SUCCESS           Opcode is added.
 | |
|   @note  A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptSavePci2Poll (
 | |
|    IN S3_BOOT_SCRIPT_LIB_WIDTH      Width,
 | |
|    IN UINT16                        Segment,
 | |
|    IN UINT64                        Address,
 | |
|    IN VOID                         *Data,
 | |
|    IN VOID                         *DataMask,
 | |
|   IN UINT64                         Delay
 | |
| )
 | |
| {
 | |
|   UINT8                    WidthInByte;  
 | |
|   UINT8                   *Script;
 | |
|   UINT8                    Length;
 | |
|   EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL  ScriptPci2Poll;
 | |
| 
 | |
|   if (Segment != 0 ||
 | |
|       Width == S3BootScriptWidthUint64 ||
 | |
|       Width == S3BootScriptWidthFifoUint64 ||
 | |
|       Width == S3BootScriptWidthFillUint64) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   WidthInByte = (UINT8) (0x01 << (Width & 0x03));
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   } 
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptPci2Poll.OpCode   = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;
 | |
|   ScriptPci2Poll.Length   = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
 | |
|   ScriptPci2Poll.Width    = Width; 
 | |
|   ScriptPci2Poll.Segment  = Segment;
 | |
|   ScriptPci2Poll.Address  = Address;
 | |
|   ScriptPci2Poll.Delay    = Delay;
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);
 | |
|   CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);
 | |
|   
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Do the calculation of start address from which a new s3 boot script entry will write into.
 | |
|   
 | |
|   @param EntryLength      The new entry length.
 | |
|   @param Position         specifies the position in the boot script table where the opcode will be
 | |
|                           inserted, either before or after, depending on BeforeOrAfter. 
 | |
|   @param BeforeOrAfter    The flag to indicate to insert the nod before or after the position.
 | |
|                           This parameter is effective when InsertFlag is TRUE
 | |
|   @param Script           return out the position from which the a new s3 boot script entry will write into
 | |
| **/
 | |
| VOID
 | |
| S3BootScriptCalculateInsertAddress (
 | |
|   IN  UINT8     EntryLength,
 | |
|   IN  VOID     *Position OPTIONAL,
 | |
|   IN  BOOLEAN   BeforeOrAfter OPTIONAL,
 | |
|   OUT UINT8   **Script   
 | |
|   )
 | |
| {
 | |
|    UINTN                            TableLength;
 | |
|    UINT8                            *S3TableBase;
 | |
|    UINTN                            PositionOffset; 
 | |
|    EFI_BOOT_SCRIPT_COMMON_HEADER     ScriptHeader;
 | |
|    //
 | |
|    // The entry inserting to table is already added to the end of the table
 | |
|    //
 | |
|    TableLength =  mS3BootScriptTablePtr->TableLength - EntryLength;
 | |
|    S3TableBase = mS3BootScriptTablePtr->TableBase ;
 | |
|    // 
 | |
|    // calculate the Position offset
 | |
|    //
 | |
|    if (Position != NULL) {
 | |
|      PositionOffset = (UINTN) ((UINT8 *)Position - S3TableBase);
 | |
|    
 | |
|      //
 | |
|      // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.
 | |
|      //
 | |
|      if (!BeforeOrAfter) {
 | |
|         CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));  
 | |
|         PositionOffset += (ScriptHeader.Length);
 | |
|      }
 | |
|      //     
 | |
|      // Insert the node before the adjusted Position
 | |
|      //
 | |
|      CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);  
 | |
|      //
 | |
|      // calculate the the start address for the new entry. 
 | |
|      //
 | |
|      *Script = S3TableBase + PositionOffset;
 | |
|        
 | |
|    } else {
 | |
|      if (!BeforeOrAfter) {
 | |
|        //
 | |
|        //  Insert the node to the end of the table
 | |
|        //
 | |
|        *Script = S3TableBase + TableLength; 
 | |
|      } else {
 | |
|        // 
 | |
|        // Insert the node to the beginning of the table
 | |
|        //
 | |
|        PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|        CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset); 
 | |
|        *Script = S3TableBase + PositionOffset; 
 | |
|      }
 | |
|    }       
 | |
| }
 | |
| /**
 | |
|   Move the last boot script entry to the position 
 | |
| 
 | |
|   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
 | |
|                                 in the boot script table specified by Position. If Position is NULL or points to
 | |
|                                 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
 | |
|                                 of the table (if FALSE).
 | |
|   @param  Position              On entry, specifies the position in the boot script table where the opcode will be
 | |
|                                 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
 | |
|                                 the position of the inserted opcode in the boot script table.
 | |
| 
 | |
|   @retval RETURN_OUT_OF_RESOURCES  The table is not available.
 | |
|   @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
 | |
|   @retval RETURN_SUCCESS           Opcode is inserted.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptMoveLastOpcode (
 | |
|   IN     BOOLEAN                        BeforeOrAfter,
 | |
|   IN OUT VOID                         **Position OPTIONAL
 | |
| )
 | |
| {
 | |
|   UINT8*                Script;
 | |
|   VOID                  *TempPosition;  
 | |
|   UINTN                 StartAddress;
 | |
|   UINT32                TableLength;
 | |
|   EFI_BOOT_SCRIPT_COMMON_HEADER  ScriptHeader;
 | |
|   BOOLEAN               ValidatePosition;
 | |
|   UINT8*                LastOpcode;
 | |
|   UINT8                 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];
 | |
|   
 | |
|   ValidatePosition = FALSE;
 | |
|   TempPosition = (Position == NULL) ? NULL:(*Position);
 | |
| 
 | |
|   //
 | |
|   // Check that the script is initialized and synced without adding an entry to the script.
 | |
|   //
 | |
|   Script = S3BootScriptGetEntryAddAddress (0);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   Script = mS3BootScriptTablePtr->TableBase;
 | |
| 
 | |
|   StartAddress  = (UINTN) Script;
 | |
|   TableLength   = mS3BootScriptTablePtr->TableLength;
 | |
|   Script        = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
 | |
|   LastOpcode    = Script;
 | |
|   //
 | |
|   // Find the last boot Script Entry which is not the terminate node
 | |
|   //
 | |
|   while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {    
 | |
|     CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));   
 | |
|     if (TempPosition != NULL && TempPosition == Script) {
 | |
|       //
 | |
|       // If the position is specified, the position must be pointed to a boot script entry start address. 
 | |
|       //
 | |
|       ValidatePosition = TRUE;
 | |
|     }
 | |
|     if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {
 | |
|       LastOpcode = Script;
 | |
|     } 
 | |
|     Script  = Script + ScriptHeader.Length;
 | |
|   }
 | |
|   //
 | |
|   // If the position is specified, but not the start of a boot script entry, it is a invalid input
 | |
|   //
 | |
|   if (TempPosition != NULL && !ValidatePosition) {
 | |
|     return RETURN_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER)); 
 | |
|   
 | |
|   CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length); 
 | |
|   //
 | |
|   // Find the right position to write the node in
 | |
|   //
 | |
|   S3BootScriptCalculateInsertAddress (
 | |
|     ScriptHeader.Length,
 | |
|     TempPosition,
 | |
|     BeforeOrAfter,
 | |
|     &Script   
 | |
|   );
 | |
|   //
 | |
|   // Copy the node to Boot script table
 | |
|   //
 | |
|   CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   //
 | |
|   // return out the Position
 | |
|   //
 | |
|   if (Position != NULL) {
 | |
|     *Position = Script;
 | |
|   }
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Create a Label node in the boot script table. 
 | |
|   
 | |
|   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
 | |
|                                 in the boot script table specified by Position. If Position is NULL or points to
 | |
|                                 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
 | |
|                                 of the table (if FALSE).
 | |
|   @param  Position              On entry, specifies the position in the boot script table where the opcode will be
 | |
|                                 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
 | |
|                                 the position of the inserted opcode in the boot script table.  
 | |
|   @param InformationLength      Length of the label in bytes
 | |
|   @param Information            Label to be logged in the boot scrpit
 | |
|  
 | |
|   @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
 | |
|   @retval RETURN_OUT_OF_RESOURCES  Not enough memory for the table do operation.
 | |
|   @retval RETURN_SUCCESS           Opcode is added.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| S3BootScriptLabelInternal (
 | |
|   IN        BOOLEAN                        BeforeOrAfter,
 | |
|   IN OUT    VOID                         **Position OPTIONAL, 
 | |
|   IN        UINT32                         InformationLength, 
 | |
|   IN CONST  CHAR8                          *Information
 | |
|   )
 | |
| {
 | |
|   UINT8                 Length;
 | |
|   UINT8                 *Script;
 | |
|   EFI_BOOT_SCRIPT_INFORMATION  ScriptInformation;
 | |
|  
 | |
|   Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
 | |
|   
 | |
|   Script = S3BootScriptGetEntryAddAddress (Length);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build script data
 | |
|   //
 | |
|   ScriptInformation.OpCode     = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;
 | |
|   ScriptInformation.Length     = Length;
 | |
| 
 | |
| 
 | |
|   ScriptInformation.InformationLength = InformationLength;  
 | |
| 
 | |
|   CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
 | |
|   CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
 | |
| 
 | |
|   SyncBootScript (Script);
 | |
| 
 | |
|   return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
 | |
| 
 | |
| }
 | |
| /**
 | |
|   Find a label within the boot script table and, if not present, optionally create it.
 | |
| 
 | |
|   @param  BeforeOrAfter         Specifies whether the opcode is stored before (TRUE)
 | |
|                                 or after (FALSE) the position in the boot script table 
 | |
|                                 specified by Position.
 | |
|   @param  CreateIfNotFound      Specifies whether the label will be created if the label 
 | |
|                                 does not exists (TRUE) or not (FALSE).
 | |
|   @param  Position              On entry, specifies the position in the boot script table
 | |
|                                 where the opcode will be inserted, either before or after,
 | |
|                                 depending on BeforeOrAfter. On exit, specifies the position
 | |
|                                 of the inserted opcode in the boot script table.
 | |
|   @param  Label                 Points to the label which will be inserted in the boot script table.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The operation succeeded. A record was added into the
 | |
|                                 specified script table.
 | |
|   @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
 | |
|                                 If the opcode is unknow or not supported because of the PCD 
 | |
|                                 Feature Flags.
 | |
|   @retval EFI_OUT_OF_RESOURCES  There is insufficient memory to store the boot script.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI 
 | |
| S3BootScriptLabel (
 | |
|   IN       BOOLEAN                      BeforeOrAfter,
 | |
|   IN       BOOLEAN                      CreateIfNotFound,
 | |
|   IN OUT   VOID                       **Position OPTIONAL,
 | |
|   IN CONST CHAR8                       *Label
 | |
|   )
 | |
| {
 | |
|   UINT8*                Script;
 | |
|   UINTN                 StartAddress;
 | |
|   UINT32                TableLength;
 | |
|   EFI_BOOT_SCRIPT_COMMON_HEADER  ScriptHeader;
 | |
|   EFI_BOOT_SCRIPT_TABLE_HEADER   TableHeader;
 | |
|   UINT32                         LabelLength;
 | |
|   //
 | |
|   // Check NULL Label
 | |
|   //
 | |
|   if (Label == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Check empty Label
 | |
|   //
 | |
|   if (Label[0] == '\0') {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Check that the script is initialized and synced without adding an entry to the script.
 | |
|   // The code must search for the label first before it knows if a new entry needs
 | |
|   // to be added.
 | |
|   //
 | |
|   Script = S3BootScriptGetEntryAddAddress (0);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Check the header and search for existing label.
 | |
|   // 
 | |
|   Script = mS3BootScriptTablePtr->TableBase;
 | |
|   CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
 | |
|   if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   StartAddress  = (UINTN) Script;
 | |
|   TableLength   = mS3BootScriptTablePtr->TableLength;
 | |
|   Script    =     Script + TableHeader.Length;
 | |
|   while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
 | |
|     
 | |
|     CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));   
 | |
|     if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {
 | |
|       if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {
 | |
|         (*Position) = Script; 
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     } 
 | |
|     Script  = Script + ScriptHeader.Length;
 | |
|   }
 | |
|   if (CreateIfNotFound) {
 | |
|     LabelLength = (UINT32)AsciiStrSize(Label);
 | |
|     return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label);     
 | |
|   } else {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }   
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Compare two positions in the boot script table and return their relative position.
 | |
|   @param  Position1             The positions in the boot script table to compare
 | |
|   @param  Position2             The positions in the boot script table to compare
 | |
|   @param  RelativePosition      On return, points to the result of the comparison
 | |
| 
 | |
|   @retval EFI_SUCCESS           The operation succeeded. A record was added into the
 | |
|                                 specified script table.
 | |
|   @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
 | |
|                                 If the opcode is unknow or not supported because of the PCD 
 | |
|                                 Feature Flags.
 | |
|   @retval EFI_OUT_OF_RESOURCES  There is insufficient memory to store the boot script.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI 
 | |
| S3BootScriptCompare (
 | |
|   IN  UINT8                       *Position1,
 | |
|   IN  UINT8                       *Position2,
 | |
|   OUT UINTN                       *RelativePosition
 | |
|   )
 | |
| {
 | |
|   UINT8*                    Script;
 | |
|   UINT32                    TableLength; 
 | |
| 
 | |
|   if (RelativePosition == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check that the script is initialized and synced without adding an entry to the script.
 | |
|   //
 | |
|   Script = S3BootScriptGetEntryAddAddress (0);
 | |
|   if (Script == NULL) {
 | |
|     return RETURN_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   Script = mS3BootScriptTablePtr->TableBase;
 | |
| 
 | |
|   //
 | |
|   // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up
 | |
|   //
 | |
|   TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
 | |
|   if (Position1 < Script || Position1 > Script+TableLength) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   if (Position2 < Script || Position2 > Script+TableLength) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |