X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FPiDxeS3BootScriptLib%2FBootScriptSave.c;h=0ff73211acc44a7de6aba29bc45485bca3a1b761;hp=afb5ed1bb345f80d472b393297b62faa5765be65;hb=d6f38e374ece00f1f8176007c9d3e8eff1f2308f;hpb=3aa764ed7477d45ee78c7080c9f7624e62d10346 diff --git a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c index afb5ed1bb3..0ff73211ac 100644 --- a/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c +++ b/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c @@ -1,7 +1,7 @@ /** @file - Save the S3 data to S3 boot script. - - Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+ Save the S3 data to S3 boot script. + + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -19,46 +19,124 @@ Data structure usage: - +------------------------------+<-- PcdS3BootScriptTablePrivateDataPtr + +------------------------------+<------- 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 |--|-- - | AtRuntime | | | - | InSmm | | | - +------------------------------+ | | - | | - +------------------------------+<-- | - | EFI_BOOT_SCRIPT_TABLE_HEADER | | - | TableLength |----|-- - +------------------------------+ | | - | ...... | | | - +------------------------------+<---- | - | EFI_BOOT_SCRIPT_TERMINATE | | - +------------------------------+<------ + | TableBase | + | TableLength | + | TableMemoryPageNumber | + | AtRuntime | + | InSmm | + | BootTimeScriptLength | + | SmmLocked | + | BackFromS3 = TRUE | + +------------------------------+ **/ SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr; -EFI_EVENT mEnterRuntimeEvent; + // -// Allocate SMM copy because we can not use mS3BootScriptTablePtr when we AtRuntime in InSmm. +// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm. // SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr; -UINTN mLockBoxLength; EFI_GUID mBootScriptDataGuid = { 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 } }; -EFI_GUID mBootScriptHeaderDataGuid = { +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 *mSmst = NULL; + /** 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 tble. + @return the base address of the boot script table. **/ UINT8* S3BootScriptInternalCloseTable ( @@ -93,18 +171,15 @@ S3BootScriptInternalCloseTable ( return S3TableBase; // // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to - // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE). Because - // maybe in runtime, we still need add entries into the table, and the runtime entry should be - // added start before this TERMINATE node. + // 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. - 1. BootSriptPrivate data, BootScript data - Image and DispatchContext are handled by platform. - 2. BootScriptExecutor, BootScriptExecutor context - - ACPI variable - (PI version) sould be handled by SMM driver. S3 Page table is handled here. - - ACPI variable - framework version is already handled by Framework CPU driver. + **/ VOID SaveBootScriptDataToLockBox ( @@ -114,13 +189,13 @@ SaveBootScriptDataToLockBox ( EFI_STATUS Status; // - // mS3BootScriptTablePtr->TableLength does not include EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime. - // Save all info here, just in case that no one will add boot script entry in SMM. + // Save whole memory copy into LockBox. + // It will be used to restore data at S3 resume. // Status = SaveLockBox ( &mBootScriptDataGuid, (VOID *)mS3BootScriptTablePtr->TableBase, - mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) + EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber) ); ASSERT_EFI_ERROR (Status); @@ -132,22 +207,22 @@ SaveBootScriptDataToLockBox ( // Do not update other field because they will NOT be used in S3. // Status = SaveLockBox ( - &mBootScriptHeaderDataGuid, + &mBootScriptTableBaseGuid, (VOID *)&mS3BootScriptTablePtr->TableBase, sizeof(mS3BootScriptTablePtr->TableBase) ); ASSERT_EFI_ERROR (Status); - Status = SetLockBoxAttributes (&mBootScriptHeaderDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + 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 - run time phase. + SmmLocked phase. @param Event Pointer to this event - @param Context Event hanlder private data + @param Context Event handler private data **/ VOID EFIAPI @@ -173,28 +248,29 @@ S3BootScriptEventCallBack ( } // - // Here we should tell the library that we are enter into runtime phase. and - // the memory page number occupied by the table should not grow anymore. + // 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->AtRuntime) { + if (!mS3BootScriptTablePtr->SmmLocked) { // - // In boot time, we need not write the terminate node when adding a node to boot scipt table - // or else, that will impact the performance. However, in runtime, we should append terminate - // node on every add to boot script table + // 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->AtRuntime = TRUE; + 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 - run time phase and set InSmm flag. - + 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 @@ -217,7 +293,7 @@ S3BootScriptSmmEventCallBack ( } // - // Last chance to call-out, just make sure AtRuntime is set + // Last chance to call-out, just make sure SmmLocked is set. // S3BootScriptEventCallBack (NULL, NULL); @@ -226,22 +302,117 @@ S3BootScriptSmmEventCallBack ( // 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 ACPINvs copy, because it is not safe. + // 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); + // - // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM. - // InSmm will only be checked if AtRuntime is TRUE. + // Save BootScriptDataBootTime + // It will be used to restore data after back from S3. // - mS3BootScriptTablePtr->InSmm = TRUE; + 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; // - // Record LockBoxLength + // Save boot script SMM private data with BackFromS3 = TRUE. // - mLockBoxLength = mS3BootScriptTableSmmPtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE); + 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; } @@ -254,8 +425,8 @@ S3BootScriptSmmEventCallBack ( @param ImageHandle The firmware allocated handle for the EFI image. @param SystemTable A pointer to the EFI System Table. - @retval RETURN_SUCCESS Allocate the global memory space to store S3 boot script table private data - @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated. + @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS. + **/ RETURN_STATUS EFIAPI @@ -270,7 +441,6 @@ S3BootScriptLibInitialize ( VOID *Registration; EFI_SMM_BASE2_PROTOCOL *SmmBase2; BOOLEAN InSmm; - EFI_SMM_SYSTEM_TABLE2 *Smst; EFI_PHYSICAL_ADDRESS Buffer; S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr); @@ -281,29 +451,29 @@ S3BootScriptLibInitialize ( Buffer = SIZE_4GB - 1; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)), &Buffer ); - if (EFI_ERROR (Status)) { - return RETURN_OUT_OF_RESOURCES; - } + ASSERT_EFI_ERROR (Status); + mS3BootScriptTableAllocated = TRUE; S3TablePtr = (VOID *) (UINTN) Buffer; - PcdSet64 (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr); - ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); + 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 runtime phase + // Create event to notify the library system enter the SmmLocked phase. // - mEnterRuntimeEvent = EfiCreateProtocolNotifyEvent ( - &gEfiDxeSmmReadyToLockProtocolGuid, - TPL_CALLBACK, - S3BootScriptEventCallBack, - NULL, - &Registration - ); - ASSERT (mEnterRuntimeEvent != NULL); - } + mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent ( + &gEfiDxeSmmReadyToLockProtocolGuid, + TPL_CALLBACK, + S3BootScriptEventCallBack, + NULL, + &Registration + ); + ASSERT (mEventDxeSmmReadyToLock != NULL); + } mS3BootScriptTablePtr = S3TablePtr; // @@ -323,7 +493,7 @@ S3BootScriptLibInitialize ( // // Good, we are in SMM // - Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst); + Status = SmmBase2->GetSmstLocation (SmmBase2, &mSmst); if (EFI_ERROR (Status)) { return RETURN_SUCCESS; } @@ -333,33 +503,137 @@ S3BootScriptLibInitialize ( // The Boot script private data in SMM is not be initialized. create it // if (S3TableSmmPtr == 0) { - Status = Smst->SmmAllocatePool ( + Status = mSmst->SmmAllocatePool ( EfiRuntimeServicesData, sizeof(SCRIPT_TABLE_PRIVATE_DATA), (VOID **) &S3TableSmmPtr ); - if (EFI_ERROR (Status)) { - return RETURN_OUT_OF_RESOURCES; - } + ASSERT_EFI_ERROR (Status); + mS3BootScriptTableSmmAllocated = TRUE; - PcdSet64 (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr); + Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr); + ASSERT_EFI_ERROR (Status); ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA)); + + // + // Register SmmExitBootServices and SmmLegacyBoot notification. + // + Status = mSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmExitBootServicesProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &mRegistrationSmmExitBootServices + ); + ASSERT_EFI_ERROR (Status); + + Status = mSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmLegacyBootProtocolGuid, + S3BootScriptSmmAtRuntimeCallBack, + &mRegistrationSmmLegacyBoot + ); + ASSERT_EFI_ERROR (Status); } mS3BootScriptTableSmmPtr = S3TableSmmPtr; // - // Then register event after lock + // Register SmmReadyToLock notification. // - Registration = NULL; - Status = Smst->SmmRegisterProtocolNotify ( + Status = mSmst->SmmRegisterProtocolNotify ( &gEfiSmmReadyToLockProtocolGuid, S3BootScriptSmmEventCallBack, - &Registration + &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; + + DEBUG ((EFI_D_INFO, "%a() in %a module\n", __FUNCTION__, gEfiCallerBaseName)); + + if (mEventDxeSmmReadyToLock != NULL) { + // + // Close the DxeSmmReadyToLock event. + // + Status = gBS->CloseEvent (mEventDxeSmmReadyToLock); + ASSERT_EFI_ERROR (Status); + } + + if (mSmst != NULL) { + if (mRegistrationSmmExitBootServices != NULL) { + // + // Unregister SmmExitBootServices notification. + // + Status = mSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmExitBootServicesProtocolGuid, + NULL, + &mRegistrationSmmExitBootServices + ); + ASSERT_EFI_ERROR (Status); + } + if (mRegistrationSmmLegacyBoot != NULL) { + // + // Unregister SmmLegacyBoot notification. + // + Status = mSmst->SmmRegisterProtocolNotify ( + &gEdkiiSmmLegacyBootProtocolGuid, + NULL, + &mRegistrationSmmLegacyBoot + ); + ASSERT_EFI_ERROR (Status); + } + if (mRegistrationSmmReadyToLock != NULL) { + // + // Unregister SmmReadyToLock notification. + // + Status = mSmst->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 ((mSmst != NULL) && mS3BootScriptTableSmmAllocated) { + Status = mSmst->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 @@ -385,14 +659,14 @@ S3BootScriptGetBootTimeEntryAddAddress ( S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase); if (S3TableBase == 0) { + // // The table is not exist. This is the first to add entry. - // Allocate ACPI script table space under 4G memory. We need it to save - // some settings done by CSM, which runs after normal script table closed + // Allocate ACPI script table space under 4G memory. // S3TableBase = 0xffffffff; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), (EFI_PHYSICAL_ADDRESS*)&S3TableBase ); @@ -407,6 +681,7 @@ S3BootScriptGetBootTimeEntryAddAddress ( 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; @@ -414,16 +689,16 @@ S3BootScriptGetBootTimeEntryAddAddress ( } // Here we do not count the reserved memory for runtime script table. - PageNumber = (UINT16)(mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); + PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber)); TableLength = mS3BootScriptTablePtr->TableLength; - if ((UINT32)(PageNumber * EFI_PAGE_SIZE) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) { + if ((UINTN) EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (UINTN) (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) { // // The buffer is too small to hold the table, Reallocate the buffer // NewS3TableBase = 0xffffffff; Status = gBS->AllocatePages ( AllocateMaxAddress, - EfiACPIMemoryNVS, + EfiReservedMemoryType, 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber), (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase ); @@ -459,12 +734,12 @@ S3BootScriptGetBootTimeEntryAddAddress ( return NewEntryPtr; } /** - To get the start address from which a new runtime s3 boot script entry will write into. + 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 script entry will write into + @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into **/ UINT8* S3BootScriptGetRuntimeEntryAddAddress ( @@ -477,7 +752,7 @@ S3BootScriptGetRuntimeEntryAddAddress ( // // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node. // - if (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE) <= EFI_PAGES_TO_SIZE((UINT32)(mS3BootScriptTablePtr->TableMemoryPageNumber))) { + if ((UINTN) (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= (UINTN) EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) { NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength; mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength; // @@ -487,12 +762,53 @@ S3BootScriptGetRuntimeEntryAddAddress ( } 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 runtime script entry will write into + @retval the address from which the a new s3 boot script entry will write into **/ UINT8* S3BootScriptGetEntryAddAddress ( @@ -500,56 +816,31 @@ S3BootScriptGetEntryAddAddress ( ) { UINT8* NewEntryPtr; - EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader; - EFI_STATUS Status; - if (mS3BootScriptTablePtr->AtRuntime) { + if (mS3BootScriptTablePtr->SmmLocked) { // - // We need check InSmm when AtRuntime, because after SmmReadyToLock, only SMM driver is allowed to write boot script. + // 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 at boot time. - // Do not use ASSERT, because we may have test invoke this interface. + // 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 ((EFI_D_ERROR, "FATAL ERROR: Set boot script after ReadyToLock!!!\n")); + DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n")); return NULL; } - // - // NOTE: OS will restore ACPINvs data. After S3, the table length in mS3BootScriptTableSmmPtr (SMM) is different with - // table length in BootScriptTable header (ACPINvs). - // So here we need sync them. We choose ACPINvs table length, because we want to override the boot script saved - // in SMM every time. - // - ASSERT (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr); - CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); - if (mS3BootScriptTablePtr->TableLength + sizeof(EFI_BOOT_SCRIPT_TERMINATE) != TableHeader.TableLength) { - // - // Restore it to use original value + if (mS3BootScriptTablePtr->BackFromS3) { // - RestoreLockBox (&mBootScriptDataGuid, NULL, NULL); + // Back from S3, restore boot time boot script data from LockBox + // and set BackFromS3 flag back to FALSE. // - // Copy it again to get original value - // NOTE: We should NOT use TableHeader.TableLength, because it is already updated to be whole length. - // - mS3BootScriptTablePtr->TableLength = (UINT32)(mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)); + RestoreBootTimeDataFromLockBox (); + mS3BootScriptTablePtr->BackFromS3 = FALSE; } NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength); - // - // Now the length field is updated, need sync to lockbox. - // So in S3 resume, the data can be restored correctly. - // - CopyMem ((VOID*)&TableHeader, (VOID*)mS3BootScriptTablePtr->TableBase, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER)); - Status = UpdateLockBox ( - &mBootScriptDataGuid, - OFFSET_OF(EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength), - &TableHeader.TableLength, - sizeof(TableHeader.TableLength) - ); - ASSERT_EFI_ERROR (Status); - } else { + } else { NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength); } return NewEntryPtr; @@ -558,26 +849,52 @@ S3BootScriptGetEntryAddAddress ( /** Sync BootScript LockBox data. + + @param Script The address from where the boot script has been added or updated. + **/ VOID SyncBootScript ( - VOID + IN UINT8 *Script ) { EFI_STATUS Status; + UINT32 ScriptOffset; + UINT32 TotalScriptLength; - if (!mS3BootScriptTablePtr->AtRuntime || !mS3BootScriptTablePtr->InSmm) { + 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 Terminate + // Update BootScriptData // So in S3 resume, the data can be restored correctly. // Status = UpdateLockBox ( &mBootScriptDataGuid, - mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE), - (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + mLockBoxLength - sizeof(EFI_BOOT_SCRIPT_TERMINATE)), - sizeof(EFI_BOOT_SCRIPT_TERMINATE) + 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); } @@ -600,10 +917,10 @@ SyncBootScript ( for Framework Spec compatibility. If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out - how to get the script to run on an S3 resume because the boot script maintained by the lib will be + 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 tble. + @return the base address of the new copy of the boot script table. @note this function could only called in boot time phase **/ @@ -698,7 +1015,7 @@ S3BootScriptSaveIoWrite ( CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE)); CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -747,7 +1064,7 @@ S3BootScriptSaveIoReadWrite ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -795,7 +1112,7 @@ S3BootScriptSaveMemWrite ( CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE)); CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -843,7 +1160,7 @@ S3BootScriptSaveMemReadWrite ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -857,6 +1174,8 @@ S3BootScriptSaveMemReadWrite ( @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 @@ -872,6 +1191,12 @@ S3BootScriptSavePciCfgWrite ( UINT8 WidthInByte; EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite; + if (Width == S3BootScriptWidthUint64 || + Width == S3BootScriptWidthFifoUint64 || + Width == S3BootScriptWidthFillUint64) { + return EFI_INVALID_PARAMETER; + } + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count)); @@ -891,7 +1216,7 @@ S3BootScriptSavePciCfgWrite ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -905,6 +1230,8 @@ S3BootScriptSavePciCfgWrite ( @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 @@ -920,6 +1247,12 @@ S3BootScriptSavePciCfgReadWrite ( 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)); @@ -943,12 +1276,12 @@ S3BootScriptSavePciCfgReadWrite ( WidthInByte ); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } /** - Adds a record for a PCI configuration space modify operation into a specified boot script table. + 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. @@ -958,6 +1291,8 @@ S3BootScriptSavePciCfgReadWrite ( @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. @retval RETURN_SUCCESS Opcode is added. + @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported. + **/ RETURN_STATUS EFIAPI @@ -973,7 +1308,14 @@ S3BootScriptSavePciCfg2Write ( UINT8 *Script; UINT8 WidthInByte; EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2; - + + if (Segment != 0 || + Width == S3BootScriptWidthUint64 || + Width == S3BootScriptWidthFifoUint64 || + Width == S3BootScriptWidthFillUint64) { + return EFI_INVALID_PARAMETER; + } + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count)); @@ -994,12 +1336,12 @@ S3BootScriptSavePciCfg2Write ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } /** - Adds a record for a PCI configuration space modify operation into a specified boot script table. + 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. @@ -1009,6 +1351,8 @@ S3BootScriptSavePciCfg2Write ( @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation. @retval RETURN_SUCCESS Opcode is added. + @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported. + **/ RETURN_STATUS EFIAPI @@ -1024,6 +1368,13 @@ S3BootScriptSavePciCfg2ReadWrite ( UINT8 *Script; UINT8 WidthInByte; EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2; + + if (Segment != 0 || + Width == S3BootScriptWidthUint64 || + Width == S3BootScriptWidthFifoUint64 || + Width == S3BootScriptWidthFillUint64) { + return EFI_INVALID_PARAMETER; + } WidthInByte = (UINT8) (0x01 << (Width & 0x03)); Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2)); @@ -1049,10 +1400,111 @@ S3BootScriptSavePciCfg2ReadWrite ( WidthInByte ); - SyncBootScript (); + 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. @@ -1074,11 +1526,24 @@ S3BootScriptSaveSmbusExecute ( IN VOID *Buffer ) { + EFI_STATUS Status; + UINTN BufferLength; UINT8 DataSize; UINT8 *Script; EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute; - DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + (*Length)); + if (Length == NULL) { + BufferLength = 0; + } else { + BufferLength = *Length; + } + + Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength); Script = S3BootScriptGetEntryAddAddress (DataSize); if (Script == NULL) { @@ -1091,16 +1556,16 @@ S3BootScriptSaveSmbusExecute ( ScriptSmbusExecute.Length = DataSize; ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress; ScriptSmbusExecute.Operation = Operation; - ScriptSmbusExecute.DataSize = (UINT32) *Length; + 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, - (*Length) + BufferLength ); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -1137,12 +1602,12 @@ S3BootScriptSaveStall ( CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL)); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } /** - Adds a record for an execution stall on the processor into a specified boot script table. + 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. @@ -1176,7 +1641,7 @@ S3BootScriptSaveDispatch2 ( CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2)); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; @@ -1184,7 +1649,12 @@ S3BootScriptSaveDispatch2 ( /** 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. @@ -1234,7 +1704,7 @@ S3BootScriptSaveMemPoll ( CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte); CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL)); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -1278,7 +1748,7 @@ S3BootScriptSaveInformation ( CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION)); CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; @@ -1337,7 +1807,7 @@ S3BootScriptSaveDispatch ( CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH)); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; @@ -1394,7 +1864,7 @@ S3BootScriptSaveIoPoll ( CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte); CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte); - SyncBootScript (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -1413,6 +1883,7 @@ S3BootScriptSaveIoPoll ( @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 @@ -1430,6 +1901,12 @@ S3BootScriptSavePciPoll ( 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)); @@ -1450,7 +1927,7 @@ S3BootScriptSavePciPoll ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -1469,9 +1946,8 @@ S3BootScriptSavePciPoll ( @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: When interpreting the opcode EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE - EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE and EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE, the 'Segment' parameter is assumed as - Zero, or else, assert. + @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported. + **/ RETURN_STATUS EFIAPI @@ -1488,7 +1964,14 @@ S3BootScriptSavePci2Poll ( UINT8 *Script; UINT8 Length; EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll; - + + if (Segment != 0 || + Width == S3BootScriptWidthUint64 || + Width == S3BootScriptWidthFifoUint64 || + Width == S3BootScriptWidthFillUint64) { + return EFI_INVALID_PARAMETER; + } + WidthInByte = (UINT8) (0x01 << (Width & 0x03)); Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2)); @@ -1510,7 +1993,7 @@ S3BootScriptSavePci2Poll ( 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 (); + SyncBootScript (Script); return RETURN_SUCCESS; } @@ -1612,10 +2095,16 @@ S3BootScriptMoveLastOpcode ( ValidatePosition = FALSE; TempPosition = (Position == NULL) ? NULL:(*Position); - Script = mS3BootScriptTablePtr->TableBase; - if (Script == 0) { - return EFI_OUT_OF_RESOURCES; + + // + // 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); @@ -1658,7 +2147,10 @@ S3BootScriptMoveLastOpcode ( // // Copy the node to Boot script table // - CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length); + CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length); + + SyncBootScript (Script); + // // return out the Position // @@ -1716,6 +2208,8 @@ S3BootScriptLabelInternal ( 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); } @@ -1770,8 +2264,8 @@ S3BootScriptLabel ( } // - // Check that the script is initialized without adding an entry to the script. - // The code must search for the label first befor it knows if a new entry needs + // 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); @@ -1834,13 +2328,19 @@ S3BootScriptCompare ( UINT8* Script; UINT32 TableLength; - Script = mS3BootScriptTablePtr->TableBase; - if (Script == NULL) { - return EFI_OUT_OF_RESOURCES; - } 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 //