/** @file\r
- Save the S3 data to S3 boot script. \r
- \r
- Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
+ Save the S3 data to S3 boot script.\r
+\r
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
\r
Data structure usage:\r
\r
- +------------------------------+<-- PcdS3BootScriptTablePrivateDataPtr\r
+ +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr\r
+ | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock)\r
+ | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr\r
+ | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm)\r
+ | TableMemoryPageNumber |--|-|----\r
+ | AtRuntime | | | |\r
+ | InSmm | | | |\r
+ | BootTimeScriptLength |--|-|---|---\r
+ | SmmLocked | | | | |\r
+ | BackFromS3 | | | | |\r
+ +------------------------------+ | | | |\r
+ | | | |\r
+ +------------------------------+<-- | | |\r
+ | EFI_BOOT_SCRIPT_TABLE_HEADER | | | |\r
+ | TableLength |----|-- | |\r
+ +------------------------------+ | | | |\r
+ | ...... | | | | |\r
+ +------------------------------+<---- | | |\r
+ | EFI_BOOT_SCRIPT_TERMINATE | | | |\r
+ +------------------------------+<------ | |\r
+ | |\r
+ | |\r
+ mBootScriptDataBootTimeGuid LockBox: | |\r
+ Used to restore data after back from S3| |\r
+ to handle potential INSERT boot script | |\r
+ at runtime. | |\r
+ +------------------------------+ | |\r
+ | Boot Time Boot Script | | |\r
+ | Before SmmReadyToLock | | |\r
+ | | | |\r
+ | | | |\r
+ +------------------------------+ | |\r
+ | Boot Time Boot Script | | |\r
+ | After SmmReadyToLock InSmm | | |\r
+ | | | |\r
+ +------------------------------+<-------|--|\r
+ | |\r
+ | |\r
+ mBootScriptDataGuid LockBox: (IN_PLACE) | |\r
+ Used to restore data at S3 resume. | |\r
+ +------------------------------+ | |\r
+ | Boot Time Boot Script | | |\r
+ | Before SmmReadyToLock | | |\r
+ | | | |\r
+ | | | |\r
+ +------------------------------+ | |\r
+ | Boot Time Boot Script | | |\r
+ | After SmmReadyToLock InSmm | | |\r
+ | | | |\r
+ +------------------------------+<-------|---\r
+ | Runtime Boot Script | |\r
+ | After SmmReadyToLock InSmm | |\r
+ +------------------------------+ |\r
+ | ...... | |\r
+ +------------------------------+<--------\r
+\r
+\r
+ mBootScriptTableBaseGuid LockBox: (IN_PLACE)\r
+ +------------------------------+\r
+ | mS3BootScriptTablePtr-> |\r
+ | TableBase |\r
+ +------------------------------+\r
+\r
+\r
+ mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE)\r
+ SMM private data with BackFromS3 = TRUE\r
+ at runtime. S3 will help restore it to\r
+ tell the Library the system is back from S3.\r
+ +------------------------------+\r
| SCRIPT_TABLE_PRIVATE_DATA |\r
- | TableBase |---\r
- | TableLength |--|--\r
- | AtRuntime | | |\r
- | InSmm | | |\r
- +------------------------------+ | |\r
- | |\r
- +------------------------------+<-- |\r
- | EFI_BOOT_SCRIPT_TABLE_HEADER | |\r
- | TableLength |----|--\r
- +------------------------------+ | |\r
- | ...... | | |\r
- +------------------------------+<---- |\r
- | EFI_BOOT_SCRIPT_TERMINATE | |\r
- +------------------------------+<------\r
+ | TableBase |\r
+ | TableLength |\r
+ | TableMemoryPageNumber |\r
+ | AtRuntime |\r
+ | InSmm |\r
+ | BootTimeScriptLength |\r
+ | SmmLocked |\r
+ | BackFromS3 = TRUE |\r
+ +------------------------------+\r
\r
**/\r
\r
SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;\r
-EFI_EVENT mEnterRuntimeEvent;\r
+\r
//\r
-// Allocate local copy in SMM because we can not use mS3BootScriptTablePtr when we AtRuntime in InSmm.\r
+// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm.\r
//\r
-SCRIPT_TABLE_PRIVATE_DATA mS3BootScriptTable;\r
-UINTN mLockBoxLength;\r
+SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr;\r
\r
EFI_GUID mBootScriptDataGuid = {\r
0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }\r
};\r
\r
-EFI_GUID mBootScriptHeaderDataGuid = {\r
+EFI_GUID mBootScriptDataBootTimeGuid = {\r
+ 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }\r
+};\r
+\r
+EFI_GUID mBootScriptTableBaseGuid = {\r
0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }\r
};\r
\r
-EFI_GUID mBootScriptInformationGuid = {\r
- 0x2c680508, 0x2b87, 0x46ab, { 0xb9, 0x8a, 0x49, 0xfc, 0x23, 0xf9, 0xf5, 0x95 }\r
+EFI_GUID mBootScriptSmmPrivateDataGuid = {\r
+ 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 }\r
};\r
\r
+EFI_EVENT mEventDxeSmmReadyToLock = NULL;\r
+VOID *mRegistrationSmmExitBootServices = NULL;\r
+VOID *mRegistrationSmmLegacyBoot = NULL;\r
+VOID *mRegistrationSmmReadyToLock = NULL;\r
+BOOLEAN mS3BootScriptTableAllocated = FALSE;\r
+BOOLEAN mS3BootScriptTableSmmAllocated = FALSE;\r
+EFI_SMM_SYSTEM_TABLE2 *mSmst = NULL;\r
+\r
/**\r
This is an internal function to add a terminate node the entry, recalculate the table \r
length and fill into the table. \r
\r
- @return the base address of the boot script tble. \r
+ @return the base address of the boot script table. \r
**/\r
UINT8*\r
S3BootScriptInternalCloseTable (\r
return S3TableBase;\r
//\r
// NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to \r
- // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). Because \r
- // maybe in runtime, we still need add entries into the table, and the runtime entry should be\r
- // added start before this TERMINATE node.\r
+ // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE).\r
+ // Because maybe after SmmReadyToLock, we still need add entries into the table,\r
+ // and the entry should be added start before this TERMINATE node.\r
//\r
} \r
\r
-/**\r
- This function return the total size of INFORMATION OPCODE in boot script table.\r
-\r
- @return InformationBufferSize The total size of INFORMATION OPCODE in boot script table.\r
-**/\r
-UINTN\r
-GetBootScriptInformationBufferSize (\r
- VOID\r
- )\r
-{\r
- UINT8 *S3TableBase;\r
- UINT8 *Script;\r
- UINTN TableLength;\r
- EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
- EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;\r
- EFI_BOOT_SCRIPT_INFORMATION Information;\r
- UINTN InformationBufferSize;\r
-\r
- InformationBufferSize = 0;\r
-\r
- S3TableBase = mS3BootScriptTablePtr->TableBase;\r
- Script = S3TableBase;\r
- CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));\r
- TableLength = TableHeader.TableLength;\r
-\r
- //\r
- // Go through the ScriptTable\r
- //\r
- while ((UINTN) Script < (UINTN) (S3TableBase + TableLength)) {\r
- CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
- switch (ScriptHeader.OpCode) {\r
- case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:\r
- CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(Information));\r
- InformationBufferSize += Information.InformationLength;\r
- break;\r
- default:\r
- break;\r
- }\r
- Script = Script + ScriptHeader.Length;\r
- }\r
-\r
- return InformationBufferSize;\r
-}\r
-\r
-/**\r
- This function fix INFORMATION OPCODE in boot script table.\r
- Originally, the Information buffer is pointer to EfiRuntimeServicesCode,\r
- EfiRuntimeServicesData, or EfiACPIMemoryNVS. They are seperated.\r
- Now, in order to save it to LockBox, we allocate a big EfiACPIMemoryNVS,\r
- and fix the pointer for INFORMATION opcode InformationBuffer.\r
-\r
- @param InformationBuffer The address of new Information buffer.\r
- @param InformationBufferSize The size of new Information buffer.\r
-**/\r
-VOID\r
-FixBootScriptInformation (\r
- IN VOID *InformationBuffer,\r
- IN UINTN InformationBufferSize\r
- )\r
-{\r
- UINT8 *S3TableBase;\r
- UINT8 *Script;\r
- UINTN TableLength;\r
- EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
- EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;\r
- EFI_BOOT_SCRIPT_INFORMATION Information;\r
- UINTN FixedInformationBufferSize;\r
-\r
- FixedInformationBufferSize = 0;\r
-\r
- S3TableBase = mS3BootScriptTablePtr->TableBase;\r
- Script = S3TableBase;\r
- CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));\r
- TableLength = TableHeader.TableLength;\r
-\r
- //\r
- // Go through the ScriptTable\r
- //\r
- while ((UINTN) Script < (UINTN) (S3TableBase + TableLength)) {\r
- CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
- switch (ScriptHeader.OpCode) {\r
- case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:\r
- CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(Information));\r
-\r
- CopyMem (\r
- (VOID *)((UINTN)InformationBuffer + FixedInformationBufferSize),\r
- (VOID *)(UINTN)Information.Information,\r
- Information.InformationLength\r
- );\r
- gBS->FreePool ((VOID *)(UINTN)Information.Information);\r
- Information.Information = (EFI_PHYSICAL_ADDRESS)((UINTN)InformationBuffer + FixedInformationBufferSize);\r
-\r
- CopyMem ((VOID*)Script, (VOID*)&Information, sizeof(Information));\r
-\r
- FixedInformationBufferSize += Information.InformationLength;\r
- break;\r
- default:\r
- break;\r
- }\r
- Script = Script + ScriptHeader.Length;\r
- }\r
-\r
- ASSERT (FixedInformationBufferSize == InformationBufferSize);\r
-\r
- return ;\r
-}\r
-\r
/**\r
This function save boot script data to LockBox.\r
- 1. BootSriptPrivate data, BootScript data - Image and DispatchContext are handled by platform.\r
- 2. BootScriptExecutor, BootScriptExecutor context\r
- - ACPI variable - (PI version) sould be handled by SMM driver. S3 Page table is handled here.\r
- - ACPI variable - framework version is already handled by Framework CPU driver.\r
+\r
**/\r
VOID\r
SaveBootScriptDataToLockBox (\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS InformationBuffer;\r
- UINTN InformationBufferSize;\r
\r
//\r
- // We need save BootScriptInformation to LockBox, because it is in\r
- // EfiRuntimeServicesCode, EfiRuntimeServicesData, or EfiACPIMemoryNVS.\r
- // \r
- //\r
- InformationBufferSize = GetBootScriptInformationBufferSize ();\r
- if (InformationBufferSize != 0) {\r
- InformationBuffer = 0xFFFFFFFF;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
- EFI_SIZE_TO_PAGES(InformationBufferSize),\r
- &InformationBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Fix BootScript information pointer\r
- //\r
- FixBootScriptInformation ((VOID *)(UINTN)InformationBuffer, InformationBufferSize);\r
-\r
- //\r
- // Save BootScript information to lockbox\r
- //\r
- Status = SaveLockBox (\r
- &mBootScriptInformationGuid,\r
- (VOID *)(UINTN)InformationBuffer,\r
- InformationBufferSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = SetLockBoxAttributes (&mBootScriptInformationGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- //\r
- // mS3BootScriptTablePtr->TableLength does not include EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime.\r
- // Save all info here, just in case that no one will add boot script entry in SMM.\r
+ // Save whole memory copy into LockBox.\r
+ // It will be used to restore data at S3 resume.\r
//\r
Status = SaveLockBox (\r
&mBootScriptDataGuid,\r
(VOID *)mS3BootScriptTablePtr->TableBase,\r
- mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE)\r
+ EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber)\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
// Do not update other field because they will NOT be used in S3.\r
//\r
Status = SaveLockBox (\r
- &mBootScriptHeaderDataGuid,\r
+ &mBootScriptTableBaseGuid,\r
(VOID *)&mS3BootScriptTablePtr->TableBase,\r
sizeof(mS3BootScriptTablePtr->TableBase)\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
- Status = SetLockBoxAttributes (&mBootScriptHeaderDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+ Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
ASSERT_EFI_ERROR (Status);\r
}\r
\r
/**\r
This is the Event call back function to notify the Library the system is entering\r
- run time phase.\r
+ SmmLocked phase.\r
\r
@param Event Pointer to this event\r
- @param Context Event hanlder private data \r
+ @param Context Event handler private data \r
**/\r
VOID\r
EFIAPI\r
}\r
\r
//\r
- // Here we should tell the library that we are enter into runtime phase. and \r
- // the memory page number occupied by the table should not grow anymore.\r
+ // Here we should tell the library that we are entering SmmLocked phase.\r
+ // and the memory page number occupied by the table should not grow anymore.\r
//\r
- if (!mS3BootScriptTablePtr->AtRuntime) {\r
+ if (!mS3BootScriptTablePtr->SmmLocked) {\r
//\r
- // In boot time, we need not write the terminate node when adding a node to boot scipt table\r
- // or else, that will impact the performance. However, in runtime, we should append terminate\r
- // node on every add to boot script table\r
+ // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table\r
+ // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate\r
+ // node on every add to boot script table.\r
//\r
S3BootScriptInternalCloseTable ();\r
- mS3BootScriptTablePtr->AtRuntime = TRUE;\r
+ mS3BootScriptTablePtr->SmmLocked = TRUE;\r
\r
//\r
// Save BootScript data to lockbox\r
//\r
SaveBootScriptDataToLockBox ();\r
}\r
-} \r
+}\r
+\r
/**\r
- This is the Event call back function is triggered in SMM to notify the Library the system is entering\r
- run time phase and set InSmm flag.\r
- \r
+ This is the Event call back function is triggered in SMM to notify the Library\r
+ the system is entering SmmLocked phase and set InSmm flag.\r
+\r
@param Protocol Points to the protocol's unique identifier\r
@param Interface Points to the interface instance\r
@param Handle The handle on which the interface was installed\r
//\r
// Check if it is already done\r
//\r
- if (mS3BootScriptTablePtr == &mS3BootScriptTable) {\r
+ if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {\r
return EFI_SUCCESS;\r
}\r
\r
//\r
- // Last chance to call-out, just make sure AtRuntime is set\r
+ // Last chance to call-out, just make sure SmmLocked is set.\r
//\r
S3BootScriptEventCallBack (NULL, NULL);\r
\r
//\r
- // Save a local copy\r
+ // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.\r
//\r
- CopyMem (&mS3BootScriptTable, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));\r
+ if (mS3BootScriptTableSmmPtr->TableBase == NULL) {\r
+ CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));\r
+\r
+ //\r
+ // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.\r
+ // InSmm will only be checked if SmmLocked is TRUE.\r
+ //\r
+ mS3BootScriptTableSmmPtr->InSmm = TRUE;\r
+ }\r
//\r
- // We should not use ACPINvs copy, because it is not safe.\r
+ // We should not use ACPI Reserved copy, because it is not safe.\r
//\r
- mS3BootScriptTablePtr = &mS3BootScriptTable;\r
+ mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is to save boot time boot script data to LockBox.\r
+\r
+ Because there may be INSERT boot script at runtime in SMM.\r
+ The boot time copy will be used to restore data after back from S3.\r
+ Otherwise the data inserted may cause some boot time boot script data lost\r
+ if only BootScriptData used.\r
+\r
+**/\r
+VOID\r
+SaveBootTimeDataToLockBox (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
\r
//\r
- // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.\r
- // InSmm will only be checked if AtRuntime is TRUE.\r
+ // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first,\r
+ // and then save the data to BootScriptDataBootTime LockBox.\r
//\r
- mS3BootScriptTablePtr->InSmm = TRUE;\r
+ Status = RestoreLockBox (\r
+ &mBootScriptDataGuid,\r
+ NULL,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
\r
//\r
- // Record LockBoxLength\r
+ // Save BootScriptDataBootTime\r
+ // It will be used to restore data after back from S3.\r
//\r
- mLockBoxLength = mS3BootScriptTable.TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE);\r
+ Status = SaveLockBox (\r
+ &mBootScriptDataBootTimeGuid,\r
+ (VOID *) mS3BootScriptTablePtr->TableBase,\r
+ mS3BootScriptTablePtr->BootTimeScriptLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+ This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime.\r
+ S3 resume will help restore it to tell the Library the system is back from S3.\r
+\r
+**/\r
+VOID\r
+SaveSmmPriviateDataToLockBoxAtRuntime (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Save boot script SMM private data with BackFromS3 = TRUE.\r
+ //\r
+ mS3BootScriptTablePtr->BackFromS3 = TRUE;\r
+ Status = SaveLockBox (\r
+ &mBootScriptSmmPrivateDataGuid,\r
+ (VOID *) mS3BootScriptTablePtr,\r
+ sizeof (SCRIPT_TABLE_PRIVATE_DATA)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3.\r
+ //\r
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;\r
+}\r
+\r
+/**\r
+ This is the Event call back function is triggered in SMM to notify the Library\r
+ the system is entering runtime phase.\r
+\r
+ @param[in] Protocol Points to the protocol's unique identifier\r
+ @param[in] Interface Points to the interface instance\r
+ @param[in] Handle The handle on which the interface was installed\r
+\r
+ @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully\r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+S3BootScriptSmmAtRuntimeCallBack (\r
+ IN CONST EFI_GUID *Protocol,\r
+ IN VOID *Interface,\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ if (!mS3BootScriptTablePtr->AtRuntime) {\r
+ mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
+ SaveBootTimeDataToLockBox ();\r
+\r
+ mS3BootScriptTablePtr->AtRuntime = TRUE;\r
+ SaveSmmPriviateDataToLockBoxAtRuntime ();\r
+ }\r
\r
return EFI_SUCCESS;\r
}\r
@param ImageHandle The firmware allocated handle for the EFI image.\r
@param SystemTable A pointer to the EFI System Table.\r
\r
- @retval RETURN_SUCCESS Allocate the global memory space to store S3 boot script table private data\r
- @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.\r
+ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
{\r
EFI_STATUS Status;\r
SCRIPT_TABLE_PRIVATE_DATA *S3TablePtr;\r
+ SCRIPT_TABLE_PRIVATE_DATA *S3TableSmmPtr;\r
VOID *Registration;\r
EFI_SMM_BASE2_PROTOCOL *SmmBase2;\r
BOOLEAN InSmm;\r
- EFI_SMM_SYSTEM_TABLE2 *Smst;\r
EFI_PHYSICAL_ADDRESS Buffer;\r
\r
S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);\r
Buffer = SIZE_4GB - 1;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
+ EfiReservedMemoryType,\r
EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),\r
&Buffer\r
);\r
- if (EFI_ERROR (Status)) {\r
- return RETURN_OUT_OF_RESOURCES;\r
- }\r
+ ASSERT_EFI_ERROR (Status);\r
+ mS3BootScriptTableAllocated = TRUE;\r
S3TablePtr = (VOID *) (UINTN) Buffer;\r
\r
- PcdSet64 (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr); \r
- ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); \r
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));\r
//\r
- // create event to notify the library system enter the runtime phase\r
+ // Create event to notify the library system enter the SmmLocked phase.\r
//\r
- mEnterRuntimeEvent = EfiCreateProtocolNotifyEvent (\r
- &gEfiDxeSmmReadyToLockProtocolGuid,\r
- TPL_CALLBACK,\r
- S3BootScriptEventCallBack,\r
- NULL,\r
- &Registration\r
- );\r
- ASSERT (mEnterRuntimeEvent != NULL);\r
- } \r
+ mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent (\r
+ &gEfiDxeSmmReadyToLockProtocolGuid,\r
+ TPL_CALLBACK,\r
+ S3BootScriptEventCallBack,\r
+ NULL,\r
+ &Registration\r
+ );\r
+ ASSERT (mEventDxeSmmReadyToLock != NULL);\r
+ }\r
mS3BootScriptTablePtr = S3TablePtr;\r
\r
//\r
//\r
// Good, we are in SMM\r
//\r
- Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);\r
+ Status = SmmBase2->GetSmstLocation (SmmBase2, &mSmst);\r
if (EFI_ERROR (Status)) {\r
return RETURN_SUCCESS;\r
}\r
\r
+ S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);\r
+ //\r
+ // The Boot script private data in SMM is not be initialized. create it\r
+ //\r
+ if (S3TableSmmPtr == 0) {\r
+ Status = mSmst->SmmAllocatePool (\r
+ EfiRuntimeServicesData,\r
+ sizeof(SCRIPT_TABLE_PRIVATE_DATA),\r
+ (VOID **) &S3TableSmmPtr\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ mS3BootScriptTableSmmAllocated = TRUE;\r
+\r
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));\r
+\r
+ //\r
+ // Register SmmExitBootServices and SmmLegacyBoot notification.\r
+ //\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
+ &gEdkiiSmmExitBootServicesProtocolGuid,\r
+ S3BootScriptSmmAtRuntimeCallBack,\r
+ &mRegistrationSmmExitBootServices\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
+ &gEdkiiSmmLegacyBootProtocolGuid,\r
+ S3BootScriptSmmAtRuntimeCallBack,\r
+ &mRegistrationSmmLegacyBoot\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ mS3BootScriptTableSmmPtr = S3TableSmmPtr;\r
+\r
//\r
- // Then register event after lock\r
+ // Register SmmReadyToLock notification.\r
//\r
- Registration = NULL;\r
- Status = Smst->SmmRegisterProtocolNotify (\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
&gEfiSmmReadyToLockProtocolGuid,\r
S3BootScriptSmmEventCallBack,\r
- &Registration\r
+ &mRegistrationSmmReadyToLock\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
return RETURN_SUCCESS;\r
}\r
+\r
+/**\r
+ Library Destructor to free the resources allocated by\r
+ S3BootScriptLibInitialize() and unregister callbacks.\r
+\r
+ NOTICE: The destructor doesn't support unloading as a separate action, and it\r
+ only supports unloading if the containing driver's entry point function fails.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+S3BootScriptLibDeinitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG ((EFI_D_INFO, "%a() in %a module\n", __FUNCTION__, gEfiCallerBaseName));\r
+\r
+ if (mEventDxeSmmReadyToLock != NULL) {\r
+ //\r
+ // Close the DxeSmmReadyToLock event.\r
+ //\r
+ Status = gBS->CloseEvent (mEventDxeSmmReadyToLock);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (mSmst != NULL) {\r
+ if (mRegistrationSmmExitBootServices != NULL) {\r
+ //\r
+ // Unregister SmmExitBootServices notification.\r
+ //\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
+ &gEdkiiSmmExitBootServicesProtocolGuid,\r
+ NULL,\r
+ &mRegistrationSmmExitBootServices\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ if (mRegistrationSmmLegacyBoot != NULL) {\r
+ //\r
+ // Unregister SmmLegacyBoot notification.\r
+ //\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
+ &gEdkiiSmmLegacyBootProtocolGuid,\r
+ NULL,\r
+ &mRegistrationSmmLegacyBoot\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ if (mRegistrationSmmReadyToLock != NULL) {\r
+ //\r
+ // Unregister SmmReadyToLock notification.\r
+ //\r
+ Status = mSmst->SmmRegisterProtocolNotify (\r
+ &gEfiSmmReadyToLockProtocolGuid,\r
+ NULL,\r
+ &mRegistrationSmmReadyToLock\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free the resources allocated and set PCDs to 0.\r
+ //\r
+ if (mS3BootScriptTableAllocated) {\r
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)));\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ if (mS3BootScriptTableSmmAllocated) {\r
+ Status = mSmst->SmmFreePool (mS3BootScriptTableSmmPtr);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
/**\r
To get the start address from which a new boot time s3 boot script entry will write into.\r
If the table is not exist, the functio will first allocate a buffer for the table\r
\r
S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);\r
if (S3TableBase == 0) {\r
+ //\r
// The table is not exist. This is the first to add entry. \r
- // Allocate ACPI script table space under 4G memory. We need it to save\r
- // some settings done by CSM, which runs after normal script table closed\r
+ // Allocate ACPI script table space under 4G memory.\r
//\r
S3TableBase = 0xffffffff;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
+ EfiReservedMemoryType,\r
2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),\r
(EFI_PHYSICAL_ADDRESS*)&S3TableBase\r
);\r
ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;\r
ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;\r
ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
+ ScriptTableInfo->Version = BOOT_SCRIPT_TABLE_VERSION;\r
ScriptTableInfo->TableLength = 0; // will be calculate at CloseTable\r
mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;\r
}\r
\r
// Here we do not count the reserved memory for runtime script table.\r
- PageNumber = (UINT16)(mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); \r
+ PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));\r
TableLength = mS3BootScriptTablePtr->TableLength;\r
- if ((UINT32)(PageNumber * EFI_PAGE_SIZE) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {\r
+ if ((UINTN) EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (UINTN) (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {\r
// \r
// The buffer is too small to hold the table, Reallocate the buffer\r
//\r
NewS3TableBase = 0xffffffff;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
+ EfiReservedMemoryType,\r
2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),\r
(EFI_PHYSICAL_ADDRESS*)&NewS3TableBase\r
);\r
return NewEntryPtr; \r
}\r
/**\r
- To get the start address from which a new runtime s3 boot script entry will write into.\r
+ To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into.\r
In this case, it should be ensured that there is enough buffer to hold the entry.\r
\r
@param EntryLength the new entry length.\r
\r
- @retval the address from which the a new s3 runtime script entry will write into\r
+ @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into\r
**/\r
UINT8*\r
S3BootScriptGetRuntimeEntryAddAddress (\r
//\r
// Check if the memory range reserved for S3 Boot Script table is large enough to hold the node. \r
//\r
- if (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE) <= EFI_PAGES_TO_SIZE((UINT32)(mS3BootScriptTablePtr->TableMemoryPageNumber))) {\r
+ if ((UINTN) (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= (UINTN) EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) {\r
NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; \r
mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;\r
//\r
}\r
return (UINT8*)NewEntryPtr; \r
}\r
+\r
+/**\r
+ This function is to restore boot time boot script data from LockBox.\r
+\r
+**/\r
+VOID\r
+RestoreBootTimeDataFromLockBox (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN LockBoxLength;\r
+\r
+ //\r
+ // Restore boot time boot script data from LockBox.\r
+ //\r
+ LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength;\r
+ Status = RestoreLockBox (\r
+ &mBootScriptDataBootTimeGuid,\r
+ (VOID *) mS3BootScriptTablePtr->TableBase,\r
+ &LockBoxLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Update the data to BootScriptData LockBox.\r
+ //\r
+ Status = UpdateLockBox (\r
+ &mBootScriptDataGuid,\r
+ 0,\r
+ (VOID *) mS3BootScriptTablePtr->TableBase,\r
+ LockBoxLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Update TableLength.\r
+ //\r
+ mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
+}\r
+\r
/**\r
To get the start address from which a new s3 boot script entry will write into.\r
\r
@param EntryLength the new entry length.\r
\r
- @retval the address from which the a new s3 runtime script entry will write into \r
+ @retval the address from which the a new s3 boot script entry will write into \r
**/ \r
UINT8* \r
S3BootScriptGetEntryAddAddress (\r
)\r
{\r
UINT8* NewEntryPtr;\r
- EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;\r
- EFI_STATUS Status;\r
\r
- if (mS3BootScriptTablePtr->AtRuntime) {\r
+ if (mS3BootScriptTablePtr->SmmLocked) {\r
//\r
- // We need check InSmm when AtRuntime, because after SmmReadyToLock, only SMM driver is allowed to write boot script.\r
+ // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script.\r
//\r
if (!mS3BootScriptTablePtr->InSmm) {\r
//\r
- // Add DEBUG ERROR, so that we can find it at boot time.\r
- // Do not use ASSERT, because we may have test invoke this interface.\r
+ // Add DEBUG ERROR, so that we can find it after SmmReadyToLock.\r
+ // Do not use ASSERT, because we may have test to invoke this interface.\r
//\r
- DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script after ReadyToLock!!!\n"));\r
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n"));\r
return NULL;\r
}\r
\r
- //\r
- // NOTE: OS will restore ACPINvs data. After S3, the table length in mS3BootScriptTable (SMM) is different with\r
- // table length in BootScriptTable header (ACPINvs).\r
- // So here we need sync them. We choose ACPINvs table length, because we want to override the boot script saved\r
- // in SMM every time.\r
- //\r
- ASSERT (mS3BootScriptTablePtr == &mS3BootScriptTable);\r
- CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));\r
- if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) {\r
- //\r
- // Restore it to use original value\r
- //\r
- RestoreLockBox (&mBootScriptDataGuid, NULL, NULL);\r
+ if (mS3BootScriptTablePtr->BackFromS3) {\r
//\r
- // Copy it again to get original value\r
- // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length.\r
+ // Back from S3, restore boot time boot script data from LockBox\r
+ // and set BackFromS3 flag back to FALSE.\r
//\r
- mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE));\r
+ RestoreBootTimeDataFromLockBox ();\r
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;\r
}\r
\r
NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);\r
- //\r
- // Now the length field is updated, need sync to lockbox.\r
- // So in S3 resume, the data can be restored correctly.\r
- //\r
- CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));\r
- Status = UpdateLockBox (\r
- &mBootScriptDataGuid,\r
- OFFSET_OF(EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),\r
- &TableHeader.TableLength,\r
- sizeof(TableHeader.TableLength)\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- } else { \r
+ } else {\r
NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);\r
} \r
return NewEntryPtr;\r
\r
/**\r
Sync BootScript LockBox data.\r
+\r
+ @param Script The address from where the boot script has been added or updated.\r
+\r
**/\r
VOID\r
SyncBootScript (\r
- VOID\r
+ IN UINT8 *Script\r
)\r
{\r
EFI_STATUS Status;\r
+ UINT32 ScriptOffset;\r
+ UINT32 TotalScriptLength;\r
\r
- if (!mS3BootScriptTablePtr->AtRuntime || !mS3BootScriptTablePtr->InSmm) {\r
+ if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) {\r
+ //\r
+ // If it is not after SmmReadyToLock in SMM,\r
+ // just return.\r
+ //\r
return ;\r
}\r
+\r
+ ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase);\r
+\r
+ TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
+\r
//\r
- // Update Terminate\r
+ // Update BootScriptData\r
// So in S3 resume, the data can be restored correctly.\r
//\r
Status = UpdateLockBox (\r
&mBootScriptDataGuid,\r
- mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE),\r
- (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)),\r
- sizeof(EFI_BOOT_SCRIPT_TERMINATE)\r
+ ScriptOffset,\r
+ (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),\r
+ TotalScriptLength - ScriptOffset\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Now the length field is updated, need sync to lockbox.\r
+ // So at S3 resume, the data can be restored correctly.\r
+ //\r
+ Status = UpdateLockBox (\r
+ &mBootScriptDataGuid,\r
+ OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),\r
+ &TotalScriptLength,\r
+ sizeof (TotalScriptLength)\r
);\r
ASSERT_EFI_ERROR (Status);\r
}\r
for Framework Spec compatibility.\r
\r
If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out \r
- how to get the script to run on an S3 resume because the boot script maintained by the lib will be \r
+ how to get the script to run at S3 resume because the boot script maintained by the lib will be \r
destroyed.\r
\r
- @return the base address of the new copy of the boot script tble. \r
+ @return the base address of the new copy of the boot script table. \r
@note this function could only called in boot time phase\r
\r
**/\r
CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
+ @note A known Limitations in the implementation which is 64bits operations are not supported.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
UINT8 WidthInByte;\r
EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;\r
\r
+ if (Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN__SUCCESS Opcode is added.\r
+ @note A known Limitations in the implementation which is 64bits operations are not supported.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
UINT8 WidthInByte;\r
EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;\r
\r
+ if (Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));\r
\r
WidthInByte\r
);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
/**\r
- Adds a record for a PCI configuration space modify operation into a specified boot script table.\r
+ Adds a record for a PCI configuration 2 space write operation into a specified boot script table.\r
\r
@param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
@param Segment The PCI segment number for Address.\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
UINT8 *Script;\r
UINT8 WidthInByte;\r
EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2;\r
- \r
+\r
+ if (Segment != 0 ||\r
+ Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));\r
CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
/**\r
- Adds a record for a PCI configuration space modify operation into a specified boot script table.\r
+ Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.\r
\r
@param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
@param Segment The PCI segment number for Address.\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
UINT8 *Script;\r
UINT8 WidthInByte;\r
EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2;\r
+\r
+ if (Segment != 0 ||\r
+ Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));\r
WidthInByte\r
);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
+\r
+/**\r
+ Checks the parameter of S3BootScriptSaveSmbusExecute().\r
+\r
+ This function checks the input parameters of SmbusExecute(). If the input parameters are valid\r
+ for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain\r
+ error code based on the input SMBus bus protocol.\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, \r
+ and PEC.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus\r
+ protocol. \r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckParameters (\r
+ IN UINTN SmBusAddress,\r
+ IN EFI_SMBUS_OPERATION Operation,\r
+ IN OUT UINTN *Length,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN RequiredLen;\r
+ EFI_SMBUS_DEVICE_COMMAND Command;\r
+ BOOLEAN PecCheck;\r
+ \r
+ Command = SMBUS_LIB_COMMAND (SmBusAddress);\r
+ PecCheck = SMBUS_LIB_PEC (SmBusAddress);\r
+ //\r
+ // Set default value to be 2:\r
+ // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall. \r
+ //\r
+ RequiredLen = 2;\r
+ Status = EFI_SUCCESS;\r
+ switch (Operation) {\r
+ case EfiSmbusQuickRead:\r
+ case EfiSmbusQuickWrite:\r
+ if (PecCheck || Command != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ break;\r
+ case EfiSmbusReceiveByte:\r
+ case EfiSmbusSendByte:\r
+ if (Command != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Cascade to check length parameter.\r
+ //\r
+ case EfiSmbusReadByte:\r
+ case EfiSmbusWriteByte:\r
+ RequiredLen = 1;\r
+ //\r
+ // Cascade to check length parameter.\r
+ //\r
+ case EfiSmbusReadWord:\r
+ case EfiSmbusWriteWord:\r
+ case EfiSmbusProcessCall:\r
+ if (Buffer == NULL || Length == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (*Length < RequiredLen) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *Length = RequiredLen;\r
+ break;\r
+ case EfiSmbusReadBlock:\r
+ case EfiSmbusWriteBlock:\r
+ case EfiSmbusBWBRProcessCall:\r
+ if ((Buffer == NULL) || \r
+ (Length == NULL) || \r
+ (*Length < MIN_SMBUS_BLOCK_LEN) ||\r
+ (*Length > MAX_SMBUS_BLOCK_LEN)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return Status;\r
+}\r
+\r
/**\r
Adds a record for an SMBus command execution into a specified boot script table.\r
\r
IN VOID *Buffer\r
)\r
{\r
+ EFI_STATUS Status;\r
+ UINTN BufferLength;\r
UINT8 DataSize;\r
UINT8 *Script;\r
EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;\r
\r
- DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + (*Length));\r
+ if (Length == NULL) {\r
+ BufferLength = 0;\r
+ } else {\r
+ BufferLength = *Length;\r
+ }\r
+\r
+ Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);\r
\r
Script = S3BootScriptGetEntryAddAddress (DataSize);\r
if (Script == NULL) {\r
ScriptSmbusExecute.Length = DataSize;\r
ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;\r
ScriptSmbusExecute.Operation = Operation;\r
- ScriptSmbusExecute.DataSize = (UINT32) *Length;\r
+ ScriptSmbusExecute.DataSize = (UINT32) BufferLength;\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));\r
CopyMem (\r
(VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),\r
Buffer,\r
- (*Length)\r
+ BufferLength\r
);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
/**\r
- Adds a record for an execution stall on the processor into a specified boot script table.\r
+ Adds a record for dispatching specified arbitrary code into a specified boot script table.\r
\r
@param EntryPoint Entry point of the code to be dispatched.\r
@param Context Argument to be passed into the EntryPoint of the code to be dispatched.\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
\r
/**\r
Adds a record for memory reads of the memory location and continues when the exit criteria is\r
satisfied or after a defined duration.\r
- \r
+\r
+ Please aware, below interface is different with PI specification, Vol 5:\r
+ EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.\r
+ "Duration" below is microseconds, while "Delay" in PI specification means\r
+ the number of 100ns units to poll.\r
+\r
@param Width The width of the memory operations.\r
@param Address The base address of the memory operations.\r
@param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);\r
CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL)); \r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
@param InformationLength Length of the data in bytes\r
@param Information Information to be logged in the boot scrpit\r
\r
- @retval RETURN_UNSUPPORTED If entering runtime, this method will not support.\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
\r
IN VOID *Information\r
)\r
{\r
- RETURN_STATUS Status;\r
UINT8 Length;\r
UINT8 *Script;\r
- VOID *Buffer;\r
EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
\r
- if (mS3BootScriptTablePtr->AtRuntime) {\r
- return RETURN_UNSUPPORTED;\r
- }\r
- Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
- \r
- //\r
- // Use BootServicesData to hold the data, just in case caller free it.\r
- // It will be copied into ACPINvs later.\r
- //\r
- Status = gBS->AllocatePool (\r
- EfiBootServicesData,\r
- InformationLength,\r
- &Buffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return RETURN_OUT_OF_RESOURCES;\r
- }\r
- \r
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
+\r
Script = S3BootScriptGetEntryAddAddress (Length);\r
if (Script == NULL) {\r
return RETURN_OUT_OF_RESOURCES;\r
\r
ScriptInformation.InformationLength = InformationLength; \r
\r
- CopyMem ((VOID *)(UINTN)Buffer, Information,(UINTN) InformationLength); \r
- ScriptInformation.Information = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
- \r
- CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION)); \r
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);\r
+\r
+ SyncBootScript (Script);\r
+\r
return RETURN_SUCCESS;\r
\r
}\r
\r
CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH)); \r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
+ @note A known Limitations in the implementation which is 64bits operations are not supported.\r
\r
**/\r
RETURN_STATUS\r
UINT8 Length;\r
EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;\r
\r
+ if (Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));\r
\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
@retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
@retval RETURN_SUCCESS Opcode is added.\r
- @note A known Limitations in the implementation: When interpreting the opcode EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE\r
- EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE and EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE, the 'Segment' parameter is assumed as \r
- Zero, or else, assert.\r
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.\r
+\r
**/\r
RETURN_STATUS\r
EFIAPI\r
UINT8 *Script;\r
UINT8 Length;\r
EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll;\r
- \r
+\r
+ if (Segment != 0 ||\r
+ Width == S3BootScriptWidthUint64 ||\r
+ Width == S3BootScriptWidthFifoUint64 ||\r
+ Width == S3BootScriptWidthFillUint64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));\r
\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);\r
CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);\r
\r
- SyncBootScript ();\r
+ SyncBootScript (Script);\r
\r
return RETURN_SUCCESS;\r
}\r
\r
ValidatePosition = FALSE;\r
TempPosition = (Position == NULL) ? NULL:(*Position);\r
- Script = mS3BootScriptTablePtr->TableBase;\r
- if (Script == 0) { \r
- return EFI_OUT_OF_RESOURCES;\r
+\r
+ //\r
+ // Check that the script is initialized and synced without adding an entry to the script.\r
+ //\r
+ Script = S3BootScriptGetEntryAddAddress (0);\r
+ if (Script == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
}\r
+ Script = mS3BootScriptTablePtr->TableBase;\r
+\r
StartAddress = (UINTN) Script;\r
TableLength = mS3BootScriptTablePtr->TableLength;\r
Script = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);\r
//\r
// Copy the node to Boot script table\r
//\r
- CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length); \r
+ CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);\r
+\r
+ SyncBootScript (Script);\r
+\r
//\r
// return out the Position\r
//\r
{\r
UINT8 Length;\r
UINT8 *Script;\r
- VOID *Buffer;\r
EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
\r
Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
if (Script == NULL) {\r
return RETURN_OUT_OF_RESOURCES;\r
}\r
- Buffer = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION);\r
//\r
// Build script data\r
//\r
\r
ScriptInformation.InformationLength = InformationLength; \r
\r
- AsciiStrnCpy (Buffer, Information,(UINTN) InformationLength); \r
- ScriptInformation.Information = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
- \r
- CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION)); \r
- \r
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);\r
+\r
+ SyncBootScript (Script);\r
+\r
return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);\r
\r
}\r
}\r
\r
//\r
- // Check that the script is initialized without adding an entry to the script.\r
- // The code must search for the label first befor it knows if a new entry needs\r
+ // Check that the script is initialized and synced without adding an entry to the script.\r
+ // The code must search for the label first before it knows if a new entry needs\r
// to be added.\r
//\r
Script = S3BootScriptGetEntryAddAddress (0);\r
UINT8* Script;\r
UINT32 TableLength; \r
\r
- Script = mS3BootScriptTablePtr->TableBase;\r
- if (Script == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
if (RelativePosition == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- TableLength = ((EFI_BOOT_SCRIPT_TABLE_HEADER*)Script)->TableLength;\r
+\r
//\r
- // If in boot time, TableLength does not include the termination node. so add it up \r
+ // Check that the script is initialized and synced without adding an entry to the script.\r
//\r
- if (!mS3BootScriptTablePtr->AtRuntime) {\r
- TableLength += sizeof(EFI_BOOT_SCRIPT_TERMINATE);\r
+ Script = S3BootScriptGetEntryAddAddress (0);\r
+ if (Script == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
}\r
+ Script = mS3BootScriptTablePtr->TableBase;\r
+\r
+ //\r
+ // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up\r
+ //\r
+ TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
if (Position1 < Script || Position1 > Script+TableLength) {\r
return EFI_INVALID_PARAMETER;\r
}\r