From 7e2ccccace24636f29ddc210b94606abd4c7e42b Mon Sep 17 00:00:00 2001 From: kx Date: Tue, 4 Jun 2024 06:43:08 +0300 Subject: Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305b --- .../Library/PiDxeS3BootScriptLib/BootScriptSave.c | 5156 ++++++++++---------- 1 file changed, 2578 insertions(+), 2578 deletions(-) (limited to 'MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c') diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c index a6af2e8485..100abf8ab2 100644 --- a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c @@ -1,2578 +1,2578 @@ -/** @file - Save the S3 data to S3 boot script. - - Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ -#include "InternalBootScriptLib.h" - -/** - - Data structure usage: - - +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr - | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock) - | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr - | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm) - | TableMemoryPageNumber |--|-|---- - | AtRuntime | | | | - | InSmm | | | | - | BootTimeScriptLength |--|-|---|--- - | SmmLocked | | | | | - | BackFromS3 | | | | | - +------------------------------+ | | | | - | | | | - +------------------------------+<-- | | | - | EFI_BOOT_SCRIPT_TABLE_HEADER | | | | - | TableLength |----|-- | | - +------------------------------+ | | | | - | ...... | | | | | - +------------------------------+<---- | | | - | EFI_BOOT_SCRIPT_TERMINATE | | | | - +------------------------------+<------ | | - | | - | | - mBootScriptDataBootTimeGuid LockBox: | | - Used to restore data after back from S3| | - to handle potential INSERT boot script | | - at runtime. | | - +------------------------------+ | | - | Boot Time Boot Script | | | - | Before SmmReadyToLock | | | - | | | | - | | | | - +------------------------------+ | | - | Boot Time Boot Script | | | - | After SmmReadyToLock InSmm | | | - | | | | - +------------------------------+<-------|--| - | | - | | - mBootScriptDataGuid LockBox: (IN_PLACE) | | - Used to restore data at S3 resume. | | - +------------------------------+ | | - | Boot Time Boot Script | | | - | Before SmmReadyToLock | | | - | | | | - | | | | - +------------------------------+ | | - | Boot Time Boot Script | | | - | After SmmReadyToLock InSmm | | | - | | | | - +------------------------------+<-------|--- - | Runtime Boot Script | | - | After SmmReadyToLock InSmm | | - +------------------------------+ | - | ...... | | - +------------------------------+<-------- - - - mBootScriptTableBaseGuid LockBox: (IN_PLACE) - +------------------------------+ - | mS3BootScriptTablePtr-> | - | TableBase | - +------------------------------+ - - - mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE) - SMM private data with BackFromS3 = TRUE - at runtime. S3 will help restore it to - tell the Library the system is back from S3. - +------------------------------+ - | SCRIPT_TABLE_PRIVATE_DATA | - | TableBase | - | TableLength | - | TableMemoryPageNumber | - | AtRuntime | - | InSmm | - | BootTimeScriptLength | - | SmmLocked | - | BackFromS3 = TRUE | - +------------------------------+ - -**/ - -SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; - -// -// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm. -// -SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr; - -EFI_GUID mBootScriptDataGuid = { - 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 } -}; - -EFI_GUID mBootScriptDataBootTimeGuid = { - 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d } -}; - -EFI_GUID mBootScriptTableBaseGuid = { - 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 } -}; - -EFI_GUID mBootScriptSmmPrivateDataGuid = { - 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 } -}; - -EFI_EVENT mEventDxeSmmReadyToLock = NULL; -VOID *mRegistrationSmmExitBootServices = NULL; -VOID *mRegistrationSmmLegacyBoot = NULL; -VOID *mRegistrationSmmReadyToLock = NULL; -BOOLEAN mS3BootScriptTableAllocated = FALSE; -BOOLEAN mS3BootScriptTableSmmAllocated = FALSE; -EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL; -BOOLEAN mS3BootScriptAcpiS3Enable = TRUE; - -/** - 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 after SmmReadyToLock, we still need add entries into the table, - // and the entry should be added start before this TERMINATE node. - // -} - -/** - This function save boot script data to LockBox. - -**/ -VOID -SaveBootScriptDataToLockBox ( - VOID - ) -{ - EFI_STATUS Status; - - // - // Save whole memory copy into LockBox. - // It will be used to restore data at S3 resume. - // - Status = SaveLockBox ( - &mBootScriptDataGuid, - (VOID *)mS3BootScriptTablePtr->TableBase, - EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber) - ); - ASSERT_EFI_ERROR (Status); - - Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); - ASSERT_EFI_ERROR (Status); - - // - // Just need save TableBase. - // Do not update other field because they will NOT be used in S3. - // - Status = SaveLockBox ( - &mBootScriptTableBaseGuid, - (VOID *)&mS3BootScriptTablePtr->TableBase, - sizeof (mS3BootScriptTablePtr->TableBase) - ); - ASSERT_EFI_ERROR (Status); - - Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, 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 - SmmLocked 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 entering SmmLocked phase. - // and the memory page number occupied by the table should not grow anymore. - // - if (!mS3BootScriptTablePtr->SmmLocked) { - // - // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table - // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate - // node on every add to boot script table. - // - S3BootScriptInternalCloseTable (); - mS3BootScriptTablePtr->SmmLocked = 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 SmmLocked 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 SmmLocked 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)); - - // - // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. - // InSmm will only be checked if SmmLocked is TRUE. - // - mS3BootScriptTableSmmPtr->InSmm = TRUE; - } - - // - // We should not use ACPI Reserved copy, because it is not safe. - // - mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr; - - return EFI_SUCCESS; -} - -/** - This function is to save boot time boot script data to LockBox. - - Because there may be INSERT boot script at runtime in SMM. - The boot time copy will be used to restore data after back from S3. - Otherwise the data inserted may cause some boot time boot script data lost - if only BootScriptData used. - -**/ -VOID -SaveBootTimeDataToLockBox ( - VOID - ) -{ - EFI_STATUS Status; - - // - // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first, - // and then save the data to BootScriptDataBootTime LockBox. - // - Status = RestoreLockBox ( - &mBootScriptDataGuid, - NULL, - NULL - ); - ASSERT_EFI_ERROR (Status); - - // - // Save BootScriptDataBootTime - // It will be used to restore data after back from S3. - // - Status = SaveLockBox ( - &mBootScriptDataBootTimeGuid, - (VOID *)mS3BootScriptTablePtr->TableBase, - mS3BootScriptTablePtr->BootTimeScriptLength - ); - ASSERT_EFI_ERROR (Status); -} - -/** - This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime. - S3 resume will help restore it to tell the Library the system is back from S3. - -**/ -VOID -SaveSmmPriviateDataToLockBoxAtRuntime ( - VOID - ) -{ - EFI_STATUS Status; - - // - // Save boot script SMM private data with BackFromS3 = TRUE. - // - mS3BootScriptTablePtr->BackFromS3 = TRUE; - Status = SaveLockBox ( - &mBootScriptSmmPrivateDataGuid, - (VOID *)mS3BootScriptTablePtr, - sizeof (SCRIPT_TABLE_PRIVATE_DATA) - ); - ASSERT_EFI_ERROR (Status); - - Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); - ASSERT_EFI_ERROR (Status); - - // - // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3. - // - mS3BootScriptTablePtr->BackFromS3 = FALSE; -} - -/** - This is the Event call back function is triggered in SMM to notify the Library - the system is entering runtime phase. - - @param[in] Protocol Points to the protocol's unique identifier - @param[in] Interface Points to the interface instance - @param[in] Handle The handle on which the interface was installed - - @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully - **/ -EFI_STATUS -EFIAPI -S3BootScriptSmmAtRuntimeCallBack ( - IN CONST EFI_GUID *Protocol, - IN VOID *Interface, - IN EFI_HANDLE Handle - ) -{ - if (!mS3BootScriptTablePtr->AtRuntime) { - mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32)(mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); - SaveBootTimeDataToLockBox (); - - mS3BootScriptTablePtr->AtRuntime = TRUE; - SaveSmmPriviateDataToLockBoxAtRuntime (); - } - - 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 The constructor always returns RETURN_SUCCESS. - -**/ -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_PHYSICAL_ADDRESS Buffer; - - if (!PcdGetBool (PcdAcpiS3Enable)) { - mS3BootScriptAcpiS3Enable = FALSE; - DEBUG ((DEBUG_INFO, "%a: Skip S3BootScript because ACPI S3 disabled.\n", gEfiCallerBaseName)); - return RETURN_SUCCESS; - } - - 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, - EfiReservedMemoryType, - EFI_SIZE_TO_PAGES (sizeof (SCRIPT_TABLE_PRIVATE_DATA)), - &Buffer - ); - ASSERT_EFI_ERROR (Status); - mS3BootScriptTableAllocated = TRUE; - S3TablePtr = (VOID *)(UINTN)Buffer; - - Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64)(UINTN)S3TablePtr); - ASSERT_EFI_ERROR (Status); - ZeroMem (S3TablePtr, sizeof (SCRIPT_TABLE_PRIVATE_DATA)); - // - // Create event to notify the library system enter the SmmLocked phase. - // - mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent ( - &gEfiDxeSmmReadyToLockProtocolGuid, - TPL_CALLBACK, - S3BootScriptEventCallBack, - NULL, - &Registration - ); - ASSERT (mEventDxeSmmReadyToLock != 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, &mBootScriptSmst); - 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 = mBootScriptSmst->SmmAllocatePool ( - EfiRuntimeServicesData, - sizeof (SCRIPT_TABLE_PRIVATE_DATA), - (VOID **)&S3TableSmmPtr - ); - ASSERT_EFI_ERROR (Status); - mS3BootScriptTableSmmAllocated = TRUE; - - Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64)(UINTN)S3TableSmmPtr); - ASSERT_EFI_ERROR (Status); - ZeroMem (S3TableSmmPtr, sizeof (SCRIPT_TABLE_PRIVATE_DATA)); - - // - // Register SmmExitBootServices and SmmLegacyBoot notification. - // - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEdkiiSmmExitBootServicesProtocolGuid, - S3BootScriptSmmAtRuntimeCallBack, - &mRegistrationSmmExitBootServices - ); - ASSERT_EFI_ERROR (Status); - - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEdkiiSmmLegacyBootProtocolGuid, - S3BootScriptSmmAtRuntimeCallBack, - &mRegistrationSmmLegacyBoot - ); - ASSERT_EFI_ERROR (Status); - } - - mS3BootScriptTableSmmPtr = S3TableSmmPtr; - - // - // Register SmmReadyToLock notification. - // - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEfiSmmReadyToLockProtocolGuid, - S3BootScriptSmmEventCallBack, - &mRegistrationSmmReadyToLock - ); - ASSERT_EFI_ERROR (Status); - - return RETURN_SUCCESS; -} - -/** - Library Destructor to free the resources allocated by - S3BootScriptLibInitialize() and unregister callbacks. - - NOTICE: The destructor doesn't support unloading as a separate action, and it - only supports unloading if the containing driver's entry point function fails. - - @param ImageHandle The firmware allocated handle for the EFI image. - @param SystemTable A pointer to the EFI System Table. - - @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS. - -**/ -RETURN_STATUS -EFIAPI -S3BootScriptLibDeinitialize ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - DEBUG ((DEBUG_INFO, "%a() in %a module\n", __func__, gEfiCallerBaseName)); - - if (mEventDxeSmmReadyToLock != NULL) { - // - // Close the DxeSmmReadyToLock event. - // - Status = gBS->CloseEvent (mEventDxeSmmReadyToLock); - ASSERT_EFI_ERROR (Status); - } - - if (mBootScriptSmst != NULL) { - if (mRegistrationSmmExitBootServices != NULL) { - // - // Unregister SmmExitBootServices notification. - // - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEdkiiSmmExitBootServicesProtocolGuid, - NULL, - &mRegistrationSmmExitBootServices - ); - ASSERT_EFI_ERROR (Status); - } - - if (mRegistrationSmmLegacyBoot != NULL) { - // - // Unregister SmmLegacyBoot notification. - // - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEdkiiSmmLegacyBootProtocolGuid, - NULL, - &mRegistrationSmmLegacyBoot - ); - ASSERT_EFI_ERROR (Status); - } - - if (mRegistrationSmmReadyToLock != NULL) { - // - // Unregister SmmReadyToLock notification. - // - Status = mBootScriptSmst->SmmRegisterProtocolNotify ( - &gEfiSmmReadyToLockProtocolGuid, - NULL, - &mRegistrationSmmReadyToLock - ); - ASSERT_EFI_ERROR (Status); - } - } - - // - // Free the resources allocated and set PCDs to 0. - // - if (mS3BootScriptTableAllocated) { - Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES (sizeof (SCRIPT_TABLE_PRIVATE_DATA))); - ASSERT_EFI_ERROR (Status); - Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0); - ASSERT_EFI_ERROR (Status); - } - - if ((mBootScriptSmst != NULL) && mS3BootScriptTableSmmAllocated) { - Status = mBootScriptSmst->SmmFreePool (mS3BootScriptTableSmmPtr); - ASSERT_EFI_ERROR (Status); - Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0); - 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. - // - S3TableBase = 0xffffffff; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiReservedMemoryType, - 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 (EFI_PAGES_TO_SIZE ((UINTN)PageNumber) < (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, - EfiReservedMemoryType, - 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(after SmmReadyToLock) 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(after SmmReadyToLock) 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 ((UINTN)(mS3BootScriptTablePtr->TableMemoryPageNumber))) { - NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; - mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength; - // - // Append a terminate node on every insert - // - S3BootScriptInternalCloseTable (); - } - - return (UINT8 *)NewEntryPtr; -} - -/** - This function is to restore boot time boot script data from LockBox. - -**/ -VOID -RestoreBootTimeDataFromLockBox ( - VOID - ) -{ - EFI_STATUS Status; - UINTN LockBoxLength; - - // - // Restore boot time boot script data from LockBox. - // - LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength; - Status = RestoreLockBox ( - &mBootScriptDataBootTimeGuid, - (VOID *)mS3BootScriptTablePtr->TableBase, - &LockBoxLength - ); - ASSERT_EFI_ERROR (Status); - - // - // Update the data to BootScriptData LockBox. - // - Status = UpdateLockBox ( - &mBootScriptDataGuid, - 0, - (VOID *)mS3BootScriptTablePtr->TableBase, - LockBoxLength - ); - ASSERT_EFI_ERROR (Status); - - // - // Update TableLength. - // - mS3BootScriptTablePtr->TableLength = (UINT32)(mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE)); -} - -/** - 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 boot script entry will write into - **/ -UINT8 * -S3BootScriptGetEntryAddAddress ( - UINT8 EntryLength - ) -{ - UINT8 *NewEntryPtr; - - if (!mS3BootScriptAcpiS3Enable) { - return NULL; - } - - if (mS3BootScriptTablePtr->SmmLocked) { - // - // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script. - // - if (!mS3BootScriptTablePtr->InSmm) { - // - // Add DEBUG ERROR, so that we can find it after SmmReadyToLock. - // Do not use ASSERT, because we may have test to invoke this interface. - // - DEBUG ((DEBUG_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n")); - return NULL; - } - - if (mS3BootScriptTablePtr->BackFromS3) { - // - // Back from S3, restore boot time boot script data from LockBox - // and set BackFromS3 flag back to FALSE. - // - RestoreBootTimeDataFromLockBox (); - mS3BootScriptTablePtr->BackFromS3 = FALSE; - } - - NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength); - } 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; - UINT32 ScriptOffset; - UINT32 TotalScriptLength; - - if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) { - // - // If it is not after SmmReadyToLock in SMM, - // just return. - // - return; - } - - ScriptOffset = (UINT32)(Script - mS3BootScriptTablePtr->TableBase); - - TotalScriptLength = (UINT32)(mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); - - // - // Update BootScriptData - // So in S3 resume, the data can be restored correctly. - // - Status = UpdateLockBox ( - &mBootScriptDataGuid, - ScriptOffset, - (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset), - TotalScriptLength - ScriptOffset - ); - ASSERT_EFI_ERROR (Status); - - // - // Now the length field is updated, need sync to lockbox. - // So at S3 resume, the data can be restored correctly. - // - Status = UpdateLockBox ( - &mBootScriptDataGuid, - OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), - &TotalScriptLength, - sizeof (TotalScriptLength) - ); - 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 at 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 or no action is required as ACPI S3 was disabled. -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - WidthInByte = (UINT8)(0x01 << (Width & 0x03)); - - // - // Truncation check - // - if ((Count > MAX_UINT8) || - (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_IO_WRITE))) - { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - WidthInByte = (UINT8)(0x01 << (Width & 0x03)); - - // - // Truncation check - // - if ((Count > MAX_UINT8) || - (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_MEM_WRITE))) - { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - @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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - if ((Width == S3BootScriptWidthUint64) || - (Width == S3BootScriptWidthFifoUint64) || - (Width == S3BootScriptWidthFillUint64)) - { - return EFI_INVALID_PARAMETER; - } - - WidthInByte = (UINT8)(0x01 << (Width & 0x03)); - - // - // Truncation check - // - if ((Count > MAX_UINT8) || - (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE))) - { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. - @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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - if ((Width == S3BootScriptWidthUint64) || - (Width == S3BootScriptWidthFifoUint64) || - (Width == S3BootScriptWidthFillUint64)) - { - return EFI_INVALID_PARAMETER; - } - - WidthInByte = (UINT8)(0x01 << (Width & 0x03)); - - // - // Truncation check - // - if ((Count > MAX_UINT8) || - (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE))) - { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. - @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - if ((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 or no action is required as ACPI S3 was disabled. -**/ -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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - if (Length == NULL) { - BufferLength = 0; - } else { - BufferLength = *Length; - } - - Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Truncation check - // - if (BufferLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)) { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. -**/ -RETURN_STATUS -EFIAPI -S3BootScriptSaveStall ( - IN UINTN Duration - ) -{ - UINT8 Length; - UINT8 *Script; - EFI_BOOT_SCRIPT_STALL ScriptStall; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. -**/ -RETURN_STATUS -EFIAPI -S3BootScriptSaveDispatch2 ( - IN VOID *EntryPoint, - IN VOID *Context - ) -{ - UINT8 Length; - UINT8 *Script; - EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - -**/ -RETURN_STATUS -EFIAPI -S3BootScriptSaveMemPoll ( - IN S3_BOOT_SCRIPT_LIB_WIDTH Width, - IN UINT64 Address, - IN VOID *BitMask, - IN VOID *BitValue, - IN UINTN Duration, - IN UINT64 LoopTimes - ) -{ - UINT8 Length; - UINT8 *Script; - UINT8 WidthInByte; - EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - -**/ -RETURN_STATUS -EFIAPI -S3BootScriptSaveInformation ( - IN UINT32 InformationLength, - IN VOID *Information - ) -{ - UINT8 Length; - UINT8 *Script; - EFI_BOOT_SCRIPT_INFORMATION ScriptInformation; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - // - // Truncation check - // - if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required as ACPI S3 was disabled. - -**/ -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 or no action is required as ACPI S3 was disabled. -**/ -RETURN_STATUS -EFIAPI -S3BootScriptSaveDispatch ( - IN VOID *EntryPoint - ) -{ - UINT8 Length; - UINT8 *Script; - EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - @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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - if ((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)Position - (UINTN)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 no action is required as ACPI S3 was disabled. -**/ -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]; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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 or no action is required as ACPI S3 was disabled. - -**/ -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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - // - // Truncation check - // - if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) { - return RETURN_OUT_OF_RESOURCES; - } - - 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 or no action is required. - A record was added into the specified script table if ACPI S3 was enabled. - @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; - - if (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - // - // 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 or no action is required. - A record was added into the specified script table if ACPI S3 was enabled. - @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 (!mS3BootScriptAcpiS3Enable) { - return RETURN_SUCCESS; - } - - 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; -} +/** @file + Save the S3 data to S3 boot script. + + Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "InternalBootScriptLib.h" + +/** + + Data structure usage: + + +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr + | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock) + | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr + | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm) + | TableMemoryPageNumber |--|-|---- + | AtRuntime | | | | + | InSmm | | | | + | BootTimeScriptLength |--|-|---|--- + | SmmLocked | | | | | + | BackFromS3 | | | | | + +------------------------------+ | | | | + | | | | + +------------------------------+<-- | | | + | EFI_BOOT_SCRIPT_TABLE_HEADER | | | | + | TableLength |----|-- | | + +------------------------------+ | | | | + | ...... | | | | | + +------------------------------+<---- | | | + | EFI_BOOT_SCRIPT_TERMINATE | | | | + +------------------------------+<------ | | + | | + | | + mBootScriptDataBootTimeGuid LockBox: | | + Used to restore data after back from S3| | + to handle potential INSERT boot script | | + at runtime. | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | Before SmmReadyToLock | | | + | | | | + | | | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | After SmmReadyToLock InSmm | | | + | | | | + +------------------------------+<-------|--| + | | + | | + mBootScriptDataGuid LockBox: (IN_PLACE) | | + Used to restore data at S3 resume. | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | Before SmmReadyToLock | | | + | | | | + | | | | + +------------------------------+ | | + | Boot Time Boot Script | | | + | After SmmReadyToLock InSmm | | | + | | | | + +------------------------------+<-------|--- + | Runtime Boot Script | | + | After SmmReadyToLock InSmm | | + +------------------------------+ | + | ...... | | + +------------------------------+<-------- + + + mBootScriptTableBaseGuid LockBox: (IN_PLACE) + +------------------------------+ + | mS3BootScriptTablePtr-> | + | TableBase | + +------------------------------+ + + + mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE) + SMM private data with BackFromS3 = TRUE + at runtime. S3 will help restore it to + tell the Library the system is back from S3. + +------------------------------+ + | SCRIPT_TABLE_PRIVATE_DATA | + | TableBase | + | TableLength | + | TableMemoryPageNumber | + | AtRuntime | + | InSmm | + | BootTimeScriptLength | + | SmmLocked | + | BackFromS3 = TRUE | + +------------------------------+ + +**/ + +SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; + +// +// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm. +// +SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr; + +EFI_GUID mBootScriptDataGuid = { + 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 } +}; + +EFI_GUID mBootScriptDataBootTimeGuid = { + 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d } +}; + +EFI_GUID mBootScriptTableBaseGuid = { + 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 } +}; + +EFI_GUID mBootScriptSmmPrivateDataGuid = { + 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 } +}; + +EFI_EVENT mEventDxeSmmReadyToLock = NULL; +VOID *mRegistrationSmmExitBootServices = NULL; +VOID *mRegistrationSmmLegacyBoot = NULL; +VOID *mRegistrationSmmReadyToLock = NULL; +BOOLEAN mS3BootScriptTableAllocated = FALSE; +BOOLEAN mS3BootScriptTableSmmAllocated = FALSE; +EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL; +BOOLEAN mS3BootScriptAcpiS3Enable = TRUE; + +/** + 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 after SmmReadyToLock, we still need add entries into the table, + // and the entry should be added start before this TERMINATE node. + // +} + +/** + This function save boot script data to LockBox. + +**/ +VOID +SaveBootScriptDataToLockBox ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Save whole memory copy into LockBox. + // It will be used to restore data at S3 resume. + // + Status = SaveLockBox ( + &mBootScriptDataGuid, + (VOID *)mS3BootScriptTablePtr->TableBase, + EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + // + // Just need save TableBase. + // Do not update other field because they will NOT be used in S3. + // + Status = SaveLockBox ( + &mBootScriptTableBaseGuid, + (VOID *)&mS3BootScriptTablePtr->TableBase, + sizeof (mS3BootScriptTablePtr->TableBase) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, 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 + SmmLocked 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 entering SmmLocked phase. + // and the memory page number occupied by the table should not grow anymore. + // + if (!mS3BootScriptTablePtr->SmmLocked) { + // + // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table + // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate + // node on every add to boot script table. + // + S3BootScriptInternalCloseTable (); + mS3BootScriptTablePtr->SmmLocked = 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 SmmLocked 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 SmmLocked 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)); + + // + // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. + // InSmm will only be checked if SmmLocked is TRUE. + // + mS3BootScriptTableSmmPtr->InSmm = TRUE; + } + + // + // We should not use ACPI Reserved copy, because it is not safe. + // + mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr; + + return EFI_SUCCESS; +} + +/** + This function is to save boot time boot script data to LockBox. + + Because there may be INSERT boot script at runtime in SMM. + The boot time copy will be used to restore data after back from S3. + Otherwise the data inserted may cause some boot time boot script data lost + if only BootScriptData used. + +**/ +VOID +SaveBootTimeDataToLockBox ( + VOID + ) +{ + EFI_STATUS Status; + + // + // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first, + // and then save the data to BootScriptDataBootTime LockBox. + // + Status = RestoreLockBox ( + &mBootScriptDataGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Save BootScriptDataBootTime + // It will be used to restore data after back from S3. + // + Status = SaveLockBox ( + &mBootScriptDataBootTimeGuid, + (VOID *)mS3BootScriptTablePtr->TableBase, + mS3BootScriptTablePtr->BootTimeScriptLength + ); + ASSERT_EFI_ERROR (Status); +} + +/** + This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime. + S3 resume will help restore it to tell the Library the system is back from S3. + +**/ +VOID +SaveSmmPriviateDataToLockBoxAtRuntime ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Save boot script SMM private data with BackFromS3 = TRUE. + // + mS3BootScriptTablePtr->BackFromS3 = TRUE; + Status = SaveLockBox ( + &mBootScriptSmmPrivateDataGuid, + (VOID *)mS3BootScriptTablePtr, + sizeof (SCRIPT_TABLE_PRIVATE_DATA) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + // + // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3. + // + mS3BootScriptTablePtr->BackFromS3 = FALSE; +} + +/** + This is the Event call back function is triggered in SMM to notify the Library + the system is entering runtime phase. + + @param[in] Protocol Points to the protocol's unique identifier + @param[in] Interface Points to the interface instance + @param[in] Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully + **/ +EFI_STATUS +EFIAPI +S3BootScriptSmmAtRuntimeCallBack ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + if (!mS3BootScriptTablePtr->AtRuntime) { + mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32)(mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); + SaveBootTimeDataToLockBox (); + + mS3BootScriptTablePtr->AtRuntime = TRUE; + SaveSmmPriviateDataToLockBoxAtRuntime (); + } + + 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 The constructor always returns RETURN_SUCCESS. + +**/ +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_PHYSICAL_ADDRESS Buffer; + + if (!PcdGetBool (PcdAcpiS3Enable)) { + mS3BootScriptAcpiS3Enable = FALSE; + DEBUG ((DEBUG_INFO, "%a: Skip S3BootScript because ACPI S3 disabled.\n", gEfiCallerBaseName)); + return RETURN_SUCCESS; + } + + 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, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (sizeof (SCRIPT_TABLE_PRIVATE_DATA)), + &Buffer + ); + ASSERT_EFI_ERROR (Status); + mS3BootScriptTableAllocated = TRUE; + S3TablePtr = (VOID *)(UINTN)Buffer; + + Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64)(UINTN)S3TablePtr); + ASSERT_EFI_ERROR (Status); + ZeroMem (S3TablePtr, sizeof (SCRIPT_TABLE_PRIVATE_DATA)); + // + // Create event to notify the library system enter the SmmLocked phase. + // + mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent ( + &gEfiDxeSmmReadyToLockProtocolGuid, + TPL_CALLBACK, + S3BootScriptEventCallBack, + NULL, + &Registration + ); + ASSERT (mEventDxeSmmReadyToLock != 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, &mBootScriptSmst); + 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 = mBootScriptSmst->SmmAllocatePool ( + EfiRuntimeServicesData, + sizeof (SCRIPT_TABLE_PRIVATE_DATA), + (VOID **)&S3TableSmmPtr + ); + ASSERT_EFI_ERROR (Status); + mS3BootScriptTableSmmAllocated = TRUE; + + Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64)(UINTN)S3TableSmmPtr); + ASSERT_EFI_ERROR (Status); + ZeroMem (S3TableSmmPtr, sizeof (SCRIPT_TABLE_PRIVATE_DATA)); + + // + // Register SmmExitBootServices and SmmLegacyBoot notification. + // + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmExitBootServicesProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &mRegistrationSmmExitBootServices + ); + ASSERT_EFI_ERROR (Status); + + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmLegacyBootProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &mRegistrationSmmLegacyBoot + ); + ASSERT_EFI_ERROR (Status); + } + + mS3BootScriptTableSmmPtr = S3TableSmmPtr; + + // + // Register SmmReadyToLock notification. + // + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + S3BootScriptSmmEventCallBack, + &mRegistrationSmmReadyToLock + ); + ASSERT_EFI_ERROR (Status); + + return RETURN_SUCCESS; +} + +/** + Library Destructor to free the resources allocated by + S3BootScriptLibInitialize() and unregister callbacks. + + NOTICE: The destructor doesn't support unloading as a separate action, and it + only supports unloading if the containing driver's entry point function fails. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptLibDeinitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "%a() in %a module\n", __func__, gEfiCallerBaseName)); + + if (mEventDxeSmmReadyToLock != NULL) { + // + // Close the DxeSmmReadyToLock event. + // + Status = gBS->CloseEvent (mEventDxeSmmReadyToLock); + ASSERT_EFI_ERROR (Status); + } + + if (mBootScriptSmst != NULL) { + if (mRegistrationSmmExitBootServices != NULL) { + // + // Unregister SmmExitBootServices notification. + // + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmExitBootServicesProtocolGuid, + NULL, + &mRegistrationSmmExitBootServices + ); + ASSERT_EFI_ERROR (Status); + } + + if (mRegistrationSmmLegacyBoot != NULL) { + // + // Unregister SmmLegacyBoot notification. + // + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmLegacyBootProtocolGuid, + NULL, + &mRegistrationSmmLegacyBoot + ); + ASSERT_EFI_ERROR (Status); + } + + if (mRegistrationSmmReadyToLock != NULL) { + // + // Unregister SmmReadyToLock notification. + // + Status = mBootScriptSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + NULL, + &mRegistrationSmmReadyToLock + ); + ASSERT_EFI_ERROR (Status); + } + } + + // + // Free the resources allocated and set PCDs to 0. + // + if (mS3BootScriptTableAllocated) { + Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES (sizeof (SCRIPT_TABLE_PRIVATE_DATA))); + ASSERT_EFI_ERROR (Status); + Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0); + ASSERT_EFI_ERROR (Status); + } + + if ((mBootScriptSmst != NULL) && mS3BootScriptTableSmmAllocated) { + Status = mBootScriptSmst->SmmFreePool (mS3BootScriptTableSmmPtr); + ASSERT_EFI_ERROR (Status); + Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0); + 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. + // + S3TableBase = 0xffffffff; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + 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 (EFI_PAGES_TO_SIZE ((UINTN)PageNumber) < (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, + EfiReservedMemoryType, + 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(after SmmReadyToLock) 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(after SmmReadyToLock) 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 ((UINTN)(mS3BootScriptTablePtr->TableMemoryPageNumber))) { + NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; + mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength; + // + // Append a terminate node on every insert + // + S3BootScriptInternalCloseTable (); + } + + return (UINT8 *)NewEntryPtr; +} + +/** + This function is to restore boot time boot script data from LockBox. + +**/ +VOID +RestoreBootTimeDataFromLockBox ( + VOID + ) +{ + EFI_STATUS Status; + UINTN LockBoxLength; + + // + // Restore boot time boot script data from LockBox. + // + LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength; + Status = RestoreLockBox ( + &mBootScriptDataBootTimeGuid, + (VOID *)mS3BootScriptTablePtr->TableBase, + &LockBoxLength + ); + ASSERT_EFI_ERROR (Status); + + // + // Update the data to BootScriptData LockBox. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + 0, + (VOID *)mS3BootScriptTablePtr->TableBase, + LockBoxLength + ); + ASSERT_EFI_ERROR (Status); + + // + // Update TableLength. + // + mS3BootScriptTablePtr->TableLength = (UINT32)(mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE)); +} + +/** + 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 boot script entry will write into + **/ +UINT8 * +S3BootScriptGetEntryAddAddress ( + UINT8 EntryLength + ) +{ + UINT8 *NewEntryPtr; + + if (!mS3BootScriptAcpiS3Enable) { + return NULL; + } + + if (mS3BootScriptTablePtr->SmmLocked) { + // + // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script. + // + if (!mS3BootScriptTablePtr->InSmm) { + // + // Add DEBUG ERROR, so that we can find it after SmmReadyToLock. + // Do not use ASSERT, because we may have test to invoke this interface. + // + DEBUG ((DEBUG_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n")); + return NULL; + } + + if (mS3BootScriptTablePtr->BackFromS3) { + // + // Back from S3, restore boot time boot script data from LockBox + // and set BackFromS3 flag back to FALSE. + // + RestoreBootTimeDataFromLockBox (); + mS3BootScriptTablePtr->BackFromS3 = FALSE; + } + + NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength); + } 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; + UINT32 ScriptOffset; + UINT32 TotalScriptLength; + + if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) { + // + // If it is not after SmmReadyToLock in SMM, + // just return. + // + return; + } + + ScriptOffset = (UINT32)(Script - mS3BootScriptTablePtr->TableBase); + + TotalScriptLength = (UINT32)(mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)); + + // + // Update BootScriptData + // So in S3 resume, the data can be restored correctly. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + ScriptOffset, + (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset), + TotalScriptLength - ScriptOffset + ); + ASSERT_EFI_ERROR (Status); + + // + // Now the length field is updated, need sync to lockbox. + // So at S3 resume, the data can be restored correctly. + // + Status = UpdateLockBox ( + &mBootScriptDataGuid, + OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), + &TotalScriptLength, + sizeof (TotalScriptLength) + ); + 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 at 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 or no action is required as ACPI S3 was disabled. +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + WidthInByte = (UINT8)(0x01 << (Width & 0x03)); + + // + // Truncation check + // + if ((Count > MAX_UINT8) || + (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_IO_WRITE))) + { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + WidthInByte = (UINT8)(0x01 << (Width & 0x03)); + + // + // Truncation check + // + if ((Count > MAX_UINT8) || + (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_MEM_WRITE))) + { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + @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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + if ((Width == S3BootScriptWidthUint64) || + (Width == S3BootScriptWidthFifoUint64) || + (Width == S3BootScriptWidthFillUint64)) + { + return EFI_INVALID_PARAMETER; + } + + WidthInByte = (UINT8)(0x01 << (Width & 0x03)); + + // + // Truncation check + // + if ((Count > MAX_UINT8) || + (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE))) + { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. + @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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + if ((Width == S3BootScriptWidthUint64) || + (Width == S3BootScriptWidthFifoUint64) || + (Width == S3BootScriptWidthFillUint64)) + { + return EFI_INVALID_PARAMETER; + } + + WidthInByte = (UINT8)(0x01 << (Width & 0x03)); + + // + // Truncation check + // + if ((Count > MAX_UINT8) || + (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE))) + { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. + @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + if ((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 or no action is required as ACPI S3 was disabled. +**/ +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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + if (Length == NULL) { + BufferLength = 0; + } else { + BufferLength = *Length; + } + + Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Truncation check + // + if (BufferLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)) { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveStall ( + IN UINTN Duration + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_STALL ScriptStall; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveDispatch2 ( + IN VOID *EntryPoint, + IN VOID *Context + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveMemPoll ( + IN S3_BOOT_SCRIPT_LIB_WIDTH Width, + IN UINT64 Address, + IN VOID *BitMask, + IN VOID *BitValue, + IN UINTN Duration, + IN UINT64 LoopTimes + ) +{ + UINT8 Length; + UINT8 *Script; + UINT8 WidthInByte; + EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveInformation ( + IN UINT32 InformationLength, + IN VOID *Information + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_INFORMATION ScriptInformation; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + // + // Truncation check + // + if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required as ACPI S3 was disabled. + +**/ +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 or no action is required as ACPI S3 was disabled. +**/ +RETURN_STATUS +EFIAPI +S3BootScriptSaveDispatch ( + IN VOID *EntryPoint + ) +{ + UINT8 Length; + UINT8 *Script; + EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + @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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + @note A known Limitations in the implementation which is 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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + if ((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)Position - (UINTN)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 no action is required as ACPI S3 was disabled. +**/ +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]; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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 or no action is required as ACPI S3 was disabled. + +**/ +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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + // + // Truncation check + // + if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) { + return RETURN_OUT_OF_RESOURCES; + } + + 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 or no action is required. + A record was added into the specified script table if ACPI S3 was enabled. + @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; + + if (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + // + // 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 or no action is required. + A record was added into the specified script table if ACPI S3 was enabled. + @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 (!mS3BootScriptAcpiS3Enable) { + return RETURN_SUCCESS; + } + + 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; +} -- cgit v1.2.3