mirror of https://github.com/acidanthera/audk.git
2495 lines
83 KiB
C
2495 lines
83 KiB
C
/** @file
|
|
Save the S3 data to S3 boot script.
|
|
|
|
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
|
|
|
|
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", __FUNCTION__, 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.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveIoWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN VOID *Buffer
|
|
)
|
|
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_IO_WRITE ScriptIoWrite;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
|
|
//
|
|
// 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.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveIoReadWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *Data,
|
|
IN VOID *DataMask
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;
|
|
ScriptIoReadWrite.Length = Length;
|
|
ScriptIoReadWrite.Width = Width;
|
|
ScriptIoReadWrite.Address = Address;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptIoReadWrite, sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE));
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for a memory write operation into a specified boot script table.
|
|
|
|
@param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
|
|
@param Address The base address of the memory operations
|
|
@param Count The number of memory operations to perform.
|
|
@param Buffer The source buffer from which to write the data.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveMemWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
|
|
//
|
|
// 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.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveMemReadWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *Data,
|
|
IN VOID *DataMask
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;
|
|
ScriptMemReadWrite.Length = Length;
|
|
ScriptMemReadWrite.Width = Width;
|
|
ScriptMemReadWrite.Address = Address;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptMemReadWrite, sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for a PCI configuration space write operation into a specified boot script table.
|
|
|
|
@param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
|
|
@param Address The address within the PCI configuration space.
|
|
@param Count The number of PCI operations to perform.
|
|
@param Buffer The source buffer from which to write the data.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
@note A known Limitations in the implementation which is 64bits operations are not supported.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSavePciCfgWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;
|
|
|
|
if ((Width == S3BootScriptWidthUint64) ||
|
|
(Width == S3BootScriptWidthFifoUint64) ||
|
|
(Width == S3BootScriptWidthFillUint64))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
|
|
//
|
|
// 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.
|
|
@note A known Limitations in the implementation which is 64bits operations are not supported.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSavePciCfgReadWrite (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *Data,
|
|
IN VOID *DataMask
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;
|
|
|
|
if ((Width == S3BootScriptWidthUint64) ||
|
|
(Width == S3BootScriptWidthFifoUint64) ||
|
|
(Width == S3BootScriptWidthFillUint64))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;
|
|
ScriptPciReadWrite.Length = Length;
|
|
ScriptPciReadWrite.Width = Width;
|
|
ScriptPciReadWrite.Address = Address;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);
|
|
CopyMem (
|
|
(VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),
|
|
DataMask,
|
|
WidthInByte
|
|
);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for a PCI configuration 2 space write operation into a specified boot script table.
|
|
|
|
@param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
|
|
@param Segment The PCI segment number for Address.
|
|
@param Address The address within the PCI configuration space.
|
|
@param Count The number of PCI operations to perform.
|
|
@param Buffer The source buffer from which to write the data.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
@note A known Limitations in the implementation which is 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 ((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.
|
|
@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 ((Width == S3BootScriptWidthUint64) ||
|
|
(Width == S3BootScriptWidthFifoUint64) ||
|
|
(Width == S3BootScriptWidthFillUint64))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;
|
|
ScriptPciReadWrite2.Length = Length;
|
|
ScriptPciReadWrite2.Width = Width;
|
|
ScriptPciReadWrite2.Segment = Segment;
|
|
ScriptPciReadWrite2.Address = Address;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
|
|
CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);
|
|
CopyMem (
|
|
(VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),
|
|
DataMask,
|
|
WidthInByte
|
|
);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Checks the parameter of S3BootScriptSaveSmbusExecute().
|
|
|
|
This function checks the input parameters of SmbusExecute(). If the input parameters are valid
|
|
for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
|
|
error code based on the input SMBus bus protocol.
|
|
|
|
@param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
|
|
and PEC.
|
|
@param Operation Signifies which particular SMBus hardware protocol instance that
|
|
it will use to execute the SMBus transactions. This SMBus
|
|
hardware protocol is defined by the SMBus Specification and is
|
|
not related to EFI.
|
|
@param Length Signifies the number of bytes that this operation will do. The
|
|
maximum number of bytes can be revision specific and operation
|
|
specific. This field will contain the actual number of bytes that
|
|
are executed for this operation. Not all operations require this
|
|
argument.
|
|
@param Buffer Contains the value of data to execute to the SMBus slave device.
|
|
Not all operations require this argument. The length of this
|
|
buffer is identified by Length.
|
|
|
|
@retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus
|
|
protocol.
|
|
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
|
|
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
|
|
and EfiSmbusQuickWrite. Length is outside the range of valid
|
|
values.
|
|
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
|
|
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CheckParameters (
|
|
IN UINTN SmBusAddress,
|
|
IN EFI_SMBUS_OPERATION Operation,
|
|
IN OUT UINTN *Length,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN RequiredLen;
|
|
EFI_SMBUS_DEVICE_COMMAND Command;
|
|
BOOLEAN PecCheck;
|
|
|
|
Command = SMBUS_LIB_COMMAND (SmBusAddress);
|
|
PecCheck = SMBUS_LIB_PEC (SmBusAddress);
|
|
//
|
|
// Set default value to be 2:
|
|
// for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
|
|
//
|
|
RequiredLen = 2;
|
|
Status = EFI_SUCCESS;
|
|
switch (Operation) {
|
|
case EfiSmbusQuickRead:
|
|
case EfiSmbusQuickWrite:
|
|
if (PecCheck || (Command != 0)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
break;
|
|
case EfiSmbusReceiveByte:
|
|
case EfiSmbusSendByte:
|
|
if (Command != 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Cascade to check length parameter.
|
|
//
|
|
case EfiSmbusReadByte:
|
|
case EfiSmbusWriteByte:
|
|
RequiredLen = 1;
|
|
//
|
|
// Cascade to check length parameter.
|
|
//
|
|
case EfiSmbusReadWord:
|
|
case EfiSmbusWriteWord:
|
|
case EfiSmbusProcessCall:
|
|
if ((Buffer == NULL) || (Length == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
} else if (*Length < RequiredLen) {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*Length = RequiredLen;
|
|
break;
|
|
case EfiSmbusReadBlock:
|
|
case EfiSmbusWriteBlock:
|
|
case EfiSmbusBWBRProcessCall:
|
|
if ((Buffer == NULL) ||
|
|
(Length == NULL) ||
|
|
(*Length < MIN_SMBUS_BLOCK_LEN) ||
|
|
(*Length > MAX_SMBUS_BLOCK_LEN))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Adds a record for an SMBus command execution into a specified boot script table.
|
|
|
|
@param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.
|
|
@param Operation Indicates which particular SMBus protocol it will use to execute the SMBus
|
|
transactions.
|
|
@param Length A pointer to signify the number of bytes that this operation will do.
|
|
@param Buffer Contains the value of data to execute to the SMBUS slave device.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveSmbusExecute (
|
|
IN UINTN SmBusAddress,
|
|
IN EFI_SMBUS_OPERATION Operation,
|
|
IN UINTN *Length,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferLength;
|
|
UINT8 DataSize;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;
|
|
|
|
if (Length == NULL) {
|
|
BufferLength = 0;
|
|
} else {
|
|
BufferLength = *Length;
|
|
}
|
|
|
|
Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveStall (
|
|
IN UINTN Duration
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_STALL ScriptStall;
|
|
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE;
|
|
ScriptStall.Length = Length;
|
|
ScriptStall.Duration = Duration;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for dispatching specified arbitrary code into a specified boot script table.
|
|
|
|
@param EntryPoint Entry point of the code to be dispatched.
|
|
@param Context Argument to be passed into the EntryPoint of the code to be dispatched.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveDispatch2 (
|
|
IN VOID *EntryPoint,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;
|
|
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;
|
|
ScriptDispatch2.Length = Length;
|
|
ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
|
|
ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for memory reads of the memory location and continues when the exit criteria is
|
|
satisfied or after a defined duration.
|
|
|
|
Please aware, below interface is different with PI specification, Vol 5:
|
|
EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.
|
|
"Duration" below is microseconds, while "Delay" in PI specification means
|
|
the number of 100ns units to poll.
|
|
|
|
@param Width The width of the memory operations.
|
|
@param Address The base address of the memory operations.
|
|
@param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.
|
|
@param BitValue A pointer to the data value after to be Masked.
|
|
@param Duration Duration in microseconds of the stall.
|
|
@param LoopTimes The times of the register polling.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveMemPoll (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *BitMask,
|
|
IN VOID *BitValue,
|
|
IN UINTN Duration,
|
|
IN UINT64 LoopTimes
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;
|
|
ScriptMemPoll.Length = Length;
|
|
ScriptMemPoll.Width = Width;
|
|
ScriptMemPoll.Address = Address;
|
|
ScriptMemPoll.Duration = Duration;
|
|
ScriptMemPoll.LoopTimes = LoopTimes;
|
|
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only
|
|
used for debugging script issues.
|
|
|
|
@param InformationLength Length of the data in bytes
|
|
@param Information Information to be logged in the boot scrpit
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveInformation (
|
|
IN UINT32 InformationLength,
|
|
IN VOID *Information
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
|
|
|
|
//
|
|
// 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.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveInformationAsciiString (
|
|
IN CONST CHAR8 *String
|
|
)
|
|
{
|
|
return S3BootScriptSaveInformation (
|
|
(UINT32)AsciiStrLen (String) + 1,
|
|
(VOID *)String
|
|
);
|
|
}
|
|
|
|
/**
|
|
Adds a record for dispatching specified arbitrary code into a specified boot script table.
|
|
|
|
@param EntryPoint Entry point of the code to be dispatched.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveDispatch (
|
|
IN VOID *EntryPoint
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;
|
|
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;
|
|
ScriptDispatch.Length = Length;
|
|
ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a
|
|
defined duration.
|
|
|
|
@param Width The width of the I/O operations.
|
|
@param Address The base address of the I/O operations.
|
|
@param Data The comparison value used for the polling exit criteria.
|
|
@param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
|
|
in Data are ignored when polling the memory address.
|
|
@param Delay The number of 100ns units to poll. Note that timer available may be of poorer
|
|
granularity so the delay may be longer.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSaveIoPoll (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *Data,
|
|
IN VOID *DataMask,
|
|
IN UINT64 Delay
|
|
)
|
|
{
|
|
UINT8 WidthInByte;
|
|
UINT8 *Script;
|
|
UINT8 Length;
|
|
EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll;
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;
|
|
ScriptIoPoll.Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
|
|
ScriptIoPoll.Width = Width;
|
|
ScriptIoPoll.Address = Address;
|
|
ScriptIoPoll.Delay = Delay;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
|
|
after a defined duration.
|
|
|
|
@param Width The width of the I/O operations.
|
|
@param Address The address within the PCI configuration space.
|
|
@param Data The comparison value used for the polling exit criteria.
|
|
@param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
|
|
in Data are ignored when polling the memory address
|
|
@param Delay The number of 100ns units to poll. Note that timer available may be of poorer
|
|
granularity so the delay may be longer.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
@note A known Limitations in the implementation which is 64bits operations are not supported.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptSavePciPoll (
|
|
IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN VOID *Data,
|
|
IN VOID *DataMask,
|
|
IN UINT64 Delay
|
|
)
|
|
{
|
|
UINT8 *Script;
|
|
UINT8 WidthInByte;
|
|
UINT8 Length;
|
|
EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;
|
|
|
|
if ((Width == S3BootScriptWidthUint64) ||
|
|
(Width == S3BootScriptWidthFifoUint64) ||
|
|
(Width == S3BootScriptWidthFillUint64))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
WidthInByte = (UINT8)(0x01 << (Width & 0x03));
|
|
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
|
|
|
|
Script = S3BootScriptGetEntryAddAddress (Length);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Build script data
|
|
//
|
|
ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;
|
|
ScriptPciPoll.Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
|
|
ScriptPciPoll.Width = Width;
|
|
ScriptPciPoll.Address = Address;
|
|
ScriptPciPoll.Delay = Delay;
|
|
|
|
CopyMem ((VOID *)Script, (VOID *)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);
|
|
CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
|
|
after a defined duration.
|
|
|
|
@param Width The width of the I/O operations.
|
|
@param Segment The PCI segment number for Address.
|
|
@param Address The address within the PCI configuration space.
|
|
@param Data The comparison value used for the polling exit criteria.
|
|
@param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
|
|
in Data are ignored when polling the memory address
|
|
@param Delay The number of 100ns units to poll. Note that timer available may be of poorer
|
|
granularity so the delay may be longer.
|
|
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
@note A known Limitations in the implementation which is 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 ((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.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptMoveLastOpcode (
|
|
IN BOOLEAN BeforeOrAfter,
|
|
IN OUT VOID **Position OPTIONAL
|
|
)
|
|
{
|
|
UINT8 *Script;
|
|
VOID *TempPosition;
|
|
UINTN StartAddress;
|
|
UINT32 TableLength;
|
|
EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
|
|
BOOLEAN ValidatePosition;
|
|
UINT8 *LastOpcode;
|
|
UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];
|
|
|
|
ValidatePosition = FALSE;
|
|
TempPosition = (Position == NULL) ? NULL : (*Position);
|
|
|
|
//
|
|
// Check that the script is initialized and synced without adding an entry to the script.
|
|
//
|
|
Script = S3BootScriptGetEntryAddAddress (0);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Script = mS3BootScriptTablePtr->TableBase;
|
|
|
|
StartAddress = (UINTN)Script;
|
|
TableLength = mS3BootScriptTablePtr->TableLength;
|
|
Script = Script + sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
|
|
LastOpcode = Script;
|
|
//
|
|
// Find the last boot Script Entry which is not the terminate node
|
|
//
|
|
while ((UINTN)Script < (UINTN)(StartAddress + TableLength)) {
|
|
CopyMem ((VOID *)&ScriptHeader, Script, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));
|
|
if ((TempPosition != NULL) && (TempPosition == Script)) {
|
|
//
|
|
// If the position is specified, the position must be pointed to a boot script entry start address.
|
|
//
|
|
ValidatePosition = TRUE;
|
|
}
|
|
|
|
if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {
|
|
LastOpcode = Script;
|
|
}
|
|
|
|
Script = Script + ScriptHeader.Length;
|
|
}
|
|
|
|
//
|
|
// If the position is specified, but not the start of a boot script entry, it is a invalid input
|
|
//
|
|
if ((TempPosition != NULL) && !ValidatePosition) {
|
|
return RETURN_INVALID_PARAMETER;
|
|
}
|
|
|
|
CopyMem ((VOID *)&ScriptHeader, LastOpcode, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));
|
|
|
|
CopyMem ((VOID *)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);
|
|
//
|
|
// Find the right position to write the node in
|
|
//
|
|
S3BootScriptCalculateInsertAddress (
|
|
ScriptHeader.Length,
|
|
TempPosition,
|
|
BeforeOrAfter,
|
|
&Script
|
|
);
|
|
//
|
|
// Copy the node to Boot script table
|
|
//
|
|
CopyMem ((VOID *)Script, (VOID *)TempBootScriptEntry, ScriptHeader.Length);
|
|
|
|
SyncBootScript (Script);
|
|
|
|
//
|
|
// return out the Position
|
|
//
|
|
if (Position != NULL) {
|
|
*Position = Script;
|
|
}
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Create a Label node in the boot script table.
|
|
|
|
@param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
|
|
in the boot script table specified by Position. If Position is NULL or points to
|
|
NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
|
|
of the table (if FALSE).
|
|
@param Position On entry, specifies the position in the boot script table where the opcode will be
|
|
inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
|
|
the position of the inserted opcode in the boot script table.
|
|
@param InformationLength Length of the label in bytes
|
|
@param Information Label to be logged in the boot scrpit
|
|
|
|
@retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
|
|
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
|
|
@retval RETURN_SUCCESS Opcode is added.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptLabelInternal (
|
|
IN BOOLEAN BeforeOrAfter,
|
|
IN OUT VOID **Position OPTIONAL,
|
|
IN UINT32 InformationLength,
|
|
IN CONST CHAR8 *Information
|
|
)
|
|
{
|
|
UINT8 Length;
|
|
UINT8 *Script;
|
|
EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
|
|
|
|
//
|
|
// 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. A record was added into the
|
|
specified script table.
|
|
@retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
|
|
If the opcode is unknow or not supported because of the PCD
|
|
Feature Flags.
|
|
@retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptLabel (
|
|
IN BOOLEAN BeforeOrAfter,
|
|
IN BOOLEAN CreateIfNotFound,
|
|
IN OUT VOID **Position OPTIONAL,
|
|
IN CONST CHAR8 *Label
|
|
)
|
|
{
|
|
UINT8 *Script;
|
|
UINTN StartAddress;
|
|
UINT32 TableLength;
|
|
EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
|
|
EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;
|
|
UINT32 LabelLength;
|
|
|
|
//
|
|
// Check NULL Label
|
|
//
|
|
if (Label == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check empty Label
|
|
//
|
|
if (Label[0] == '\0') {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check that the script is initialized and synced without adding an entry to the script.
|
|
// The code must search for the label first before it knows if a new entry needs
|
|
// to be added.
|
|
//
|
|
Script = S3BootScriptGetEntryAddAddress (0);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Check the header and search for existing label.
|
|
//
|
|
Script = mS3BootScriptTablePtr->TableBase;
|
|
CopyMem ((VOID *)&TableHeader, Script, sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER));
|
|
if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
StartAddress = (UINTN)Script;
|
|
TableLength = mS3BootScriptTablePtr->TableLength;
|
|
Script = Script + TableHeader.Length;
|
|
while ((UINTN)Script < (UINTN)(StartAddress + TableLength)) {
|
|
CopyMem ((VOID *)&ScriptHeader, Script, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));
|
|
if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {
|
|
if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof (EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {
|
|
(*Position) = Script;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Script = Script + ScriptHeader.Length;
|
|
}
|
|
|
|
if (CreateIfNotFound) {
|
|
LabelLength = (UINT32)AsciiStrSize (Label);
|
|
return S3BootScriptLabelInternal (BeforeOrAfter, Position, LabelLength, Label);
|
|
} else {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Compare two positions in the boot script table and return their relative position.
|
|
@param Position1 The positions in the boot script table to compare
|
|
@param Position2 The positions in the boot script table to compare
|
|
@param RelativePosition On return, points to the result of the comparison
|
|
|
|
@retval EFI_SUCCESS The operation succeeded. A record was added into the
|
|
specified script table.
|
|
@retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
|
|
If the opcode is unknow or not supported because of the PCD
|
|
Feature Flags.
|
|
@retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
S3BootScriptCompare (
|
|
IN UINT8 *Position1,
|
|
IN UINT8 *Position2,
|
|
OUT UINTN *RelativePosition
|
|
)
|
|
{
|
|
UINT8 *Script;
|
|
UINT32 TableLength;
|
|
|
|
if (RelativePosition == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check that the script is initialized and synced without adding an entry to the script.
|
|
//
|
|
Script = S3BootScriptGetEntryAddAddress (0);
|
|
if (Script == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Script = mS3BootScriptTablePtr->TableBase;
|
|
|
|
//
|
|
// mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up
|
|
//
|
|
TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
|
|
if ((Position1 < Script) || (Position1 > Script+TableLength)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Position2 < Script) || (Position2 > Script+TableLength)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*RelativePosition = (Position1 < Position2) ? -1 : ((Position1 == Position2) ? 0 : 1);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|