From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c | 36 ++ .../Universal/CapsuleRuntimeDxe/CapsuleCache.c | 57 +++ .../Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c | 32 ++ .../Universal/CapsuleRuntimeDxe/CapsuleReset.c | 29 ++ .../CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf | 108 ++++++ .../CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni | 17 + .../CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni | 14 + .../Universal/CapsuleRuntimeDxe/CapsuleService.c | 397 +++++++++++++++++++++ .../Universal/CapsuleRuntimeDxe/CapsuleService.h | 70 ++++ .../CapsuleRuntimeDxe/SaveLongModeContext.c | 21 ++ .../CapsuleRuntimeDxe/X64/SaveLongModeContext.c | 209 +++++++++++ 11 files changed, 990 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c (limited to 'roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe') diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c new file mode 100644 index 000000000..e05f14de6 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c @@ -0,0 +1,36 @@ +/** @file + ARM implementation of architecture specific routines related to + PersistAcrossReset capsules + + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleService.h" + +/** + Whether the platform supports capsules that persist across reset. Note that + some platforms only support such capsules at boot time. + + @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule() + at this time + FALSE otherwise +**/ +BOOLEAN +IsPersistAcrossResetCapsuleSupported ( + VOID + ) +{ + // + // ARM requires the capsule payload to be cleaned to the point of coherency + // (PoC), but only permits doing so using cache maintenance instructions that + // operate on virtual addresses. Since at runtime, we don't know the virtual + // addresses of the data structures that make up the scatter/gather list, we + // cannot perform the maintenance, and all we can do is give up. + // + return FeaturePcdGet (PcdSupportUpdateCapsuleReset) && !EfiAtRuntime (); +} + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c new file mode 100644 index 000000000..3c96851e9 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c @@ -0,0 +1,57 @@ +/** @file + Flush the cache is required for most architectures while do capsule + update. It is not support at Runtime. + + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleService.h" + +#include + +/** + Writes Back a range of data cache lines covering a set of capsules in memory. + + Writes Back the data cache lines specified by ScatterGatherList. + + @param ScatterGatherList Physical address of the data structure that + describes a set of capsules in memory + +**/ +VOID +CapsuleCacheWriteBack ( + IN EFI_PHYSICAL_ADDRESS ScatterGatherList + ) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc; + + if (!EfiAtRuntime ()) { + Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)ScatterGatherList; + do { + WriteBackDataCacheRange ( + (VOID *)(UINTN)Desc, + (UINTN)sizeof (*Desc) + ); + + if (Desc->Length > 0) { + WriteBackDataCacheRange ( + (VOID *)(UINTN)Desc->Union.DataBlock, + (UINTN)Desc->Length + ); + Desc++; + } else if (Desc->Union.ContinuationPointer > 0) { + Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer; + } + } while (Desc->Length > 0 || Desc->Union.ContinuationPointer > 0); + + WriteBackDataCacheRange ( + (VOID *)(UINTN)Desc, + (UINTN)sizeof (*Desc) + ); + } +} + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c new file mode 100644 index 000000000..edff7573b --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c @@ -0,0 +1,32 @@ +/** @file + Null function version of cache function. + + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleService.h" + +#include + +/** + Writes Back a range of data cache lines covering a set of capsules in memory. + + Writes Back the data cache lines specified by ScatterGatherList. + + Null version, do nothing. + + @param ScatterGatherList Physical address of the data structure that + describes a set of capsules in memory + +**/ +VOID +CapsuleCacheWriteBack ( + IN EFI_PHYSICAL_ADDRESS ScatterGatherList + ) +{ +} + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c new file mode 100644 index 000000000..732a3c9ab --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c @@ -0,0 +1,29 @@ +/** @file + Default implementation of architecture specific routines related to + PersistAcrossReset capsules + + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleService.h" + +/** + Whether the platform supports capsules that persist across reset. Note that + some platforms only support such capsules at boot time. + + @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule() + at this time + FALSE otherwise +**/ +BOOLEAN +IsPersistAcrossResetCapsuleSupported ( + VOID + ) +{ + return FeaturePcdGet (PcdSupportUpdateCapsuleReset); +} + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf new file mode 100644 index 000000000..8bf5035a6 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf @@ -0,0 +1,108 @@ +## @file +# Capsule Runtime Driver produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities). +# +# It installs the Capsule Architectural Protocol defined in PI1.0a to signify +# the capsule runtime services are ready. +# +# Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CapsuleRuntimeDxe + MODULE_UNI_FILE = CapsuleRuntimeDxe.uni + FILE_GUID = 42857F0A-13F2-4B21-8A23-53D3F714B840 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = CapsuleServiceInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64 RISCV64 +# + +[Sources] + CapsuleService.c + CapsuleService.h + +[Sources.Ia32, Sources.EBC, Sources.ARM, Sources.AARCH64, Sources.RISCV64] + SaveLongModeContext.c + +[Sources.Ia32, Sources.X64, Sources.ARM, Sources.AARCH64, Sources.RISCV64] + CapsuleCache.c + +[Sources.Ia32, Sources.X64, Sources.EBC, Sources.RISCV64] + CapsuleReset.c + +[Sources.ARM, Sources.AARCH64] + Arm/CapsuleReset.c + +[Sources.EBC] + CapsuleCacheNull.c + +[Sources.X64] + X64/SaveLongModeContext.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + PcdLib + DebugLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + CapsuleLib + UefiRuntimeLib + BaseLib + PrintLib + BaseMemoryLib + CacheMaintenanceLib + +[LibraryClasses.X64] + UefiLib + BaseMemoryLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"CapsuleUpdateData" # (Process across reset capsule image) for capsule updated data + ## SOMETIMES_PRODUCES ## Variable:L"CapsuleLongModeBuffer" # The long mode buffer used by IA32 Capsule PEIM to call X64 CapsuleCoalesce code to handle >4GB capsule blocks + gEfiCapsuleVendorGuid + gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID # FMP capsule GUID + +[Protocols] + gEfiCapsuleArchProtocolGuid ## PRODUCES + +[Protocols.X64] + ## UNDEFINED ## NOTIFY + ## SOMETIMES_CONSUMES + gEdkiiVariableLockProtocolGuid + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSupportProcessCapsuleAtRuntime ## CONSUMES + +[FeaturePcd.X64] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule ## SOMETIMES_CONSUMES # Populate Image requires reset support. + gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES + +[Pcd.X64] + gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + +[Depex] + gEfiVariableWriteArchProtocolGuid # Depends on variable write functionality to produce capsule data variable + +# [Hob.X64] +# UNDEFINED ## SOMETIMES_CONSUMES # CPU + +[UserExtensions.TianoCore."ExtraFiles"] + CapsuleRuntimeDxeExtra.uni diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni new file mode 100644 index 000000000..b161af45c --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni @@ -0,0 +1,17 @@ +// /** @file +// Capsule Runtime Driver produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities). +// +// It installs the Capsule Architectural Protocol defined in PI1.0a to signify +// the capsule runtime services are ready. +// +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities)" + +#string STR_MODULE_DESCRIPTION #language en-US "It installs the Capsule Architectural Protocol defined in PI1.0a to signify the capsule runtime services are ready." + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni new file mode 100644 index 000000000..f97bfd64a --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// CapsuleRuntimeDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Runtime Firmware Update DXE Driver" + + diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c new file mode 100644 index 000000000..2fba22dec --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c @@ -0,0 +1,397 @@ +/** @file + Capsule Runtime Driver produces two UEFI capsule runtime services. + (UpdateCapsule, QueryCapsuleCapabilities) + It installs the Capsule Architectural Protocol defined in PI1.0a to signify + the capsule runtime services are ready. + +Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleService.h" + +// +// Handle for the installation of Capsule Architecture Protocol. +// +EFI_HANDLE mNewHandle = NULL; + +// +// The times of calling UpdateCapsule () +// +UINTN mTimes = 0; + +UINT32 mMaxSizePopulateCapsule = 0; +UINT32 mMaxSizeNonPopulateCapsule = 0; + +/** + Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended + consumption, the firmware may process the capsule immediately. If the payload should persist + across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must + be passed into ResetSystem() and will cause the capsule to be processed by the firmware as + part of the reset process. + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param ScatterGatherList Physical pointer to a set of + EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the + location in physical memory of a set of capsules. + + @retval EFI_SUCCESS Valid capsule was passed. If + CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the + capsule has been successfully processed by the firmware. + @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error. + @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were + set in the capsule header. + @retval EFI_INVALID_PARAMETER CapsuleCount is Zero. + @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL. + @retval EFI_UNSUPPORTED CapsuleImage is not recognized by the firmware. + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule + is compatible with this platform but is not capable of being submitted or processed + in runtime. The caller may resubmit the capsule prior to ExitBootServices(). + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates + the capsule is compatible with this platform but there are insufficient resources to process. + +**/ +EFI_STATUS +EFIAPI +UpdateCapsule ( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ) +{ + UINTN ArrayNumber; + EFI_STATUS Status; + EFI_CAPSULE_HEADER *CapsuleHeader; + BOOLEAN NeedReset; + BOOLEAN InitiateReset; + CHAR16 CapsuleVarName[30]; + CHAR16 *TempVarName; + + // + // Check if platform support Capsule In RAM or not. + // Platform could choose to drop CapsulePei/CapsuleX64 and do not support Capsule In RAM. + // + if (!PcdGetBool(PcdCapsuleInRamSupport)) { + return EFI_UNSUPPORTED; + } + + // + // Capsule Count can't be less than one. + // + if (CapsuleCount < 1) { + return EFI_INVALID_PARAMETER; + } + + NeedReset = FALSE; + InitiateReset = FALSE; + CapsuleHeader = NULL; + CapsuleVarName[0] = 0; + + for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { + // + // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have + // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. + // + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { + return EFI_INVALID_PARAMETER; + } + // + // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have + // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. + // + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) { + return EFI_INVALID_PARAMETER; + } + + // + // Check FMP capsule flag + // + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid) + && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) { + return EFI_INVALID_PARAMETER; + } + + // + // Check Capsule image without populate flag by firmware support capsule function + // + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { + Status = SupportCapsuleImage (CapsuleHeader); + if (EFI_ERROR(Status)) { + return Status; + } + } + } + + // + // Walk through all capsules, record whether there is a capsule needs reset + // or initiate reset. And then process capsules which has no reset flag directly. + // + for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + // + // Here should be in the boot-time for non-reset capsule image + // Platform specific update for the non-reset capsule image. + // + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) { + if (EfiAtRuntime () && !FeaturePcdGet (PcdSupportProcessCapsuleAtRuntime)) { + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = ProcessCapsuleImage(CapsuleHeader); + } + if (EFI_ERROR(Status)) { + return Status; + } + } else { + NeedReset = TRUE; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) { + InitiateReset = TRUE; + } + } + } + + // + // After launching all capsules who has no reset flag, if no more capsules claims + // for a system reset just return. + // + if (!NeedReset) { + return EFI_SUCCESS; + } + + // + // ScatterGatherList is only referenced if the capsules are defined to persist across + // system reset. + // + if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if the platform supports update capsule across a system reset + // + if (!IsPersistAcrossResetCapsuleSupported ()) { + return EFI_UNSUPPORTED; + } + + CapsuleCacheWriteBack (ScatterGatherList); + + // + // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... + // if user calls UpdateCapsule multiple times. + // + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + if (mTimes > 0) { + UnicodeValueToStringS ( + TempVarName, + sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), + 0, + mTimes, + 0 + ); + } + + // + // ScatterGatherList is only referenced if the capsules are defined to persist across + // system reset. Set its value into NV storage to let pre-boot driver to pick it up + // after coming through a system reset. + // + Status = EfiSetVariable ( + CapsuleVarName, + &gEfiCapsuleVendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINTN), + (VOID *) &ScatterGatherList + ); + if (!EFI_ERROR (Status)) { + // + // Variable has been set successfully, increase variable index. + // + mTimes++; + if(InitiateReset) { + // + // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header + // will initiate a reset of the platform which is compatible with the passed-in capsule request and will + // not return back to the caller. + // + EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + return Status; +} + +/** + Returns if the capsule can be supported via UpdateCapsule(). + Notice: When PcdCapsuleInRamSupport is unsupported, even this routine returns a valid answer, + the capsule still is unsupported via UpdateCapsule(). + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can + support as an argument to UpdateCapsule() via + CapsuleHeaderArray and ScatterGatherList. + @param ResetType Returns the type of reset required for the capsule update. + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_UNSUPPORTED The capsule image is not supported on this platform, and + MaximumCapsuleSize and ResetType are undefined. + @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL, or ResetTyep is NULL, + Or CapsuleCount is Zero, or CapsuleImage is not valid. + +**/ +EFI_STATUS +EFIAPI +QueryCapsuleCapabilities ( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaxiumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ) +{ + EFI_STATUS Status; + UINTN ArrayNumber; + EFI_CAPSULE_HEADER *CapsuleHeader; + BOOLEAN NeedReset; + + // + // Capsule Count can't be less than one. + // + if (CapsuleCount < 1) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether input parameter is valid + // + if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) { + return EFI_INVALID_PARAMETER; + } + + CapsuleHeader = NULL; + NeedReset = FALSE; + + for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + // + // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have + // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. + // + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { + return EFI_INVALID_PARAMETER; + } + // + // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have + // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. + // + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) { + return EFI_INVALID_PARAMETER; + } + + // + // Check FMP capsule flag + // + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid) + && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) { + return EFI_INVALID_PARAMETER; + } + + // + // Check Capsule image without populate flag is supported by firmware + // + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { + Status = SupportCapsuleImage (CapsuleHeader); + if (EFI_ERROR(Status)) { + return Status; + } + } + } + + // + // Find out whether there is any capsule defined to persist across system reset. + // + for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + NeedReset = TRUE; + break; + } + } + + if (NeedReset) { + // + //Check if the platform supports update capsule across a system reset + // + if (!IsPersistAcrossResetCapsuleSupported ()) { + return EFI_UNSUPPORTED; + } + *ResetType = EfiResetWarm; + *MaxiumCapsuleSize = (UINT64) mMaxSizePopulateCapsule; + } else { + // + // For non-reset capsule image. + // + *ResetType = EfiResetCold; + *MaxiumCapsuleSize = (UINT64) mMaxSizeNonPopulateCapsule; + } + + return EFI_SUCCESS; +} + + +/** + + This code installs UEFI capsule runtime service. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS UEFI Capsule Runtime Services are installed successfully. + +**/ +EFI_STATUS +EFIAPI +CapsuleServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mMaxSizePopulateCapsule = PcdGet32(PcdMaxSizePopulateCapsule); + mMaxSizeNonPopulateCapsule = PcdGet32(PcdMaxSizeNonPopulateCapsule); + + // + // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are + // put above 4GB, so capsule PEI will transfer to long mode to get capsule data. + // The page table and stack is used to transfer processor mode from IA32 to long mode. + // Create the base address of page table and stack, and save them into variable. + // This is not needed when capsule with reset type is not supported. + // + SaveLongModeContext (); + + // + // Install capsule runtime services into UEFI runtime service tables. + // + gRT->UpdateCapsule = UpdateCapsule; + gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities; + + // + // Install the Capsule Architectural Protocol on a new handle + // to signify the capsule runtime services are ready. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mNewHandle, + &gEfiCapsuleArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h new file mode 100644 index 000000000..069df3c75 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h @@ -0,0 +1,70 @@ +/** @file + Capsule Runtime Driver produces two UEFI capsule runtime services. + (UpdateCapsule, QueryCapsuleCapabilities) + It installs the Capsule Architectural Protocol defined in PI1.0a to signify + the capsule runtime services are ready. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _CAPSULE_SERVICE_H_ +#define _CAPSULE_SERVICE_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Create the variable to save the base address of page table and stack + for transferring into long mode in IA32 PEI. +**/ +VOID +SaveLongModeContext ( + VOID + ); + +/** + Whether the platform supports capsules that persist across reset. Note that + some platforms only support such capsules at boot time. + + @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule() + at this time + FALSE otherwise +**/ +BOOLEAN +IsPersistAcrossResetCapsuleSupported ( + VOID + ); + +/** + Writes Back a range of data cache lines covering a set of capsules in memory. + + Writes Back the data cache lines specified by ScatterGatherList. + + @param ScatterGatherList Physical address of the data structure that + describes a set of capsules in memory + +**/ +VOID +CapsuleCacheWriteBack ( + IN EFI_PHYSICAL_ADDRESS ScatterGatherList + ); + +#endif diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c new file mode 100644 index 000000000..37b388902 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c @@ -0,0 +1,21 @@ +/** @file + Create the NULL function to pass build in IA32/IPF/ARM/EBC. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Only when PEI is IA32 and DXE is X64, we need transfer to long mode in PEI + in order to process capsule data above 4GB. So create a NULL function here for + other cases. +**/ +VOID +SaveLongModeContext ( + VOID + ) +{ +} diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c new file mode 100644 index 000000000..d80d4ed3a --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c @@ -0,0 +1,209 @@ +/** @file + Create the variable to save the base address of page table and stack + for transferring into long mode in IA32 capsule PEI. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 8 extra pages for PF handler. +// +#define EXTRA_PAGE_TABLE_PAGES 8 + +/** + Allocate EfiReservedMemoryType below 4G memory address. + + This function allocates EfiReservedMemoryType below 4G memory address. + + @param Size Size of memory to allocate. + + @return Allocated Address for output. + +**/ +VOID* +AllocateReservedMemoryBelow4G ( + IN UINTN Size + ) +{ + UINTN Pages; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID* Buffer; + + Pages = EFI_SIZE_TO_PAGES (Size); + Address = 0xffffffff; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + Pages, + &Address + ); + ASSERT_EFI_ERROR (Status); + + Buffer = (VOID *) (UINTN) Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + Register callback function upon VariableLockProtocol + to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. +**/ +VOID +EFIAPI +VariableLockCapsuleLongModeBufferVariable ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + // + // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + if (!EFI_ERROR (Status)) { + Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid); + ASSERT_EFI_ERROR (Status); + } +} + +/** + 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping. + 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode. + +**/ +VOID +EFIAPI +PrepareContextForCapsulePei ( + VOID + ) +{ + UINTN ExtraPageTablePages; + UINT32 RegEax; + UINT32 RegEdx; + UINTN TotalPagesNum; + UINT8 PhysicalAddressBits; + UINT32 NumberOfPml4EntriesNeeded; + UINT32 NumberOfPdpEntriesNeeded; + BOOLEAN Page1GSupport; + EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer; + EFI_STATUS Status; + VOID *Registration; + + // + // Calculate the size of page table, allocate the memory. + // + Page1GSupport = FALSE; + if (PcdGetBool(PcdUse1GPageTable)) { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT26) != 0) { + Page1GSupport = TRUE; + } + } + } + + // + // Create 4G page table by default, + // and let PF handler to handle > 4G request. + // + PhysicalAddressBits = 32; + ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES; + + // + // Calculate the table entries needed. + // + if (PhysicalAddressBits <= 39 ) { + NumberOfPml4EntriesNeeded = 1; + NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30)); + } else { + NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39)); + NumberOfPdpEntriesNeeded = 512; + } + + if (!Page1GSupport) { + TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1; + } else { + TotalPagesNum = NumberOfPml4EntriesNeeded + 1; + } + TotalPagesNum += ExtraPageTablePages; + DEBUG ((DEBUG_INFO, "CapsuleRuntimeDxe X64 TotalPagesNum - 0x%x pages\n", TotalPagesNum)); + + LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum)); + ASSERT (LongModeBuffer.PageTableAddress != 0); + + // + // Allocate stack + // + LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize); + LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize)); + ASSERT (LongModeBuffer.StackBaseAddress != 0); + + Status = gRT->SetVariable ( + EFI_CAPSULE_LONG_MODE_BUFFER_NAME, + &gEfiCapsuleVendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (EFI_CAPSULE_LONG_MODE_BUFFER), + &LongModeBuffer + ); + if (!EFI_ERROR (Status)) { + // + // Register callback function upon VariableLockProtocol + // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it. + // + EfiCreateProtocolNotifyEvent ( + &gEdkiiVariableLockProtocolGuid, + TPL_CALLBACK, + VariableLockCapsuleLongModeBufferVariable, + NULL, + &Registration + ); + } else { + DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status)); + gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize)); + } +} + +/** + Create the variable to save the base address of page table and stack + for transferring into long mode in IA32 capsule PEI. +**/ +VOID +SaveLongModeContext ( + VOID + ) +{ + if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) { + // + // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB. + // + PrepareContextForCapsulePei (); + } +} -- cgit