From 3e11f7eb7174302bb350664e402552ea1bea399d Mon Sep 17 00:00:00 2001 From: "Guo, Mang" Date: Tue, 29 Mar 2016 06:02:45 +0000 Subject: Enable Capsule update and ESRT feature. Several modules are modified or added for the feature. git-svn-id: https://ssvn.intel.com:80/ssg/csd/tiano/tianoad/Research/Developer/mangguo/MinnowBoardMaxUDK2015Platform@106127 f973567a-9dae-4ef8-9d9d-80fbec5b6bbd # Conflicts: # Vlv2TbltDevicePkg/PlatformPkgConfig.dsc # Vlv2TbltDevicePkg/PlatformPkgIA32.dsc --- .../BiosUpdateConfig/BiosUpdateConfig.ini | 23 + Vlv2TbltDevicePkg/FmpSample/FmpSample.c | 114 ++ Vlv2TbltDevicePkg/FmpSample/FmpSample.h | 177 +++ Vlv2TbltDevicePkg/FmpSample/FmpSample.inf | 64 + Vlv2TbltDevicePkg/FmpSample/FmpSampleImpl.c | 336 ++++++ Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf | 4 + Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c | 37 +- Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.h | 2 + Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmm.inf | 4 + .../Include/Guid/FmpSampleImageInfoGuid.h | 30 + Vlv2TbltDevicePkg/Include/Guid/SystemFwClassGuid.h | 30 + .../Library/DxeEsrtCapsuleBsLib/DxeCapsuleLib.c | 957 +++++++++++++++ .../DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf | 62 + .../Library/DxeEsrtCapsuleRtLib/DxeCapsuleLib.c | 1038 +++++++++++++++++ .../DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf | 64 + .../Library/FlashDeviceLib/FlashDeviceLib.c | 4 +- .../Library/FlashDeviceLib/SpiChipDefinitions.h | 2 +- .../Library/PlatformBdsLib/BdsPlatform.c | 59 +- .../Library/PlatformBdsLib/BdsPlatform.h | 24 + .../Library/PlatformBdsLib/Capsules.c | 304 +++++ .../Library/PlatformBdsLib/PlatformBdsLib.inf | 6 + Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.c | 140 +++ Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.h | 32 + Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.inf | 58 + Vlv2TbltDevicePkg/PlatformPkg.dec | 12 +- Vlv2TbltDevicePkg/PlatformPkg.fdf | 67 +- Vlv2TbltDevicePkg/PlatformPkgConfig.dsc | 195 ++-- Vlv2TbltDevicePkg/PlatformPkgGcc.fdf | 55 +- Vlv2TbltDevicePkg/PlatformPkgGccX64.dsc | 48 +- Vlv2TbltDevicePkg/PlatformPkgIA32.dsc | 58 +- Vlv2TbltDevicePkg/PlatformPkgX64.dsc | 55 +- Vlv2TbltDevicePkg/UpdateDriverDxe/FlashUpdate.c | 1217 ++++++++++++++++++++ .../UpdateDriverDxe/ParseUpdateProfile.c | 1134 ++++++++++++++++++ .../UpdateDriverDxe/UpdateDispatcher.c | 897 +++++++++++++++ Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriver.h | 217 ++++ .../UpdateDriverDxe/UpdateDriverDxe.inf | 82 ++ .../UpdateDriverDxe/UpdateDriverDxe.uni | Bin 0 -> 1948 bytes .../UpdateDriverDxe/UpdateStrings.uni | Bin 0 -> 2400 bytes 38 files changed, 7455 insertions(+), 153 deletions(-) create mode 100644 Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini create mode 100644 Vlv2TbltDevicePkg/FmpSample/FmpSample.c create mode 100644 Vlv2TbltDevicePkg/FmpSample/FmpSample.h create mode 100644 Vlv2TbltDevicePkg/FmpSample/FmpSample.inf create mode 100644 Vlv2TbltDevicePkg/FmpSample/FmpSampleImpl.c create mode 100644 Vlv2TbltDevicePkg/Include/Guid/FmpSampleImageInfoGuid.h create mode 100644 Vlv2TbltDevicePkg/Include/Guid/SystemFwClassGuid.h create mode 100644 Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeCapsuleLib.c create mode 100644 Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf create mode 100644 Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeCapsuleLib.c create mode 100644 Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf create mode 100644 Vlv2TbltDevicePkg/Library/PlatformBdsLib/Capsules.c create mode 100644 Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.c create mode 100644 Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.h create mode 100644 Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.inf create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/FlashUpdate.c create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/ParseUpdateProfile.c create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDispatcher.c create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriver.h create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.inf create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.uni create mode 100644 Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateStrings.uni diff --git a/Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini b/Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini new file mode 100644 index 0000000000..b867c19c85 --- /dev/null +++ b/Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini @@ -0,0 +1,23 @@ +/** @file + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +[Head] +NumOfUpdate = 1 +Update0 = FvMain + +[FvMain] +UpdateType = 0 # Spi Update +FvBaseAddress = 0xFFD10000 #FvImage base address +FileGuid = 4A538818-5AE0-4eb2-B2EB-488B23657022 +FaultTolerant = FALSE \ No newline at end of file diff --git a/Vlv2TbltDevicePkg/FmpSample/FmpSample.c b/Vlv2TbltDevicePkg/FmpSample/FmpSample.c new file mode 100644 index 0000000000..77ffaaf0a1 --- /dev/null +++ b/Vlv2TbltDevicePkg/FmpSample/FmpSample.c @@ -0,0 +1,114 @@ +/** @file + Implement updatable firmware resource for Fmp Sample + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "FmpSample.h" + +// +// FmpSample driver private data +// +FMP_SAMPLE_PRIVATE_DATA *mFmpSamplePrivate = NULL; + + +EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = { + FmpGetImageInfo, + FmpGetImage, + FmpSetImage, + FmpCheckImage, + FmpGetPackageInfo, + FmpSetPackageInfo +}; + + +EFI_STATUS +EFIAPI +FmpSampleMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Initialize LanMacPrivateData + // + mFmpSamplePrivate = AllocateZeroPool (sizeof(FMP_SAMPLE_PRIVATE_DATA)); + if (mFmpSamplePrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = InitializePrivateData(mFmpSamplePrivate); + if (EFI_ERROR(Status)) { + FreePool(mFmpSamplePrivate); + mFmpSamplePrivate = NULL; + } + + // + // Install FMP protocol. + // + Status = gBS->InstallProtocolInterface ( + &mFmpSamplePrivate->Handle, + &gEfiFirmwareManagementProtocolGuid, + EFI_NATIVE_INTERFACE, + &mFmpSamplePrivate->Fmp + ); + if (EFI_ERROR (Status)) { + FreePool(mFmpSamplePrivate); + mFmpSamplePrivate = NULL; + return Status; + } + + return Status; +} + + +/** + This is the default unload handle for FmpSample drivers + + Update driver does not open virtual handler by driver. So can not use + Disconnect to call DriverBinding stop. Here we directly uninstall FMP + and free resource + + @param[in] ImageHandle The drivers' driver image. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. + +**/ +EFI_STATUS +EFIAPI +FmpSampleUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + // + // If the driver has been connected + // + if (mFmpSamplePrivate != NULL) { + // + // Uninstall FMP protocol + // + gBS->UninstallMultipleProtocolInterfaces( + mFmpSamplePrivate->Handle, + &gEfiFirmwareManagementProtocolGuid, + &mFmpSamplePrivate->Fmp, + NULL + ); + + FreePool(mFmpSamplePrivate); + } + + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/FmpSample/FmpSample.h b/Vlv2TbltDevicePkg/FmpSample/FmpSample.h new file mode 100644 index 0000000000..8a9589f12b --- /dev/null +++ b/Vlv2TbltDevicePkg/FmpSample/FmpSample.h @@ -0,0 +1,177 @@ +/** @file + FmpSample header file + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FMP_SAMPLE_UPDATE_H_ +#define _FMP_SAMPLE_UPDATE_H_ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Current Firmwarre version +// +#define CURRENT_FIRMWARE_VERSION 0x00000001 +// +// The lowesest Supported Firmware Version +// +#define LOWEST_SUPPORTED_FIRMWARE_VERSION 0x00000001 + + +// +// Image Version number +// + +#define FMP_SAMPLE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('F', 'M', 'P', 'S') + +#pragma pack(1) +typedef struct{ + UINT32 Version; + UINT32 Data; +}FMP_SAMPLE_UDPATE_DATA; +#pragma pack() + +// +// LAN MAC private data structure. +// +struct _FMP_SAMPLE_PRIVATE_DATA{ + UINT32 Signature; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp; + EFI_HANDLE Handle; + UINT8 DescriptorCount; + EFI_SYSTEM_RESOURCE_ENTRY EsrtInfo; + FMP_SAMPLE_UDPATE_DATA UpdateData; +}; + +typedef struct _FMP_SAMPLE_PRIVATE_DATA FMP_SAMPLE_PRIVATE_DATA; + + +/** + Returns a pointer to the FMP_SAMPLE_PRIVATE_DATA structure from the input a as Fmp. + + If the signatures matches, then a pointer to the data structure that contains + a specified field of that data structure is returned. + + @param a Pointer to the field specified by ServiceBinding within + a data structure of type FMP_SAMPLE_PRIVATE_DATA. + +**/ +#define FMP_SAMPLE_PRIVATE_DATA_FROM_FMP(a) \ + CR ( \ + (a), \ + FMP_SAMPLE_PRIVATE_DATA, \ + Fmp, \ + FMP_SAMPLE_PRIVATE_DATA_SIGNATURE \ + ) + + +EFI_STATUS +EFIAPI FmpGetImageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN OUT UINTN *ImageInfoSize, + IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + OUT UINT32 *DescriptorVersion, + OUT UINT8 *DescriptorCount, + OUT UINTN *DescriptorSize, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName + ); + +EFI_STATUS +EFIAPI FmpGetImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ); + +EFI_STATUS +EFIAPI FmpSetImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, + OUT CHAR16 **AbortReason + ); + +EFI_STATUS +EFIAPI FmpCheckImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *ImageUpdatable + ); + +EFI_STATUS +EFIAPI FmpGetPackageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName, + OUT UINT32 *PackageVersionNameMaxLen, + OUT UINT64 *AttributesSupported, + OUT UINT64 *AttributesSetting + ); + +EFI_STATUS +EFIAPI FmpSetPackageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN UINT32 PackageVersion, + IN CONST CHAR16 *PackageVersionName + ); + +/*++ + + Routine Description: + + Initialize FmpSampleDriver private data structure. + + Arguments: + + + FmpSamplePrivate - private data structure to be initialized. + + Returns: + + --*/ +EFI_STATUS +InitializePrivateData( + IN FMP_SAMPLE_PRIVATE_DATA *FmpSamplePrivate + ); + +extern EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol; + +#endif + diff --git a/Vlv2TbltDevicePkg/FmpSample/FmpSample.inf b/Vlv2TbltDevicePkg/FmpSample/FmpSample.inf new file mode 100644 index 0000000000..ac7114a9ef --- /dev/null +++ b/Vlv2TbltDevicePkg/FmpSample/FmpSample.inf @@ -0,0 +1,64 @@ +## @file +# Component description file for FmpSample module +# +# +# Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FmpSample + FILE_GUID = 30743C10-6706-4E45-9722-EC7FB6D2161D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FmpSampleMain + UNLOAD_IMAGE = FmpSampleUnload + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + FmpSample.c + FmpSampleImpl.c + FmpSample.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Vlv2TbltDevicePkg/PlatformPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + BaseMemoryLib + DebugLib + PcdLib + MemoryAllocationLib + UefiBootServicesTableLib + HobLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + +[Guids] + gFMPSampleUpdateImageInfoGuid + +[Protocols] + gEfiFirmwareManagementProtocolGuid ## SOMTIMES_PRODUCE + +[Pcd] + +[FixedPcd] + +[Depex] + gEfiVariableWriteArchProtocolGuid \ No newline at end of file diff --git a/Vlv2TbltDevicePkg/FmpSample/FmpSampleImpl.c b/Vlv2TbltDevicePkg/FmpSample/FmpSampleImpl.c new file mode 100644 index 0000000000..0ba0bedc1c --- /dev/null +++ b/Vlv2TbltDevicePkg/FmpSample/FmpSampleImpl.c @@ -0,0 +1,336 @@ +/** @file + Implement updatable firmware resource for Fmp Sample + + Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "FmpSample.h" + +/** + Returns information about the current firmware image(s) of the device. + + This function allows a copy of the current firmware image to be created and saved. + The saved copy could later been used, for example, in firmware image recovery or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer. + On input, this is the size of the buffer allocated by the caller. + On output, it is the size of the buffer returned by the firmware + if the buffer was large enough, or the size of the buffer needed + to contain the image(s) information if the buffer was too small. + @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s) + information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number + associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] DescriptorCount A pointer to the location in which firmware returns the number of + descriptors or firmware images within this device. + @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes, + of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] PackageVersion A version number that represents all the firmware images in the device. + The format is vendor specific and new version must have a greater value + than the old version. If PackageVersion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison + is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates + that package version update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the + package version name. The buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility to free it with a call + to FreePool(). + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size + needed to hold the image(s) information is returned in ImageInfoSize. + @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL. + @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image. + +**/ +EFI_STATUS +EFIAPI FmpGetImageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL*This, + IN OUT UINTN *ImageInfoSize, + IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + OUT UINT32 *DescriptorVersion, + OUT UINT8 *DescriptorCount, + OUT UINTN *DescriptorSize, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName + ) +{ + FMP_SAMPLE_PRIVATE_DATA *FmpSamplePrivate; + + if(ImageInfoSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)) { + *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR); + return EFI_BUFFER_TOO_SMALL; + } + + if (ImageInfo == NULL + || DescriptorVersion == NULL + || DescriptorCount == NULL + || DescriptorSize == NULL + || PackageVersion == NULL + || PackageVersionName == NULL) { + return EFI_INVALID_PARAMETER; + } + + FmpSamplePrivate = FMP_SAMPLE_PRIVATE_DATA_FROM_FMP(This); + + *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * FmpSamplePrivate->DescriptorCount; + *DescriptorSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR); + *DescriptorCount = FmpSamplePrivate->DescriptorCount; + *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + // + // Do not support package version + // + *PackageVersion = 0xFFFFFFFF; + *PackageVersionName = NULL; + + // + // LanMacUpdate supports 1 ImageInfo descriptor + // + ImageInfo[0].ImageIndex = 0x01; + ImageInfo[0].ImageTypeId = FmpSamplePrivate->EsrtInfo.FwClass; + ImageInfo[0].ImageId = 0x01; + ImageInfo[0].ImageIdName = NULL; + ImageInfo[0].VersionName = NULL; + ImageInfo[0].Size = sizeof(FmpSamplePrivate->UpdateData); + ImageInfo[0].AttributesSupported = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED | IMAGE_ATTRIBUTE_IN_USE; + ImageInfo[0].AttributesSetting = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED | IMAGE_ATTRIBUTE_IN_USE; + ImageInfo[0].Compatibilities = 0x0; + ImageInfo[0].Version = FmpSamplePrivate->EsrtInfo.FwVersion; + ImageInfo[0].LowestSupportedImageVersion = FmpSamplePrivate->EsrtInfo.LowestSupportedFwVersion; + ImageInfo[0].LastAttemptVersion = FmpSamplePrivate->EsrtInfo.LastAttemptVersion; + ImageInfo[0].LastAttemptStatus = FmpSamplePrivate->EsrtInfo.LastAttemptStatus; + ImageInfo[0].HardwareInstance = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI FmpGetImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ) +{ + FMP_SAMPLE_PRIVATE_DATA *FmpSamplePrivate; + + if (Image == NULL || ImageSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + FmpSamplePrivate = FMP_SAMPLE_PRIVATE_DATA_FROM_FMP(This); + + if (ImageIndex == 0 || ImageIndex > FmpSamplePrivate->DescriptorCount || ImageSize == NULL || Image == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*ImageSize < sizeof(FmpSamplePrivate->UpdateData)) { + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem(Image, &FmpSamplePrivate->UpdateData, sizeof(FmpSamplePrivate->UpdateData)); + *ImageSize = sizeof(FmpSamplePrivate->UpdateData); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI FmpSetImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, + OUT CHAR16 **AbortReason + ) +{ + EFI_STATUS Status; + FMP_SAMPLE_PRIVATE_DATA *FmpSamplePrivate; + + if (Image == NULL || AbortReason == NULL) { + return EFI_INVALID_PARAMETER; + } + + FmpSamplePrivate = FMP_SAMPLE_PRIVATE_DATA_FROM_FMP(This); + *AbortReason = NULL; + + if (ImageIndex == 0 || ImageIndex > FmpSamplePrivate->DescriptorCount || ImageSize != sizeof(FmpSamplePrivate->UpdateData) || Image == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Update Version in NV after successful flash image update . + // + Status = gRT->SetVariable( + L"UpdateData", + &gFMPSampleUpdateImageInfoGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(FmpSamplePrivate->UpdateData), + (FMP_SAMPLE_UDPATE_DATA *)Image + ); + + FmpSamplePrivate->EsrtInfo.FwVersion = ((FMP_SAMPLE_UDPATE_DATA *)Image)->Version; + FmpSamplePrivate->EsrtInfo.LastAttemptVersion = ((FMP_SAMPLE_UDPATE_DATA *)Image)->Version; + if (EFI_ERROR(Status)) { + FmpSamplePrivate->EsrtInfo.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } else { + FmpSamplePrivate->EsrtInfo.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + } + + Status = gRT->SetVariable( + L"FmpInfo", + &gFMPSampleUpdateImageInfoGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(FmpSamplePrivate->EsrtInfo), + &FmpSamplePrivate->EsrtInfo + ); + + return Status; +} + +EFI_STATUS +EFIAPI FmpCheckImage( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *ImageUpdatable + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI FmpGetPackageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName, + OUT UINT32 *PackageVersionNameMaxLen, + OUT UINT64 *AttributesSupported, + OUT UINT64 *AttributesSetting + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI FmpSetPackageInfo( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN UINT32 PackageVersion, + IN CONST CHAR16 *PackageVersionName + ) +{ + return EFI_UNSUPPORTED; +} + +/*++ + + Routine Description: + + Initialize FmpSampleDriver private data structure. + + Arguments: + + + FmpSamplePrivate - private data structure to be initialized. + + Returns: + + --*/ +EFI_STATUS +InitializePrivateData( + IN FMP_SAMPLE_PRIVATE_DATA *FmpSamplePrivate + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + UINTN DataSize; + + // + // Get current Boot Mode + // + BootMode = GetBootModeHob (); + + // + // The NV Variable is not available in RECOVERY Mode + // + if (BootMode == BOOT_IN_RECOVERY_MODE) { + return EFI_UNSUPPORTED; + } + + FmpSamplePrivate->Signature = FMP_SAMPLE_PRIVATE_DATA_SIGNATURE; + FmpSamplePrivate->Handle = NULL; + FmpSamplePrivate->DescriptorCount = 1; + CopyMem(&FmpSamplePrivate->Fmp, &mFirmwareManagementProtocol, sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL)); + + DataSize = sizeof(FmpSamplePrivate->EsrtInfo); + Status = gRT->GetVariable( + L"FmpInfo", + &gFMPSampleUpdateImageInfoGuid, + NULL, + &DataSize, + &FmpSamplePrivate->EsrtInfo + ); + + if (EFI_ERROR(Status)) { + FmpSamplePrivate->EsrtInfo.CapsuleFlags = 0; + FmpSamplePrivate->EsrtInfo.FwClass = gFMPSampleUpdateImageInfoGuid; + FmpSamplePrivate->EsrtInfo.FwType = ESRT_FW_TYPE_DEVICEFIRMWARE; + FmpSamplePrivate->EsrtInfo.FwVersion = CURRENT_FIRMWARE_VERSION; + FmpSamplePrivate->EsrtInfo.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + FmpSamplePrivate->EsrtInfo.LastAttemptVersion = 0; + FmpSamplePrivate->EsrtInfo.LowestSupportedFwVersion = LOWEST_SUPPORTED_FIRMWARE_VERSION; + Status = gRT->SetVariable( + L"FmpInfo", + &gFMPSampleUpdateImageInfoGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(FmpSamplePrivate->EsrtInfo), + &FmpSamplePrivate->EsrtInfo + ); + + } else if (DataSize != sizeof(FmpSamplePrivate->EsrtInfo)) { + Status = EFI_INVALID_PARAMETER; + } + + DataSize = sizeof(FmpSamplePrivate->UpdateData); + Status = gRT->GetVariable( + L"UpdateData", + &gFMPSampleUpdateImageInfoGuid, + NULL, + &DataSize, + &FmpSamplePrivate->UpdateData + ); + + if (EFI_ERROR(Status)) { + FmpSamplePrivate->UpdateData.Version = 0; + FmpSamplePrivate->UpdateData.Data = 0; + + Status = gRT->SetVariable( + L"UpdateData", + &gFMPSampleUpdateImageInfoGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(FmpSamplePrivate->UpdateData), + &FmpSamplePrivate->UpdateData + ); + } + return Status; +} + diff --git a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf index e8e6411fe4..dce1d8755b 100644 --- a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf +++ b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf @@ -57,6 +57,7 @@ UefiRuntimeLib UefiBootServicesTableLib UefiDriverEntryPoint + HobLib [Guids] gEfiFirmwareFileSystem2Guid # ALWAYS_CONSUMED @@ -71,6 +72,9 @@ gPlatformModuleTokenSpaceGuid.PcdFlashFvMainBase gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoveryBase + +[FeaturePcd] + gPlatformModuleTokenSpaceGuid.PcdFeatureRecoveryDisabled [Pcd] gPlatformModuleTokenSpaceGuid.PcdFlashFvMainSize diff --git a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c index da7dce6e13..723728ad65 100644 --- a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c +++ b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c @@ -1017,13 +1017,42 @@ FvbInitialize ( UINTN Idx; UINT32 MaxLbaSize; BOOLEAN FvHeaderValid; +EFI_BOOT_MODE BootMode; +UINT32 PlatformFvBaseAddress[2]; +UINT32 PlatformFvBaseAddressCount; +UINT32 PlatformFvLockList[3]; +UINT32 PlatformFvLockListCount; + // + // This platform driver knows there are 3 FVs on + // FD, which are FvRecovery, FvMain and FvNvStorage. + // + BootMode = GetBootModeHob (); + if ( FeaturePcdGet ( PcdFeatureRecoveryDisabled ) || BootMode == BOOT_IN_RECOVERY_MODE) { + // + // On recovery boot, don't report any firmware FV images, because their data can't be trusted. + // + PlatformFvBaseAddressCount = 1; + PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageVariableBase); + } else { + PlatformFvBaseAddressCount = 2; + PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashFvMainBase); + PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageVariableBase); + PlatformFvBaseAddress[2] = PcdGet32 (PcdFlashFvRecoveryBase); + } + + // + // List of FVs that should be write protected on normal boots. + // + PlatformFvLockListCount = 1; + PlatformFvLockList[0] = PcdGet32 (PcdFlashFvMainBase); + PlatformFvLockList[1] = PcdGet32 (PcdFlashFvRecoveryBase); // // Calculate the total size for all firmware volume block instances. // BufferSize = 0; - for (Idx = 0; Idx < 1; Idx++) { - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx]; + for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PlatformFvBaseAddress[Idx]; BufferSize += (FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER) @@ -1038,8 +1067,8 @@ FvbInitialize ( FwhInstance = mFvbModuleGlobal.FvInstance; mFvbModuleGlobal.NumFv = 0; - for (Idx = 0; Idx < 1; Idx++) { - BaseAddress = mPlatformFvBaseAddress[Idx]; + for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { + BaseAddress = PlatformFvBaseAddress[Idx]; FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) { diff --git a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.h b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.h index cfdb92c5bc..9ace55d035 100644 --- a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.h +++ b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.h @@ -25,6 +25,7 @@ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
#include #include +#include #include #include #include @@ -35,6 +36,7 @@ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
#include #include #include +#include // // Define two helper macro to extract the Capability field or Status field in FVB diff --git a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmm.inf b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmm.inf index 718ae0bbb2..f61a4210eb 100644 --- a/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmm.inf +++ b/Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmm.inf @@ -60,6 +60,7 @@ SmmServicesTableLib UefiBootServicesTableLib UefiDriverEntryPoint + HobLib [Guids] gEfiFirmwareFileSystem2Guid # ALWAYS_CONSUMED @@ -74,6 +75,9 @@ gPlatformModuleTokenSpaceGuid.PcdFlashFvMainBase gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoveryBase + +[FeaturePcd] + gPlatformModuleTokenSpaceGuid.PcdFeatureRecoveryDisabled [Pcd] gPlatformModuleTokenSpaceGuid.PcdFlashFvMainSize diff --git a/Vlv2TbltDevicePkg/Include/Guid/FmpSampleImageInfoGuid.h b/Vlv2TbltDevicePkg/Include/Guid/FmpSampleImageInfoGuid.h new file mode 100644 index 0000000000..66cd56c7a0 --- /dev/null +++ b/Vlv2TbltDevicePkg/Include/Guid/FmpSampleImageInfoGuid.h @@ -0,0 +1,30 @@ +/** @file + FMP Sample updatable resource guid + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#ifndef _FMP_SAMPLE_UPDATE_IMAGE_INFO_GUID_H_ +#define _FMP_SAMPLE_UPDATE_IMAGE_INFO_GUID_H_ + +// +// GUID definition for FMP sample ImageInfo +// +#define FMP_SAMPLE_UPDATE_IMAGE_INFO_GUID \ + { \ + 0xb9847c4e, 0xf5b6, 0x42dc, { 0xb6, 0xf4, 0xed, 0x44, 0x7, 0xb0, 0x67, 0x4c } \ + } + +extern EFI_GUID gFMPSampleUpdateImageInfoGuid; +#endif diff --git a/Vlv2TbltDevicePkg/Include/Guid/SystemFwClassGuid.h b/Vlv2TbltDevicePkg/Include/Guid/SystemFwClassGuid.h new file mode 100644 index 0000000000..6cfb7e7f05 --- /dev/null +++ b/Vlv2TbltDevicePkg/Include/Guid/SystemFwClassGuid.h @@ -0,0 +1,30 @@ +/** @file + System FW Class guid + + Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#ifndef _SYSTEM_FW_CLASS_GUID_H_ +#define _SYSTEM_FW_CLASS_GUID_H_ + +// +// GUID definition for System FW Class +// +#define SYSTEM_FW_CLASS_GUID \ + { \ + 0x819b858e, 0xc52c, 0x402f, { 0x80, 0xe1, 0x5b, 0x31, 0x1b, 0x6c, 0x19, 0x59 }\ + } + +extern EFI_GUID gSystemFwClassGuid; +#endif diff --git a/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeCapsuleLib.c b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeCapsuleLib.c new file mode 100644 index 0000000000..4b1acb40ec --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeCapsuleLib.c @@ -0,0 +1,957 @@ +/** @file + Capsule Boottime Library instance to update capsule image to flash. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/** + Function indicate the current completion progress of the firmware + update. Platform may override with own specific progress function. + + @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update + + @retval EFI_SUCESS Input capsule is a correct FMP capsule. +**/ +EFI_STATUS +EFIAPI +Update_Image_Progress ( + IN UINTN Completion +) +{ + return EFI_SUCCESS; +} + +/** + Validate Fmp capsules layout. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is a correct FMP capsule. + @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule. +**/ +EFI_STATUS +ValidateFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT8 *EndOfCapsule; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; + UINT8 *EndOfPayload; + UINT64 *ItemOffsetList; + UINT32 ItemNum; + UINTN Index; + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; + + if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { + return EFI_INVALID_PARAMETER; + } + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + + ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + + if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) { + // + // No payload element + // + if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) { + return EFI_SUCCESS; + } else { + return EFI_INVALID_PARAMETER; + } + } + + if (FmpCapsuleHeader->PayloadItemCount != 0) { + // + // Check if the last payload is within capsule image range + // + ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]); + EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize; + } else { + // + // No driver & payload element in FMP + // + EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1); + } + + if (EndOfPayload != EndOfCapsule) { + return EFI_INVALID_PARAMETER; + } + + // + // All the address in ItemOffsetList must be stored in ascending order + // + if (ItemNum >= 2) { + for (Index = 0; Index < ItemNum - 1; Index++) { + if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) { + return EFI_INVALID_PARAMETER; + } + } + } + + return EFI_SUCCESS; +} + +/** + Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer + is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt + buffer is passed in it will be used if it is big enough. + + @param BmpImage Pointer to BMP file + @param BmpImageSize Number of bytes in BmpImage + @param GopBlt Buffer containing GOP version of BmpImage. + @param GopBltSize Size of GopBlt in bytes. + @param PixelHeight Height of GopBlt/BmpImage in pixels + @param PixelWidth Width of GopBlt/BmpImage in pixels + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image + @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough. + GopBltSize will contain the required size. + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +static +EFI_STATUS +ConvertBmpToGopBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT VOID **GopBlt, + IN OUT UINTN *GopBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINT64 BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + BOOLEAN IsAllocated; + + BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; + + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { + return EFI_UNSUPPORTED; + } + + // + // Doesn't support compress. + // + if (BmpHeader->CompressionType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + // + // Calculate the BltBuffer needed size. + // + BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); + // + // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + return EFI_UNSUPPORTED; + } + BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + IsAllocated = FALSE; + if (*GopBlt == NULL) { + // + // GopBlt is not allocated by caller. + // + *GopBltSize = (UINTN) BltBufferSize; + *GopBlt = AllocatePool (*GopBltSize); + IsAllocated = TRUE; + if (*GopBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // GopBlt has been allocated by caller. + // + if (*GopBltSize < (UINTN) BltBufferSize) { + *GopBltSize = (UINTN) BltBufferSize; + return EFI_BUFFER_TOO_SMALL; + } + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + + // + // Convert image from BMP to Blt buffer format + // + BltBuffer = *GopBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Convert 1-bit (2 colors) BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt--; + Width--; + break; + + case 4: + // + // Convert 4-bit (16 colors) BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + break; + + case 8: + // + // Convert 8-bit (256 colors) BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + // + // It is 24-bit BMP. + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + case 32: + // + // it is 32-bit BMP. Skip pixel's highest byte + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image++; + break; + + default: + // + // Other bit format BMP is not supported. + // + if (IsAllocated) { + FreePool (*GopBlt); + *GopBlt = NULL; + } + return EFI_UNSUPPORTED; + break; + }; + + } + + ImageIndex = (UINTN) (Image - ImageHeader); + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return EFI_SUCCESS; +} + + +/** + Those capsules supported by the firmwares. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is supported by firmware. + @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware. +**/ +EFI_STATUS +DisplayCapsuleImage ( + IN DISPLAY_DISPLAY_PAYLOAD *ImagePayload, + IN UINTN PayloadSize + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINTN BltSize; + UINTN Height; + UINTN Width; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + + // + // Only Support Bitmap by now + // + if (ImagePayload->ImageType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Try to open GOP + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) { + return EFI_UNSUPPORTED; + } + + Blt = NULL; + Width = 0; + Height = 0; + Status = ConvertBmpToGopBlt ( + ImagePayload + 1, + PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD), + (VOID **)&Blt, + &BltSize, + &Height, + &Width + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GraphicsOutput->Blt ( + GraphicsOutput, + Blt, + EfiBltBufferToVideo, + 0, + 0, + (UINTN) ImagePayload->OffsetX, + (UINTN) ImagePayload->OffsetY, + Width, + Height, + Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + + FreePool(Blt); + + return Status; +} + +/** + Process Firmware management protocol data capsule. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Process Capsule Image successfully. + @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. + @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. + @retval EFI_OUT_OF_RESOURCES Not enough memory. +**/ +EFI_STATUS +ProcessFmpCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_STATUS StatusEsrt; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT8 *EndOfCapsule; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; + UINT8 *Image; + EFI_HANDLE ImageHandle; + UINT64 *ItemOffsetList; + UINT32 ItemNum; + UINTN Index; + UINTN ExitDataSize; + EFI_HANDLE *HandleBuffer; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN NumberOfHandles; + UINTN DescriptorSize; + UINT8 FmpImageInfoCount; + UINT32 FmpImageInfoDescriptorVer; + UINTN ImageInfoSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + CHAR16 *AbortReason; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo; + UINTN DriverLen; + UINTN Index1; + UINTN Index2; + MEMMAP_DEVICE_PATH MemMapNode; + EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath; + ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + + Status = EFI_SUCCESS; + HandleBuffer = NULL; + ExitDataSize = 0; + DriverDevicePath = NULL; + EsrtProtocol = NULL; + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; + + if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { + return EFI_INVALID_PARAMETER; + } + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + + ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + + // + // capsule in which driver count and payload count are both zero is not processed. + // + if (ItemNum == 0) { + return EFI_SUCCESS; + } + + // + // Update corresponding ESRT entry LastAttemp Status + // + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); + + // + // 1. ConnectAll to ensure + // All the communication protocol required by driver in capsule installed + // All FMP protocols are installed + // + EfiBootManagerConnectAll(); + + + // + // 2. Try to load & start all the drivers within capsule + // + SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode)); + MemMapNode.Header.Type = HARDWARE_DEVICE_PATH; + MemMapNode.Header.SubType = HW_MEMMAP_DP; + MemMapNode.MemoryType = EfiBootServicesCode; + MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader; + MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1); + + DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header); + if (DriverDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) { + if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) { + // + // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER + // + DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index]; + } else { + DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index]; + } + + Status = gBS->LoadImage( + FALSE, + gImageHandle, + DriverDevicePath, + (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index], + DriverLen, + &ImageHandle + ); + if (EFI_ERROR(Status)) { + goto EXIT; + } + + Status = gBS->StartImage( + ImageHandle, + &ExitDataSize, + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status)); + goto EXIT; + } + } + + // + // Connnect all again to connect drivers within capsule + // + if (FmpCapsuleHeader->EmbeddedDriverCount > 0) { + EfiBootManagerConnectAll(); + } + + // + // 3. Route payload to right FMP instance + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + + if (!EFI_ERROR(Status)) { + for(Index1 = 0; Index1 < NumberOfHandles; Index1++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index1], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + TempFmpImageInfo = FmpImageInfoBuf; + for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) { + // + // Check all the payload entry in capsule payload list + // + for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) { + ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); + if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) && + ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) { + AbortReason = NULL; + if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + if(ImageHeader->UpdateHardwareInstance != 0){ + // + // FMP Version is >=2 & UpdateHardwareInstance Skip 2 case + // 1. FMP Image info Version < 3 + // 2. HardwareInstance doesn't match + // + if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION || + ImageHeader->UpdateHardwareInstance != TempFmpImageInfo->HardwareInstance) { + continue; + } + } + Image = (UINT8 *)(ImageHeader + 1); + } else { + // + // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId. + // Header should exclude UpdateHardwareInstance field + // + Image = (UINT8 *)ImageHeader + ((EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *) 0)->UpdateHardwareInstance; + } + + if (ImageHeader->UpdateVendorCodeSize == 0) { + Status = Fmp->SetImage( + Fmp, + TempFmpImageInfo->ImageIndex, // ImageIndex + Image, // Image + ImageHeader->UpdateImageSize, // ImageSize + NULL, // VendorCode + Update_Image_Progress, // Progress + &AbortReason // AbortReason + ); + } else { + Status = Fmp->SetImage( + Fmp, + TempFmpImageInfo->ImageIndex, // ImageIndex + Image, // Image + ImageHeader->UpdateImageSize, // ImageSize + Image + ImageHeader->UpdateImageSize, // VendorCode + Update_Image_Progress, // Progress + &AbortReason // AbortReason + ); + } + if (AbortReason != NULL) { + DEBUG ((EFI_D_ERROR, "%s\n", AbortReason)); + FreePool(AbortReason); + } + // + // Update EsrtEntry For V1, V2 FMP instance. V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface + // + if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION && EsrtProtocol != NULL) { + StatusEsrt = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + if (!EFI_ERROR(StatusEsrt)){ + if (!EFI_ERROR(Status)) { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + } else { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + EsrtEntry.LastAttemptVersion = 0; + EsrtProtocol->UpdateEsrtEntry(&EsrtEntry); + } + } + } + } + // + // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version + // + TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize); + } + FreePool(FmpImageInfoBuf); + } + } + +EXIT: + + if (HandleBuffer != NULL) { + FreePool(HandleBuffer); + } + + if (DriverDevicePath != NULL) { + FreePool(DriverDevicePath); + } + + return Status; +} + + +/** + Those capsules supported by the firmwares. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is supported by firmware. + @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware. + @retval EFI_INVALID_PARAMETER Input capsule layout is not correct + +**/ +EFI_STATUS +EFIAPI +SupportCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; + + // + // We may need to add Hook point for OEM known Guids like gFwUpdateDisplayCapsuleGuid + // + + // + // check Display Capsule Guid + // + if (CompareGuid(&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + return EFI_SUCCESS; + } + + if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + // + // Check layout of FMP capsule + // + return ValidateFmpCapsule(CapsuleHeader); + } + + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + if (!EFI_ERROR(Status)) { + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + + +/** + The firmware implements to process the capsule image. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Process Capsule Image successfully. + @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. + @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. + @retval EFI_OUT_OF_RESOURCES Not enough memory. +**/ +EFI_STATUS +EFIAPI +ProcessCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + UINT32 Length; + EFI_FIRMWARE_VOLUME_HEADER *FvImage; + EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage; + EFI_STATUS Status; + EFI_STATUS StatusEsrt; + EFI_HANDLE FvProtocolHandle; + UINT32 FvAlignment; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + UINT32 AttemptStatus; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + + FvImage = NULL; + ProcessedFvImage = NULL; + Status = EFI_SUCCESS; + AttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage1\n")); + + if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) { + return EFI_UNSUPPORTED; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage2\n")); + + // + // Display image in firmware update display capsule + // + if (CompareGuid(&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + return DisplayCapsuleImage( + (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1), + (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER))); + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage3\n")); + + // + // Check FMP capsule layout + // + if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){ + Status = ValidateFmpCapsule(CapsuleHeader); + if (EFI_ERROR(Status)) { + return Status; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage4\n")); + + // + // Press EFI FMP Capsule + // + Status = ProcessFmpCapsuleImage(CapsuleHeader); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage5\n")); + + // + // Indicate to sync Esrt on next boot + // + PcdSetBool(PcdEsrtSyncFmp, TRUE); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage6\n")); + + return Status; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage7\n")); + + // + // Other non-FMP capsule handler + // + // Skip the capsule header, move to the Firware Volume + // + FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; + + while (Length != 0) { + // + // Point to the next firmware volume header, and then + // call the DXE service to process it. + // + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage8\n")); + if (FvImage->FvLength > (UINTN) Length) { + // + // Notes: need to stuff this status somewhere so that the + // error can be detected at OS runtime + // + Status = EFI_VOLUME_CORRUPTED; + break; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage9\n")); + + FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16); + // + // FvAlignment must be more than 8 bytes required by FvHeader structure. + // + if (FvAlignment < 8) { + FvAlignment = 8; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage10\n")); + // + // Check FvImage Align is required. + // + if (((UINTN) FvImage % FvAlignment) == 0) { + ProcessedFvImage = FvImage; + } else { + // + // Allocate new aligned buffer to store FvImage. + // + ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment); + if (ProcessedFvImage == NULL) { + AttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + break; + } + CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength); + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage11\n")); + + Status = gDS->ProcessFirmwareVolume ( + (VOID *) ProcessedFvImage, + (UINTN) ProcessedFvImage->FvLength, + &FvProtocolHandle + ); + if (EFI_ERROR (Status)) { + AttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + break; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage12\n")); + + // + // Call the dispatcher to dispatch any drivers from the produced firmware volume + // + gDS->Dispatch (); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage13\n")); + // + // On to the next FV in the capsule + // + Length -= (UINT32) FvImage->FvLength; + FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength); + } + + // + // Update corresponding ESRT entry LastAttemp Status + // + StatusEsrt = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage14\n")); + if (!EFI_ERROR(StatusEsrt)) { + StatusEsrt = EsrtManagement->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage15\n")); + if (!EFI_ERROR(StatusEsrt)){ + // + // Update version can't be get from FV, set LastAttemptVersion to zero after a failed update + // + if (AttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) { + EsrtEntry.LastAttemptVersion = 0; + } + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage16\n")); + EsrtEntry.LastAttemptStatus = AttemptStatus; + EsrtManagement->UpdateEsrtEntry(&EsrtEntry); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage17\n")); + } + } + + // + // Indicate to sync Esrt on next boot + // + PcdSetBool(PcdEsrtSyncFmp, TRUE); + DEBUG ((DEBUG_INFO, "ProcessCapsuleImage18\n")); + + return Status; +} + + +/** + The constructor function of DxeCapsuleLib. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor successfully . + @retval Other value The constructor can't add string package. + +**/ +EFI_STATUS +EFIAPI +DxeCapsuleLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf new file mode 100644 index 0000000000..7441faa3f4 --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf @@ -0,0 +1,62 @@ +## @file +# Component description file for Capsule Boottime Library +# +# +# Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeCapsuleLib + FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = DxeCapsuleLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DxeCapsuleLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + #BpCommonPkg/BpCommonPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + Vlv2TbltDevicePkg/PlatformPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + DxeServicesTableLib + UefiBootServicesTableLib + UefiBootManagerLib + DevicePathLib + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp + +[Protocols] + gEsrtManagementProtocolGuid ## CONSUMES + gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiCapsuleGuid ## SOMETIMES_CONSUMED ## GUID + gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID + gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID diff --git a/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeCapsuleLib.c b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeCapsuleLib.c new file mode 100644 index 0000000000..604cb3db02 --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeCapsuleLib.c @@ -0,0 +1,1038 @@ +/** @file + Capsule Runtime Library instance to update capsule image to flash. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL; +BOOLEAN mIsVirtualAddrConverted = FALSE; + + +/** + Function indicate the current completion progress of the firmware + update. Platform may override with own specific progress function. + + @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update + + @retval EFI_SUCESS Input capsule is a correct FMP capsule. +**/ +EFI_STATUS +EFIAPI +Update_Image_Progress ( + IN UINTN Completion +) +{ + return EFI_SUCCESS; +} + +/** + Validate Fmp capsules layout. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is a correct FMP capsule. + @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule. +**/ +EFI_STATUS +ValidateFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT8 *EndOfCapsule; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; + UINT8 *EndOfPayload; + UINT64 *ItemOffsetList; + UINT32 ItemNum; + UINTN Index; + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; + + if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { + return EFI_INVALID_PARAMETER; + } + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + + ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + + if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) { + // + // No payload element + // + if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) { + return EFI_SUCCESS; + } else { + return EFI_INVALID_PARAMETER; + } + } + + if (FmpCapsuleHeader->PayloadItemCount != 0) { + // + // Check if the last payload is within capsule image range + // + ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]); + EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize; + } else { + // + // No driver & payload element in FMP + // + EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1); + } + + if (EndOfPayload != EndOfCapsule) { + return EFI_INVALID_PARAMETER; + } + + // + // All the address in ItemOffsetList must be stored in ascending order + // + if (ItemNum >= 2) { + for (Index = 0; Index < ItemNum - 1; Index++) { + if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) { + return EFI_INVALID_PARAMETER; + } + } + } + + return EFI_SUCCESS; +} + +/** + Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer + is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt + buffer is passed in it will be used if it is big enough. + + @param BmpImage Pointer to BMP file + @param BmpImageSize Number of bytes in BmpImage + @param GopBlt Buffer containing GOP version of BmpImage. + @param GopBltSize Size of GopBlt in bytes. + @param PixelHeight Height of GopBlt/BmpImage in pixels + @param PixelWidth Width of GopBlt/BmpImage in pixels + + @retval EFI_SUCCESS GopBlt and GopBltSize are returned. + @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image + @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough. + GopBltSize will contain the required size. + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate. + +**/ +static +EFI_STATUS +ConvertBmpToGopBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT VOID **GopBlt, + IN OUT UINTN *GopBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINT64 BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + BOOLEAN IsAllocated; + + BmpHeader = (BMP_IMAGE_HEADER *) BmpImage; + + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') { + return EFI_UNSUPPORTED; + } + + // + // Doesn't support compress. + // + if (BmpHeader->CompressionType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER)); + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + // + // Calculate the BltBuffer needed size. + // + BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight); + // + // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow + // + if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + return EFI_UNSUPPORTED; + } + BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + IsAllocated = FALSE; + if (*GopBlt == NULL) { + // + // GopBlt is not allocated by caller. + // + *GopBltSize = (UINTN) BltBufferSize; + *GopBlt = AllocatePool (*GopBltSize); + IsAllocated = TRUE; + if (*GopBlt == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // GopBlt has been allocated by caller. + // + if (*GopBltSize < (UINTN) BltBufferSize) { + *GopBltSize = (UINTN) BltBufferSize; + return EFI_BUFFER_TOO_SMALL; + } + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + + // + // Convert image from BMP to Blt buffer format + // + BltBuffer = *GopBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Convert 1-bit (2 colors) BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt--; + Width--; + break; + + case 4: + // + // Convert 4-bit (16 colors) BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + break; + + case 8: + // + // Convert 8-bit (256 colors) BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + // + // It is 24-bit BMP. + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + case 32: + // + // it is 32-bit BMP. Skip pixel's highest byte + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image++; + break; + + default: + // + // Other bit format BMP is not supported. + // + if (IsAllocated) { + FreePool (*GopBlt); + *GopBlt = NULL; + } + return EFI_UNSUPPORTED; + break; + }; + + } + + ImageIndex = (UINTN) (Image - ImageHeader); + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return EFI_SUCCESS; +} + + +/** + Those capsules supported by the firmwares. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is supported by firmware. + @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware. +**/ +EFI_STATUS +DisplayCapsuleImage ( + IN DISPLAY_DISPLAY_PAYLOAD *ImagePayload, + IN UINTN PayloadSize + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINTN BltSize; + UINTN Height; + UINTN Width; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + + // + // Only Support Bitmap by now + // + if (ImagePayload->ImageType != 0) { + return EFI_UNSUPPORTED; + } + + // + // Try to open GOP + // + Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) { + return EFI_UNSUPPORTED; + } + + Blt = NULL; + Width = 0; + Height = 0; + Status = ConvertBmpToGopBlt ( + ImagePayload + 1, + PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD), + (VOID **)&Blt, + &BltSize, + &Height, + &Width + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GraphicsOutput->Blt ( + GraphicsOutput, + Blt, + EfiBltBufferToVideo, + 0, + 0, + (UINTN) ImagePayload->OffsetX, + (UINTN) ImagePayload->OffsetY, + Width, + Height, + Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + + FreePool(Blt); + + return Status; +} + +/** + Process Firmware management protocol data capsule. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Process Capsule Image successfully. + @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. + @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. + @retval EFI_OUT_OF_RESOURCES Not enough memory. +**/ +EFI_STATUS +ProcessFmpCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_STATUS StatusEsrt; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT8 *EndOfCapsule; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; + UINT8 *Image; + EFI_HANDLE ImageHandle; + UINT64 *ItemOffsetList; + UINT32 ItemNum; + UINTN Index; + UINTN ExitDataSize; + EFI_HANDLE *HandleBuffer; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN NumberOfHandles; + UINTN DescriptorSize; + UINT8 FmpImageInfoCount; + UINT32 FmpImageInfoDescriptorVer; + UINTN ImageInfoSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + CHAR16 *AbortReason; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo; + UINTN DriverLen; + UINTN Index1; + UINTN Index2; + MEMMAP_DEVICE_PATH MemMapNode; + EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath; + ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + + Status = EFI_SUCCESS; + HandleBuffer = NULL; + ExitDataSize = 0; + DriverDevicePath = NULL; + EsrtProtocol = NULL; + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; + + if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { + return EFI_INVALID_PARAMETER; + } + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + + ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + + // + // capsule in which driver count and payload count are both zero is not processed. + // + if (ItemNum == 0) { + return EFI_SUCCESS; + } + + // + // Update corresponding ESRT entry LastAttemp Status + // + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); + + // + // 1. ConnectAll to ensure + // All the communication protocol required by driver in capsule installed + // All FMP protocols are installed + // + EfiBootManagerConnectAll(); + + + // + // 2. Try to load & start all the drivers within capsule + // + SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode)); + MemMapNode.Header.Type = HARDWARE_DEVICE_PATH; + MemMapNode.Header.SubType = HW_MEMMAP_DP; + MemMapNode.MemoryType = EfiBootServicesCode; + MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader; + MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1); + + DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header); + if (DriverDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) { + if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) { + // + // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER + // + DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index]; + } else { + DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index]; + } + + Status = gBS->LoadImage( + FALSE, + gImageHandle, + DriverDevicePath, + (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index], + DriverLen, + &ImageHandle + ); + if (EFI_ERROR(Status)) { + goto EXIT; + } + + Status = gBS->StartImage( + ImageHandle, + &ExitDataSize, + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status)); + goto EXIT; + } + } + + // + // Connnect all again to connect drivers within capsule + // + if (FmpCapsuleHeader->EmbeddedDriverCount > 0) { + EfiBootManagerConnectAll(); + } + + // + // 3. Route payload to right FMP instance + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + + if (!EFI_ERROR(Status)) { + for(Index1 = 0; Index1 < NumberOfHandles; Index1++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index1], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + TempFmpImageInfo = FmpImageInfoBuf; + for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) { + // + // Check all the payload entry in capsule payload list + // + for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) { + ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); + if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) && + ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) { + AbortReason = NULL; + if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + if(ImageHeader->UpdateHardwareInstance != 0){ + // + // FMP Version is >=2 & UpdateHardwareInstance Skip 2 case + // 1. FMP Image info Version < 3 + // 2. HardwareInstance doesn't match + // + if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION || + ImageHeader->UpdateHardwareInstance != TempFmpImageInfo->HardwareInstance) { + continue; + } + } + Image = (UINT8 *)(ImageHeader + 1); + } else { + // + // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId. + // Header should exclude UpdateHardwareInstance field + // + Image = (UINT8 *)ImageHeader + ((EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *) 0)->UpdateHardwareInstance; + } + + if (ImageHeader->UpdateVendorCodeSize == 0) { + Status = Fmp->SetImage( + Fmp, + TempFmpImageInfo->ImageIndex, // ImageIndex + Image, // Image + ImageHeader->UpdateImageSize, // ImageSize + NULL, // VendorCode + Update_Image_Progress, // Progress + &AbortReason // AbortReason + ); + } else { + Status = Fmp->SetImage( + Fmp, + TempFmpImageInfo->ImageIndex, // ImageIndex + Image, // Image + ImageHeader->UpdateImageSize, // ImageSize + Image + ImageHeader->UpdateImageSize, // VendorCode + Update_Image_Progress, // Progress + &AbortReason // AbortReason + ); + } + if (AbortReason != NULL) { + DEBUG ((EFI_D_ERROR, "%s\n", AbortReason)); + FreePool(AbortReason); + } + // + // Update EsrtEntry For V1, V2 FMP instance. V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface + // + if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION && EsrtProtocol != NULL) { + StatusEsrt = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + if (!EFI_ERROR(StatusEsrt)){ + if (!EFI_ERROR(Status)) { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + } else { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + EsrtEntry.LastAttemptVersion = 0; + EsrtProtocol->UpdateEsrtEntry(&EsrtEntry); + } + } + } + } + // + // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version + // + TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize); + } + FreePool(FmpImageInfoBuf); + } + } + +EXIT: + + if (HandleBuffer != NULL) { + FreePool(HandleBuffer); + } + + if (DriverDevicePath != NULL) { + FreePool(DriverDevicePath); + } + + return Status; +} + + +/** + Those capsules supported by the firmwares. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Input capsule is supported by firmware. + @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware. + @retval EFI_INVALID_PARAMETER Input capsule layout is not correct + +**/ +EFI_STATUS +EFIAPI +SupportCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtArray; + ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; + UINTN i; + + // + // We may need to add Hook point for OEM known Guids like gFwUpdateDisplayCapsuleGuid + // + + // + // check Display Capsule Guid + // + if (CompareGuid(&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + return EFI_SUCCESS; + } + + if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + // + // Check layout of FMP capsule + // + return ValidateFmpCapsule(CapsuleHeader); + } + + // + // Runtime directly check EsrtTable by virtual address + // + if (mIsVirtualAddrConverted) { + if(mEsrtTable == NULL) { + // + // Esrt table not found + // + return EFI_UNSUPPORTED; + } + + EsrtArray = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1); + for (i = 0 ; i < mEsrtTable->FwResourceCount ; i++){ + if (CompareGuid(&(EsrtArray[i].FwClass), &CapsuleHeader->CapsuleGuid)){ + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; + } + + // + // Boot Time check + // Before ReadytoBoot Event + // + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + if (!EFI_ERROR(Status)) { + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + + +/** + The firmware implements to process the capsule image. + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Process Capsule Image successfully. + @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. + @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. + @retval EFI_OUT_OF_RESOURCES Not enough memory. +**/ +EFI_STATUS +EFIAPI +ProcessCapsuleImage ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + UINT32 Length; + EFI_FIRMWARE_VOLUME_HEADER *FvImage; + EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage; + EFI_STATUS Status; + EFI_STATUS StatusEsrt; + EFI_HANDLE FvProtocolHandle; + UINT32 FvAlignment; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + UINT32 AttemptStatus; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + + FvImage = NULL; + ProcessedFvImage = NULL; + Status = EFI_SUCCESS; + AttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + + if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) { + return EFI_UNSUPPORTED; + } + + // + // Display image in firmware update display capsule + // + if (CompareGuid(&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { + return DisplayCapsuleImage( + (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1), + (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER))); + } + + // + // Check FMP capsule layout + // + if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){ + Status = ValidateFmpCapsule(CapsuleHeader); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Press EFI FMP Capsule + // + Status = ProcessFmpCapsuleImage(CapsuleHeader); + // + // Indicate to sync Esrt on next boot + // + PcdSetBool(PcdEsrtSyncFmp, TRUE); + + return Status; + } + + // + // Other non-FMP capsule handler + // + // Skip the capsule header, move to the Firware Volume + // + FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); + Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; + + while (Length != 0) { + // + // Point to the next firmware volume header, and then + // call the DXE service to process it. + // + if (FvImage->FvLength > (UINTN) Length) { + // + // Notes: need to stuff this status somewhere so that the + // error can be detected at OS runtime + // + Status = EFI_VOLUME_CORRUPTED; + break; + } + + FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16); + // + // FvAlignment must be more than 8 bytes required by FvHeader structure. + // + if (FvAlignment < 8) { + FvAlignment = 8; + } + // + // Check FvImage Align is required. + // + if (((UINTN) FvImage % FvAlignment) == 0) { + ProcessedFvImage = FvImage; + } else { + // + // Allocate new aligned buffer to store FvImage. + // + ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment); + if (ProcessedFvImage == NULL) { + AttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + break; + } + CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength); + } + + Status = gDS->ProcessFirmwareVolume ( + (VOID *) ProcessedFvImage, + (UINTN) ProcessedFvImage->FvLength, + &FvProtocolHandle + ); + if (EFI_ERROR (Status)) { + AttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + break; + } + + // + // Call the dispatcher to dispatch any drivers from the produced firmware volume + // + gDS->Dispatch (); + // + // On to the next FV in the capsule + // + Length -= (UINT32) FvImage->FvLength; + FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength); + } + + // + // Update corresponding ESRT entry LastAttemp Status + // + StatusEsrt = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + if (!EFI_ERROR(StatusEsrt)) { + StatusEsrt = EsrtManagement->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &EsrtEntry); + if (!EFI_ERROR(StatusEsrt)){ + // + // Update version can't be get from FV, set LastAttemptVersion to zero after a failed update + // + if (AttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) { + EsrtEntry.LastAttemptVersion = 0; + } + EsrtEntry.LastAttemptStatus = AttemptStatus; + EsrtManagement->UpdateEsrtEntry(&EsrtEntry); + } + } + + // + // Indicate to sync Esrt on next boot + // + PcdSetBool(PcdEsrtSyncFmp, TRUE); + + return Status; +} + + +/** + Convert EsrtTable physical address to virtual address + + @param CapsuleHeader Points to a capsule header. + + @retval EFI_SUCESS Process Capsule Image successfully. + @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. + @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. + @retval EFI_OUT_OF_RESOURCES Not enough memory. +**/ +VOID +EFIAPI +DxeCapsuleLibVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN i; + EFI_CONFIGURATION_TABLE *ConfigEntry; + + // + // Get Esrt table first + // + ConfigEntry = gST->ConfigurationTable; + for (i = 0 ; i < gST->NumberOfTableEntries ; i++) { + if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) { + break; + } + ConfigEntry++; + } + + // + // If no Esrt table installed in Configure Table + // + if (i < gST->NumberOfTableEntries) { + // + // Search Esrt to check given capsule is qualified + // + mEsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable; + + // + // Update protocol pointer to Esrt Table. + // + gRT->ConvertPointer (0x00, (VOID**) &(mEsrtTable)); + } + + mIsVirtualAddrConverted = TRUE; + +} + + +/** + The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor successfully . + @retval Other value The constructor can't add string package. + +**/ +EFI_STATUS +EFIAPI +DxeCapsuleLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + // + // Make sure we can handle virtual address changes. + // + Event = NULL; + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + DxeCapsuleLibVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf new file mode 100644 index 0000000000..8876b0dd01 --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf @@ -0,0 +1,64 @@ +## @file +# Component description file for Capsule Runtime Library +# +# +# Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeCapsuleLib + FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER + CONSTRUCTOR = DxeCapsuleLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DxeCapsuleLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + #BpCommonPkg/BpCommonPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + Vlv2TbltDevicePkg/PlatformPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + DxeServicesTableLib + UefiBootServicesTableLib + UefiBootManagerLib + DevicePathLib + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp + +[Protocols] + gEsrtManagementProtocolGuid ## CONSUMES + gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiCapsuleGuid ## SOMETIMES_CONSUMED ## GUID + gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID + gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID + gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID + gEfiEventVirtualAddressChangeGuid ## CONSUMES \ No newline at end of file diff --git a/Vlv2TbltDevicePkg/Library/FlashDeviceLib/FlashDeviceLib.c b/Vlv2TbltDevicePkg/Library/FlashDeviceLib/FlashDeviceLib.c index afb12c90fb..80520ef921 100644 --- a/Vlv2TbltDevicePkg/Library/FlashDeviceLib/FlashDeviceLib.c +++ b/Vlv2TbltDevicePkg/Library/FlashDeviceLib/FlashDeviceLib.c @@ -78,11 +78,11 @@ SpiFlashBlockErase ( UINT32 SpiAddress; SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase; - SectorSize = SECTOR_SIZE_64KB; + SectorSize = SECTOR_SIZE_4KB; while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) { Status = mSpiProtocol->Execute ( mSpiProtocol, - SPI_BERASE, + SPI_SERASE, SPI_WREN, FALSE, TRUE, diff --git a/Vlv2TbltDevicePkg/Library/FlashDeviceLib/SpiChipDefinitions.h b/Vlv2TbltDevicePkg/Library/FlashDeviceLib/SpiChipDefinitions.h index 15bd1e0254..a3f178fcd8 100644 --- a/Vlv2TbltDevicePkg/Library/FlashDeviceLib/SpiChipDefinitions.h +++ b/Vlv2TbltDevicePkg/Library/FlashDeviceLib/SpiChipDefinitions.h @@ -16,7 +16,7 @@ #include -#define FLASH_SIZE 0x300000 +#define FLASH_SIZE 0x400000 #define FLASH_DEVICE_BASE_ADDRESS (0xFFFFFFFF-FLASH_SIZE+1) // diff --git a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.c b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.c index 2334c95a2c..1a3a306c7a 100644 --- a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.c +++ b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.c @@ -45,6 +45,7 @@ Abstract: #include #include #include +#include EFI_GUID *ConnectDriverTable[] = { &gEfiMmioDeviceProtocolGuid, @@ -779,6 +780,43 @@ UpdateConsoleResolution( return; } + +VOID +EFIAPI +PlatformBootManagerBeforeConsole ( + VOID + ) +{ + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + EFI_BOOT_MODE BootMode; + EFI_STATUS Status; + + // + // Require to sync ESRT from FMP in flash update boot path + // + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + if (EFI_ERROR(Status)) { + EsrtManagement = NULL; + } + + if (EsrtManagement != NULL) { + BootMode = GetBootModeHob (); + DEBUG ((DEBUG_INFO, "esrtesrt!\n")); + if (BootMode == BOOT_ON_FLASH_UPDATE) { + PcdSetBool(PcdEsrtSyncFmp, TRUE); + } + + // + // Lock ESRT cache repository before EndofDxe if ESRT sync is not needed + // + if (PcdGetBool(PcdEsrtSyncFmp) == FALSE) { + EsrtManagement->LockEsrtRepository(); + } + } +} + + + /** Connect the predefined platform default console device. Always try to find and enable the vga device if have. @@ -1616,6 +1654,7 @@ PlatformBdsPolicyBehavior ( UINT16 *BootOrder; UINTN BootOrderSize; UINT32 DxeGpioValue; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; Timeout = PcdGet16 (PcdPlatformBootTimeOut); if (Timeout > 10 ) { @@ -1739,6 +1778,11 @@ PlatformBdsPolicyBehavior ( } } + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + if (EFI_ERROR(Status)) { + EsrtManagement = NULL; + } + switch (BootMode) { case BOOT_WITH_MINIMAL_CONFIGURATION: @@ -1909,12 +1953,25 @@ PlatformBdsPolicyBehavior ( } } + // + // Always sync ESRT Cache from FMP Instances after connect all and before capsule process + // + if (EsrtManagement != NULL) { + EsrtManagement->SyncEsrtFmp(); + PcdSetBool(PcdEsrtSyncFmp, FALSE); + } + // // Close boot script and install ready to lock // InstallReadyToLock (); - ProcessCapsules (BOOT_ON_FLASH_UPDATE); + + PlatformBootManagerProcessCapsules(); + + + PlatformBdsLockNonUpdatableFlash (); + break; case BOOT_IN_RECOVERY_MODE: diff --git a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.h b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.h index d7572435ed..9202331d84 100644 --- a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.h +++ b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/BdsPlatform.h @@ -43,6 +43,7 @@ Abstract: #include #include #include +#include #include #include #include @@ -450,6 +451,29 @@ BdsDeleteAllInvalidEfiBootOption ( VOID ); +/** + + This routine is called to see if there are any capsules we need to process. + If the boot mode is not UPDATE, then we do nothing. Otherwise find the + capsule HOBS and produce firmware volumes for them via the DXE service. + Then call the dispatcher to dispatch drivers from them. Finally, check + the status of the updates. + + This function should be called by BDS in case we need to do some + sort of processing even if there is no capsule to process. We + need to do this if an earlier update went away and we need to + clear the capsule variable so on the next reset PEI does not see it and + think there is a capsule available. + + @retval EFI_INVALID_PARAMETER boot mode is not correct for an update + @retval EFI_SUCCESS There is no error when processing capsule + +**/ +EFI_STATUS +EFIAPI +PlatformBootManagerProcessCapsules ( + VOID + ); #define ONE_SECOND 10000000 #define FRONT_PAGE_KEY_CONTINUE 0x1000 diff --git a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/Capsules.c b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/Capsules.c new file mode 100644 index 0000000000..f036c09ce7 --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/Capsules.c @@ -0,0 +1,304 @@ +/** @file + BDS routines to handle capsules. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + + This routine is called to see if there are any capsules we need to process. + If the boot mode is not UPDATE, then we do nothing. Otherwise find the + capsule HOBS and produce firmware volumes for them via the DXE service. + Then call the dispatcher to dispatch drivers from them. Finally, check + the status of the updates. + + This function should be called by BDS in case we need to do some + sort of processing even if there is no capsule to process. We + need to do this if an earlier update went away and we need to + clear the capsule variable so on the next reset PEI does not see it and + think there is a capsule available. + + @retval EFI_INVALID_PARAMETER boot mode is not correct for an update + @retval EFI_SUCCESS There is no error when processing capsule + +**/ +EFI_STATUS +EFIAPI +PlatformBootManagerProcessCapsules ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS HobPointer; + EFI_CAPSULE_HEADER *CapsuleHeader; + UINT32 Size; + UINT32 CapsuleNumber; + UINT32 CapsuleTotalNumber; + EFI_CAPSULE_TABLE *CapsuleTable; + UINT32 Index; + UINT32 CacheIndex; + UINT32 CacheNumber; + VOID **CapsulePtr; + VOID **CapsulePtrCache; + EFI_GUID *CapsuleGuidCache; + BOOLEAN ColdReboot; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + + CapsuleNumber = 0; + CapsuleTotalNumber = 0; + CacheIndex = 0; + CacheNumber = 0; + ColdReboot = FALSE; + CapsulePtr = NULL; + CapsulePtrCache = NULL; + CapsuleGuidCache = NULL; + EsrtManagement = NULL; + + + // + // We don't do anything else if the boot mode is not flash-update + // + ASSERT (GetBootModeHob () == BOOT_ON_FLASH_UPDATE); + + Status = EFI_SUCCESS; + // + // Find all capsule images from hob + // + HobPointer.Raw = GetHobList (); + while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { + CapsuleTotalNumber ++; + HobPointer.Raw = GET_NEXT_HOB (HobPointer); + } + + if (CapsuleTotalNumber == 0) { + // + // We didn't find a hob, so had no errors. + // + return EFI_SUCCESS; + } + + // + // Init temp Capsule Data table. + // + CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); + ASSERT (CapsulePtr != NULL); + CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); + ASSERT (CapsulePtrCache != NULL); + CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber); + ASSERT (CapsuleGuidCache != NULL); + + // + // Find all capsule images from hob + // + HobPointer.Raw = GetHobList (); + while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { + CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress; + HobPointer.Raw = GET_NEXT_HOB (HobPointer); + } + + // + //Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install + //capsuleTable to configure table with EFI_CAPSULE_GUID + // + + // + // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating + // System to have information persist across a system reset. EFI System Table must + // point to an array of capsules that contains the same CapsuleGuid value. And agents + // searching for this type capsule will look in EFI System Table and search for the + // capsule's Guid and associated pointer to retrieve the data. Two steps below describes + // how to sorting the capsules by the unique guid and install the array to EFI System Table. + // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an + // array for later sorting capsules by CapsuleGuid. + // + for (Index = 0; Index < CapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { + // + // For each capsule, we compare it with known CapsuleGuid in the CacheArray. + // If already has the Guid, skip it. Whereas, record it in the CacheArray as + // an additional one. + // + CacheIndex = 0; + while (CacheIndex < CacheNumber) { + if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) { + break; + } + CacheIndex++; + } + if (CacheIndex == CacheNumber) { + CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID)); + } + } + } + + // + // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules + // whose guid is the same as it, and malloc memory for an array which preceding + // with UINT32. The array fills with entry point of capsules that have the same + // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install + // this array into EFI System Table, so that agents searching for this type capsule + // will look in EFI System Table and search for the capsule's Guid and associated + // pointer to retrieve the data. + // + CacheIndex = 0; + while (CacheIndex < CacheNumber) { + CapsuleNumber = 0; + for (Index = 0; Index < CapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { + if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) { + // + // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid. + // + CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader; + } + } + } + if (CapsuleNumber != 0) { + Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*); + CapsuleTable = AllocateRuntimePool (Size); + ASSERT (CapsuleTable != NULL); + CapsuleTable->CapsuleArrayNumber = CapsuleNumber; + CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*)); + Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable); + ASSERT_EFI_ERROR (Status); + } + CacheIndex++; + } + + + // + // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, if Windows UX capsule exist, process it first + // + for (Index = 0; Index < CapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0 + && CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) { + ProcessCapsuleImage (CapsuleHeader); + break; + } + } + + // + // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are + // recognized by platform. + // + for (Index = 0; Index < CapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0 + && !CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) { + // + // Call capsule library to process capsule image. + // + ProcessCapsuleImage (CapsuleHeader); + if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 || + CompareGuid(&CapsuleHeader->CapsuleGuid ,&gEfiFmpCapsuleGuid)) { + ColdReboot = TRUE; + } + } + } + + // + // Reboot System if required after all capsule processed + // + if (ColdReboot) { + + DEBUG ((DEBUG_INFO, "Cold Reset after process capsule!\n")); + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + CpuDeadLoop (); + } + + // + // Free the allocated temp memory space. + // + FreePool (CapsuleGuidCache); + FreePool (CapsulePtrCache); + FreePool (CapsulePtr); + + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + // + // Always sync ESRT Cache from FMP Instance after Connect All + // + if (!EFI_ERROR(Status)) { + // + // Reconnect all & sync ESRT from FMP + // + EfiBootManagerConnectAll (); + + Status = EsrtManagement->SyncEsrtFmp(); + } else { + Status = EFI_SUCCESS; + } + + return Status; +} + diff --git a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/PlatformBdsLib.inf b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/PlatformBdsLib.inf index ff5edc31c5..5778f697c6 100644 --- a/Vlv2TbltDevicePkg/Library/PlatformBdsLib/PlatformBdsLib.inf +++ b/Vlv2TbltDevicePkg/Library/PlatformBdsLib/PlatformBdsLib.inf @@ -38,6 +38,7 @@ BdsPlatform.h PlatformData.c PlatformBdsStrings.uni + Capsules.c [Packages] MdePkg/MdePkg.dec @@ -73,6 +74,7 @@ S3BootScriptLib SerialPortLib PchPlatformLib + UefiBootManagerLib [Protocols] gEfiFirmwareVolume2ProtocolGuid @@ -91,6 +93,7 @@ gEfiMmioDeviceProtocolGuid gEfiI2cMasterProtocolGuid gEfiI2cHostProtocolGuid + gEsrtManagementProtocolGuid ## SOMETIMES_CONSUME [Guids] gEfiMemoryTypeInformationGuid @@ -98,6 +101,7 @@ gEfiGlobalVariableGuid gEfiNormalSetupGuid gEfiPartTypeSystemPartGuid + gWindowsUxCapsuleGuid [Pcd] gPlatformModuleTokenSpaceGuid.PcdFlashFvRecovery2Base @@ -119,3 +123,5 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp + gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES diff --git a/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.c b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.c new file mode 100644 index 0000000000..ee2def8c80 --- /dev/null +++ b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.c @@ -0,0 +1,140 @@ +/** @file + Non-FMP ESRT Platform Driver to produce system firmware resource to ESRT + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "PlatformEsrtDxe.h" + + + +EFI_SYSTEM_RESOURCE_ENTRY EsrtTemplateBuf[] = { + // System Firmware Entry + { + SYSTEM_FW_CLASS_GUID, + ESRT_FW_TYPE_SYSTEMFIRMWARE, + 0x0001, + 0x0001, + 0x0000, + 0x0000, + LAST_ATTEMPT_STATUS_SUCCESS + } +}; + +UINTN EsrtCount = sizeof(EsrtTemplateBuf) / sizeof(EFI_SYSTEM_RESOURCE_ENTRY); + + +/** + Register all platform updatable firmware resourece to Esrt table + + @param[in] Event The Event that is being processed. + @param[in] Context The Event Context. + +**/ +EFI_STATUS +RegisterPlatformEsrtEntry() +{ + EFI_STATUS Status; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + UINTN Index; + + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + if (EFI_ERROR(Status)) { + return Status; + } + + for (Index = 0; Index < EsrtCount; Index++) { + Status = EsrtManagement->GetEsrtEntry( + &EsrtTemplateBuf[Index].FwClass, + &EsrtTemplateBuf[Index] + ); + if (Status == EFI_NOT_FOUND) { + // + // Init EsrtEntry for system firmware updatable resource + // + Status = EsrtManagement->RegisterEsrtEntry(&EsrtTemplateBuf[Index]); + } + } + + return Status; + +} + + +/** + Notify function for protocol ESRT management protocol. This is used to + register system firmware updatable resourece to Esrt table + + @param[in] Event The Event that is being processed. + @param[in] Context The Event Context. + +**/ +VOID +EFIAPI +PlatformEsrtNotifyFunction ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + Status = RegisterPlatformEsrtEntry(); + DEBUG ((EFI_D_INFO, "PlatformEsrtDxe Status = 0x%x\n", Status)); +} + + +EFI_STATUS +EFIAPI +PlatformEsrtDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + UINTN Index; + + for (Index = 0; Index < EsrtCount; Index++) { + EsrtTemplateBuf[Index].CapsuleFlags = PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag); + } + + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement); + if (!EFI_ERROR(Status)) { + // + // Directly Register Platform Updatable Resource + // + return RegisterPlatformEsrtEntry(); + } + + // + // Register Callback function for updating USB Rmrr address + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PlatformEsrtNotifyFunction, + NULL, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify( + &gEsrtManagementProtocolGuid, + Event, + &Registration + ); + + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.h b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.h new file mode 100644 index 0000000000..bcf1bc80be --- /dev/null +++ b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.h @@ -0,0 +1,32 @@ +/** @file + Header file for Non-FMP platform ESRT driver + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef _EFI_PLATFORM_ESRT_DXE_H_ +#define _EFI_PLATFORM_ESRT_DXE_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#endif // #ifndef _EFI_PLATFORM_ESRT_DXE_H_ diff --git a/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.inf b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.inf new file mode 100644 index 0000000000..6ee110542c --- /dev/null +++ b/Vlv2TbltDevicePkg/PlatformEsrt/PlatformEsrtDxe.inf @@ -0,0 +1,58 @@ +## @file +# Component description file for platform ESRT module +# +# +# Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformEsrtDxe + FILE_GUID = 0484EBBA-7D8F-48ae-8F98-A77E0961DEEA + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PlatformEsrtDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PlatformEsrtDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Vlv2TbltDevicePkg/PlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + PrintLib + PcdLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES + +[Protocols] + gEsrtManagementProtocolGuid ## CONSUMES + +[Guids] + gSystemFwClassGuid \ No newline at end of file diff --git a/Vlv2TbltDevicePkg/PlatformPkg.dec b/Vlv2TbltDevicePkg/PlatformPkg.dec index 642bcf92a3..ea84a93b1f 100644 --- a/Vlv2TbltDevicePkg/PlatformPkg.dec +++ b/Vlv2TbltDevicePkg/PlatformPkg.dec @@ -64,6 +64,8 @@ gFirmwareIdGuid = { 0x5e559c23, 0x1faa, 0x4ae1, { 0x8d, 0x4a, 0xc6, 0xcf, 0x02, 0x6c, 0x76, 0x6f } } gBmpImageGuid = { 0x878AC2CC, 0x5343, 0x46F2, { 0xB5, 0x63, 0x51, 0xF8, 0x9D, 0xAF, 0x56, 0xBA } } gOsSelectionVariableGuid = { 0x86843f56, 0x675d, 0x40a5, { 0x95, 0x30, 0xbc, 0x85, 0x83, 0x72, 0xf1, 0x03 } } + gFMPSampleUpdateImageInfoGuid = { 0xb9847c4e, 0xf5b6, 0x42dc, { 0xb6, 0xf4, 0xed, 0x44, 0x7, 0xb0, 0x67, 0x4c }} + gSystemFwClassGuid = { 0x819b858e, 0xc52c, 0x402f, { 0x80, 0xe1, 0x5b, 0x31, 0x1b, 0x6c, 0x19, 0x59 } } [Protocols] gEfiActiveBiosProtocolGuid = { 0xebbe2d1b, 0x1647, 0x4bda, { 0xab, 0x9a, 0x78, 0x63, 0xe3, 0x96, 0xd4, 0x1a } } @@ -155,6 +157,7 @@ gPlatformModuleTokenSpaceGuid.PcdTxeRomSize|0x003FF000|UINT32|0x4000000A gPlatformModuleTokenSpaceGuid.PcdBiosRomBase|0xFFC00000|UINT32|0x4000000B gPlatformModuleTokenSpaceGuid.PcdBiosRomSize|0x00400000|UINT32|0x4000000C + gPlatformModuleTokenSpaceGuid.PcdFlashMinEraseSize|0x1000|UINT32|0x70000007 [PcdsFeatureFlag] ## This PCD specifies whether StatusCode is reported via ISA Serial port. @@ -171,11 +174,16 @@ #new added feature for BIOS usb recovery gEfiIchTokenSpaceGuid.PcdEhciRecoveryEnabled|TRUE|BOOLEAN|0x00000026 + + gPlatformModuleTokenSpaceGuid.PcdFeatureRecoveryDisabled|FALSE|BOOLEAN|0x20005004 [PcdsDynamic,PcdsDynamicEx] gPlatformModuleTokenSpaceGuid.PcdInConfigMode|FALSE|BOOLEAN|0x80000001 gPlatformModuleTokenSpaceGuid.PcdConnectUSBKeyboardonWaitForKeyStroke|FALSE|BOOLEAN|0x80000002 gPlatformModuleTokenSpaceGuid.PcdEnableWatchdogSwSmiInputValue|0|UINT8|0x80000003 + ## Indicates platform to sync ESRT repository from FMP instances + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|TRUE|BOOLEAN|0x80000004 + # #device firmware update support # @@ -198,11 +206,11 @@ gEfiSpiProtocolGuid = { 0x1156efc6, 0xea32, 0x4396, { 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 }} gEfiGpioOperationProtocolGuid = { 0x38DDFE8F, 0x8991, 0x44AA, { 0x98, 0x89, 0x83, 0xF4, 0x91, 0x84, 0x65, 0xB0 }} gEfiEsrtOperationProtocolGuid = { 0x4549AB47, 0x6E60, 0x4293, { 0xB9, 0x1D, 0x31, 0xB6, 0x10, 0xAD, 0x80, 0x56 }} - + [Guids] gEfiFwDisplayCapsuleGuid = { 0x3b8c8162, 0x188c, 0x46a4, { 0xae, 0xc9, 0xbe, 0x43, 0xf1, 0xd6, 0x56, 0x97 } } gEfiFirmwareClassGuid = { 0xb122a262, 0x3551, 0x4f48, { 0x88, 0x92, 0x55, 0xf6, 0xc0, 0x61, 0x42, 0x90 } } gEfiDFUVerGuid = { 0x0dc73aed, 0xcbf6, 0x4a25, { 0xa6, 0x8d, 0x59, 0xc8, 0x0f, 0x44, 0xc7, 0xc3 } } gEfiEsrtTableGuid = { 0xb122a263, 0x3661, 0x4f68, { 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 } } gEfiCapsuleCrashLogVarGuid = { 0xf3ff1468, 0x04ba, 0x4966, { 0x9f, 0xb2, 0xe4, 0xa7, 0x90, 0x05, 0x46, 0x50 } } - gEfiCapsuleCrashGuid = { 0x0e1d2972, 0x65af, 0x4ac1, { 0xbf, 0xa3, 0xce, 0xf4, 0xab, 0x0c, 0x38, 0xfe } } + gEfiCapsuleCrashGuid = { 0x0e1d2972, 0x65af, 0x4ac1, { 0xbf, 0xa3, 0xce, 0xf4, 0xab, 0x0c, 0x38, 0xfe } } \ No newline at end of file diff --git a/Vlv2TbltDevicePkg/PlatformPkg.fdf b/Vlv2TbltDevicePkg/PlatformPkg.fdf index 3432904825..066cb75ba2 100644 --- a/Vlv2TbltDevicePkg/PlatformPkg.fdf +++ b/Vlv2TbltDevicePkg/PlatformPkg.fdf @@ -48,10 +48,10 @@ DEFINE FLASH_REGION_AZALIABIN_BASE = 0xFFD08000 !endif DEFINE FLASH_REGION_FVMAIN_OFFSET = 0x00110000 -DEFINE FLASH_REGION_FVMAIN_SIZE = 0x00215000 +DEFINE FLASH_REGION_FVMAIN_SIZE = 0x00210000 -DEFINE FLASH_REGION_FV_RECOVERY2_OFFSET = 0x00325000 -DEFINE FLASH_REGION_FV_RECOVERY2_SIZE = 0x0006B000 +DEFINE FLASH_REGION_FV_RECOVERY2_OFFSET = 0x00320000 +DEFINE FLASH_REGION_FV_RECOVERY2_SIZE = 0x00070000 DEFINE FLASH_REGION_FV_RECOVERY_OFFSET = 0x00390000 DEFINE FLASH_REGION_FV_RECOVERY_SIZE = 0x00070000 @@ -358,9 +358,13 @@ INF RuleOverride = BINARY $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET !if $(CAPSULE_ENABLE) == TRUE +!if $(DXE_ARCHITECTURE) == X64 INF MdeModulePkg/Universal/CapsulePei/CapsulePei.inf !if $(DXE_ARCHITECTURE) == "X64" INF MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf +!else +INF MdeModulePkg/Universal/CapsulePei/CapsulePei.inf +!endif !endif !endif @@ -719,6 +723,12 @@ FILE FREEFORM = 878AC2CC-5343-46F2-B563-51F89DAF56BA { !endif !endif +!if $(ESRT_ENABLE) == TRUE + INF MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf + INF $(PLATFORM_PACKAGE)/PlatformEsrt/PlatformEsrtDxe.inf + INF $(PLATFORM_PACKAGE)/FmpSample/FmpSample.inf +!endif + [FV.FVMAIN_COMPACT] BlockSize = $(FLASH_BLOCK_SIZE) FvAlignment = 16 @@ -738,8 +748,6 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE - - FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { !if $(LZMA_ENABLE) == TRUE # LZMA Compress @@ -782,7 +790,7 @@ READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE -[FV.Update_Data] +[FV.Bios_Update_Data] BlockSize = $(FLASH_BLOCK_SIZE) FvAlignment = 16 ERASE_POLARITY = 1 @@ -801,8 +809,8 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE -FILE RAW = 88888888-8888-8888-8888-888888888888 { - FD = Vlv +FILE FV_IMAGE = 4A538818-5AE0-4eb2-B2EB-488B23657022 { + SECTION FV_IMAGE = FVMAIN_COMPACT } [FV.BiosUpdateCargo] @@ -824,6 +832,17 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE +!if $(ESRT_ENABLE) == TRUE + INF $(PLATFORM_PACKAGE)/UpdateDriverDxe/UpdateDriverDxe.inf +!else + INF IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf +!endif +FILE RAW = 283FA2EE-532C-484d-9383-9F93B36F0B7E { + FV = Bios_Update_Data + } +FILE RAW = 98B8D59B-E8BA-48EE-98DD-C295392F1EDB { + Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini + } [FV.BiosUpdate] @@ -845,23 +864,33 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE +FILE FV_IMAGE = EDBEDF47-6EA3-4512-83C1-70F4769D4BDE { + SECTION GUIDED { + SECTION FV_IMAGE = BiosUpdateCargo + } + } + [Capsule.Capsule_Boot] -# -# gEfiCapsuleGuid supported by platform -# { 0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }} -# -CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 -CAPSULE_FLAGS = PersistAcrossReset +!if $(ESRT_ENABLE) == TRUE +CAPSULE_GUID = 819b858e-c52c-402f-80e1-5b311b6c1959 +!else +CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!endif + +CAPSULE_FLAGS = PersistAcrossReset, InitiateReset +OEM_CAPSULE_FLAGS = 0x0001 + CAPSULE_HEADER_SIZE = 0x20 FV = BiosUpdate [Capsule.Capsule_Reset] -# -# gEfiCapsuleGuid supported by platform -# { 0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }} -# -CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!if $(ESRT_ENABLE) == TRUE +CAPSULE_GUID = 819b858e-c52c-402f-80e1-5b311b6c1959 +!else +CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!endif + CAPSULE_FLAGS = PersistAcrossReset CAPSULE_HEADER_SIZE = 0x20 diff --git a/Vlv2TbltDevicePkg/PlatformPkgConfig.dsc b/Vlv2TbltDevicePkg/PlatformPkgConfig.dsc index db50b9322a..0ad8b4a538 100644 --- a/Vlv2TbltDevicePkg/PlatformPkgConfig.dsc +++ b/Vlv2TbltDevicePkg/PlatformPkgConfig.dsc @@ -1,97 +1,98 @@ -#/** @file -# platform configuration file. -# -# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
-# -# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -# -#**/ - -# -# TRUE is ENABLE. FASLE is DISABLE. -# - -# -# FSP selection -# -DEFINE MINNOW2_FSP_BUILD = FALSE - - -DEFINE SCSI_ENABLE = TRUE - - -# -# To enable extra configuration for clk gen -# -DEFINE CLKGEN_CONFIG_EXTRA_ENABLE=TRUE - -# -# Feature selection -# - -# -# Select system timer which is used to produce Timer Arch Protocol: -# TRUE - HPET timer is used. -# FALSE - 8254 timer is used. -# -DEFINE USE_HPET_TIMER = FALSE - - -# -# Feature selection -# - -DEFINE TPM_ENABLED = FALSE - -DEFINE ACPI50_ENABLE = TRUE -DEFINE PERFORMANCE_ENABLE = FALSE - - -DEFINE LFMA_ENABLE = FALSE # Load module at fixed address feature -DEFINE DXE_COMPRESS_ENABLE = TRUE -DEFINE DXE_CRC32_SECTION_ENABLE = TRUE -DEFINE SSE2_ENABLE = FALSE - -DEFINE SECURE_BOOT_ENABLE = TRUE -DEFINE USER_IDENTIFICATION_ENABLE = FALSE -DEFINE VARIABLE_INFO_ENABLE = FALSE -DEFINE S3_ENABLE = TRUE -DEFINE CAPSULE_ENABLE = FALSE -DEFINE CAPSULE_RESET_ENABLE = TRUE - -DEFINE GOP_DRIVER_ENABLE = TRUE -DEFINE DATAHUB_ENABLE = TRUE -DEFINE DATAHUB_STATUS_CODE_ENABLE = TRUE -DEFINE USB_ENABLE = TRUE - -DEFINE ISA_SERIAL_STATUS_CODE_ENABLE = TRUE -DEFINE USB_SERIAL_STATUS_CODE_ENABLE = FALSE -DEFINE RAM_SERIAL_STATUS_CODE_ENABLE = FALSE - -DEFINE ENBDT_S3_SUPPORT = TRUE - -DEFINE LZMA_ENABLE = TRUE -DEFINE S4_ENABLE = TRUE -DEFINE NETWORK_ENABLE = TRUE -DEFINE NETWORK_IP6_ENABLE = TRUE -DEFINE NETWORK_ISCSI_ENABLE = FALSE -DEFINE NETWORK_VLAN_ENABLE = FALSE - -DEFINE SATA_ENABLE = TRUE -DEFINE PCIESC_ENABLE = TRUE - -# -# Enable source level debug default -# -DEFINE SOURCE_DEBUG_ENABLE = FALSE - - - - +#/** @file +# platform configuration file. +# +# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +# +# TRUE is ENABLE. FASLE is DISABLE. +# + +# +# FSP selection +# +DEFINE MINNOW2_FSP_BUILD = FALSE + + +DEFINE SCSI_ENABLE = TRUE + + +# +# To enable extra configuration for clk gen +# +DEFINE CLKGEN_CONFIG_EXTRA_ENABLE=TRUE + +# +# Feature selection +# + +# +# Select system timer which is used to produce Timer Arch Protocol: +# TRUE - HPET timer is used. +# FALSE - 8254 timer is used. +# +DEFINE USE_HPET_TIMER = FALSE + + +# +# Feature selection +# + +DEFINE TPM_ENABLED = FALSE + +DEFINE ACPI50_ENABLE = TRUE +DEFINE PERFORMANCE_ENABLE = FALSE + + +DEFINE LFMA_ENABLE = FALSE # Load module at fixed address feature +DEFINE DXE_COMPRESS_ENABLE = TRUE +DEFINE DXE_CRC32_SECTION_ENABLE = TRUE +DEFINE SSE2_ENABLE = FALSE + +DEFINE SECURE_BOOT_ENABLE = TRUE +DEFINE USER_IDENTIFICATION_ENABLE = FALSE +DEFINE VARIABLE_INFO_ENABLE = FALSE +DEFINE S3_ENABLE = TRUE +DEFINE CAPSULE_ENABLE = TRUE +DEFINE CAPSULE_RESET_ENABLE = TRUE + +DEFINE GOP_DRIVER_ENABLE = TRUE +DEFINE DATAHUB_ENABLE = TRUE +DEFINE DATAHUB_STATUS_CODE_ENABLE = TRUE +DEFINE USB_ENABLE = TRUE + +DEFINE ISA_SERIAL_STATUS_CODE_ENABLE = TRUE +DEFINE USB_SERIAL_STATUS_CODE_ENABLE = FALSE +DEFINE RAM_SERIAL_STATUS_CODE_ENABLE = FALSE + +DEFINE ENBDT_S3_SUPPORT = TRUE + +DEFINE LZMA_ENABLE = TRUE +DEFINE S4_ENABLE = TRUE +DEFINE NETWORK_ENABLE = TRUE +DEFINE NETWORK_IP6_ENABLE = TRUE +DEFINE NETWORK_ISCSI_ENABLE = FALSE +DEFINE NETWORK_VLAN_ENABLE = FALSE + +DEFINE SATA_ENABLE = TRUE +DEFINE PCIESC_ENABLE = TRUE +DEFINE ESRT_ENABLE = TRUE + +# +# Enable source level debug default +# +DEFINE SOURCE_DEBUG_ENABLE = FALSE + + + + diff --git a/Vlv2TbltDevicePkg/PlatformPkgGcc.fdf b/Vlv2TbltDevicePkg/PlatformPkgGcc.fdf index 3326fb2925..d519edd4c8 100644 --- a/Vlv2TbltDevicePkg/PlatformPkgGcc.fdf +++ b/Vlv2TbltDevicePkg/PlatformPkgGcc.fdf @@ -676,6 +676,12 @@ FILE FREEFORM = 878AC2CC-5343-46F2-B563-51F89DAF56BA { !endif !endif +!if $(ESRT_ENABLE) == TRUE + INF MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf + INF $(PLATFORM_PACKAGE)/PlatformEsrt/PlatformEsrtDxe.inf + INF $(PLATFORM_PACKAGE)/FmpSample/FmpSample.inf +!endif + [FV.FVMAIN_COMPACT] BlockSize = $(FLASH_BLOCK_SIZE) FvAlignment = 16 @@ -739,7 +745,7 @@ READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE -[FV.Update_Data] +[FV.Bios_Update_Data] BlockSize = $(FLASH_BLOCK_SIZE) FvAlignment = 16 ERASE_POLARITY = 1 @@ -758,8 +764,8 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE -FILE RAW = 88888888-8888-8888-8888-888888888888 { - FD = Vlv +FILE FV_IMAGE = 4A538818-5AE0-4eb2-B2EB-488B23657022 { + SECTION FV_IMAGE = FVMAIN_COMPACT } [FV.BiosUpdateCargo] @@ -781,6 +787,17 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE +!if $(ESRT_ENABLE) == TRUE + INF $(PLATFORM_PACKAGE)/UpdateDriverDxe/UpdateDriverDxe.inf +!else + INF IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf +!endif +FILE RAW = 283FA2EE-532C-484d-9383-9F93B36F0B7E { + FV = Bios_Update_Data + } +FILE RAW = 98B8D59B-E8BA-48EE-98DD-C295392F1EDB { + Vlv2TbltDevicePkg/BiosUpdateConfig/BiosUpdateConfig.ini + } [FV.BiosUpdate] @@ -802,23 +819,33 @@ READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE +FILE FV_IMAGE = EDBEDF47-6EA3-4512-83C1-70F4769D4BDE { + SECTION GUIDED { + SECTION FV_IMAGE = BiosUpdateCargo + } + } + [Capsule.Capsule_Boot] -# -# gEfiCapsuleGuid supported by platform -# { 0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }} -# -CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 -CAPSULE_FLAGS = PersistAcrossReset +!if $(ESRT_ENABLE) == TRUE +CAPSULE_GUID = 819b858e-c52c-402f-80e1-5b311b6c1959 +!else +CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!endif + +CAPSULE_FLAGS = PersistAcrossReset, InitiateReset +OEM_CAPSULE_FLAGS = 0x0001 + CAPSULE_HEADER_SIZE = 0x20 FV = BiosUpdate [Capsule.Capsule_Reset] -# -# gEfiCapsuleGuid supported by platform -# { 0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }} -# -CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!if $(ESRT_ENABLE) == TRUE +CAPSULE_GUID = 819b858e-c52c-402f-80e1-5b311b6c1959 +!else +CAPSULE_GUID = 3B6686BD-0D76-4030-B70E-B5519E2FC5A0 +!endif + CAPSULE_FLAGS = PersistAcrossReset CAPSULE_HEADER_SIZE = 0x20 diff --git a/Vlv2TbltDevicePkg/PlatformPkgGccX64.dsc b/Vlv2TbltDevicePkg/PlatformPkgGccX64.dsc index 3891c7752a..f7842af05e 100644 --- a/Vlv2TbltDevicePkg/PlatformPkgGccX64.dsc +++ b/Vlv2TbltDevicePkg/PlatformPkgGccX64.dsc @@ -181,11 +181,15 @@ !endif OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf -!if $(CAPSULE_ENABLE) == TRUE - CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf + +!if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf !else - CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf !endif + + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + LanguageLib|EdkCompatibilityPkg/Compatibility/Library/UefiLanguageLib/UefiLanguageLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf @@ -681,6 +685,9 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE !endif +[PcdsFixedAtBuild.X64] +gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag|0x0001 + [PcdsFixedAtBuild.IA32.PEIM, PcdsFixedAtBuild.IA32.PEI_CORE, PcdsFixedAtBuild.IA32.SEC] !if $(TARGET) == RELEASE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 @@ -823,6 +830,15 @@ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|5 # Variable: L"Timeout" gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|L"HwErrRecSupport"|gEfiGlobalVariableGuid|0x0|1 # Variable: L"HwErrRecSupport" gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState|L"BootState"|gEfiBootStateGuid|0x0|TRUE + + # + # Indicator to sync ESRT repository from FMP instance. Set to TRUE on first boot + # +!if $(ESRT_ENABLE) == TRUE + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|TRUE|NV,BS +!else + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|FALSE|NV,BS +!endif [PcdsDynamicDefault.common.DEFAULT] gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr|0x0 @@ -1178,7 +1194,9 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf { - FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + !if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf +!endif } MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf @@ -1512,6 +1530,28 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif !endif +# +# capsule related drivers +# +IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf +!if $(ESRT_ENABLE) == TRUE + $(PLATFORM_PACKAGE)/UpdateDriverDxe/UpdateDriverDxe.inf{ + !if $(TARGET) == DEBUG + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + SerialPortLib|$(PLATFORM_PACKAGE)/Library/SerialPortLib/SerialPortLib.inf + !endif + } +!else + IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf +!endif +MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf +!if $(ESRT_ENABLE) == TRUE + MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf + $(PLATFORM_PACKAGE)/PlatformEsrt/PlatformEsrtDxe.inf + $(PLATFORM_PACKAGE)/FmpSample/FmpSample.inf +!endif + Vlv2TbltDevicePkg/Application/FirmwareUpdate/FirmwareUpdate.inf Vlv2TbltDevicePkg/Application/SsdtUpdate/SsdtUpdate.inf diff --git a/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc b/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc index 684f2fe1ef..61e28318b3 100644 --- a/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc +++ b/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc @@ -181,11 +181,15 @@ !endif OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf -!if $(CAPSULE_ENABLE) == TRUE - CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf + +!if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf !else - CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf !endif + + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + LanguageLib|EdkCompatibilityPkg/Compatibility/Library/UefiLanguageLib/UefiLanguageLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf @@ -681,6 +685,9 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE !endif +[PcdsFixedAtBuild.X64] +gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag|0x0001 + [PcdsFixedAtBuild.IA32.PEIM, PcdsFixedAtBuild.IA32.PEI_CORE, PcdsFixedAtBuild.IA32.SEC] !if $(TARGET) == RELEASE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 @@ -823,6 +830,15 @@ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|5 # Variable: L"Timeout" gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|L"HwErrRecSupport"|gEfiGlobalVariableGuid|0x0|1 # Variable: L"HwErrRecSupport" gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState|L"BootState"|gEfiBootStateGuid|0x0|TRUE + + # + # Indicator to sync ESRT repository from FMP instance. Set to TRUE on first boot + # +!if $(ESRT_ENABLE) == TRUE + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|TRUE|NV,BS +!else + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|FALSE|NV,BS +!endif [PcdsDynamicDefault.common.DEFAULT] gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr|0x0 @@ -1101,6 +1117,8 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif } + + MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf{ @@ -1164,14 +1182,22 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf { - FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + !if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf +!endif } MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf - $(PLATFORM_PACKAGE)/FvbRuntimeDxe/FvbRuntimeDxe.inf + $(PLATFORM_PACKAGE)/FvbRuntimeDxe/FvbRuntimeDxe.inf { + !if $(TARGET) == DEBUG + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + SerialPortLib|$(PLATFORM_PACKAGE)/Library/SerialPortLib/SerialPortLib.inf + !endif + } $(PLATFORM_PACKAGE)/PlatformSetupDxe/PlatformSetupDxe.inf @@ -1492,6 +1518,28 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif !endif +# +# capsule related drivers +# +IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf +!if $(ESRT_ENABLE) == TRUE + $(PLATFORM_PACKAGE)/UpdateDriverDxe/UpdateDriverDxe.inf{ + !if $(TARGET) == DEBUG + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + SerialPortLib|$(PLATFORM_PACKAGE)/Library/SerialPortLib/SerialPortLib.inf + !endif + } +!else + IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf +!endif +MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf +!if $(ESRT_ENABLE) == TRUE + MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf + $(PLATFORM_PACKAGE)/PlatformEsrt/PlatformEsrtDxe.inf + $(PLATFORM_PACKAGE)/FmpSample/FmpSample.inf +!endif + Vlv2TbltDevicePkg/Application/FirmwareUpdate/FirmwareUpdate.inf Vlv2TbltDevicePkg/Application/SsdtUpdate/SsdtUpdate.inf diff --git a/Vlv2TbltDevicePkg/PlatformPkgX64.dsc b/Vlv2TbltDevicePkg/PlatformPkgX64.dsc index a07df1cb7e..c3e29b3f06 100644 --- a/Vlv2TbltDevicePkg/PlatformPkgX64.dsc +++ b/Vlv2TbltDevicePkg/PlatformPkgX64.dsc @@ -181,11 +181,15 @@ !endif OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf -!if $(CAPSULE_ENABLE) == TRUE - CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf + +!if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleBsLib/DxeEsrtCapsuleBsLib.inf !else - CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + CapsuleLib|IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf !endif + + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + LanguageLib|EdkCompatibilityPkg/Compatibility/Library/UefiLanguageLib/UefiLanguageLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf @@ -681,6 +685,9 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE !endif +[PcdsFixedAtBuild.X64] +gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag|0x0001 + [PcdsFixedAtBuild.IA32.PEIM, PcdsFixedAtBuild.IA32.PEI_CORE, PcdsFixedAtBuild.IA32.SEC] !if $(TARGET) == RELEASE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 @@ -823,6 +830,15 @@ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|5 # Variable: L"Timeout" gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|L"HwErrRecSupport"|gEfiGlobalVariableGuid|0x0|1 # Variable: L"HwErrRecSupport" gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState|L"BootState"|gEfiBootStateGuid|0x0|TRUE + + # + # Indicator to sync ESRT repository from FMP instance. Set to TRUE on first boot + # +!if $(ESRT_ENABLE) == TRUE + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|TRUE|NV,BS +!else + gPlatformModuleTokenSpaceGuid.PcdEsrtSyncFmp|L"EsrtSyncFmp"|gPlatformModuleTokenSpaceGuid|0x0|FALSE|NV,BS +!endif [PcdsDynamicDefault.common.DEFAULT] gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr|0x0 @@ -1174,6 +1190,9 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf { + !if $(ESRT_ENABLE) == TRUE + CapsuleLib|$(PLATFORM_PACKAGE)/Library/DxeEsrtCapsuleRtLib/DxeEsrtCapsuleRtLib.inf + !endif FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf } @@ -1181,7 +1200,13 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf - $(PLATFORM_PACKAGE)/FvbRuntimeDxe/FvbRuntimeDxe.inf + $(PLATFORM_PACKAGE)/FvbRuntimeDxe/FvbRuntimeDxe.inf { + !if $(TARGET) == DEBUG + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + SerialPortLib|$(PLATFORM_PACKAGE)/Library/SerialPortLib/SerialPortLib.inf + !endif + } $(PLATFORM_PACKAGE)/PlatformSetupDxe/PlatformSetupDxe.inf @@ -1502,6 +1527,28 @@ $(PLATFORM_BINARY_PACKAGE)/$(DXE_ARCHITECTURE)$(TARGET)/IA32/fTPMInitPeim.inf !endif !endif +# +# capsule related drivers +# +IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf +!if $(ESRT_ENABLE) == TRUE + $(PLATFORM_PACKAGE)/UpdateDriverDxe/UpdateDriverDxe.inf{ + !if $(TARGET) == DEBUG + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + SerialPortLib|$(PLATFORM_PACKAGE)/Library/SerialPortLib/SerialPortLib.inf + !endif + } +!else + IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf +!endif +MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf +!if $(ESRT_ENABLE) == TRUE + MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf + $(PLATFORM_PACKAGE)/PlatformEsrt/PlatformEsrtDxe.inf + $(PLATFORM_PACKAGE)/FmpSample/FmpSample.inf +!endif + Vlv2TbltDevicePkg/Application/FirmwareUpdate/FirmwareUpdate.inf Vlv2TbltDevicePkg/Application/SsdtUpdate/SsdtUpdate.inf diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/FlashUpdate.c b/Vlv2TbltDevicePkg/UpdateDriverDxe/FlashUpdate.c new file mode 100644 index 0000000000..95216c9d24 --- /dev/null +++ b/Vlv2TbltDevicePkg/UpdateDriverDxe/FlashUpdate.c @@ -0,0 +1,1217 @@ +/** @file + Functions in this file will program the image into flash area. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UpdateDriver.h" + +/** + Write a block size data into flash. + + @param FvbProtocol Pointer to FVB protocol. + @param Lba Logic block index to be updated. + @param BlockSize Block size + @param Buffer Buffer data to be written. + + @retval EFI_SUCCESS Write data successfully. + @retval other errors Write data failed. + +**/ +EFI_STATUS +UpdateOneBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_LBA Lba, + IN UINTN BlockSize, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN Size; + + // + // First erase the block + // + Status = FvbProtocol->EraseBlocks ( + FvbProtocol, + Lba, // Lba + 1, // NumOfBlocks + EFI_LBA_LIST_TERMINATOR + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Write the block + // + Size = BlockSize; + Status = FvbProtocol->Write ( + FvbProtocol, + Lba, // Lba + 0, // Offset + &Size, // Size + Buffer // Buffer + ); + if ((EFI_ERROR (Status)) || (Size != BlockSize)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Write buffer data in a flash block. + + @param FvbProtocol Pointer to FVB protocol. + @param Lba Logic block index to be updated. + @param Offset The offset within the block. + @param Length Size of buffer to be updated. + @param BlockSize Block size. + @param Buffer Buffer data to be updated. + + @retval EFI_SUCCESS Write data successfully. + @retval other errors Write data failed. + +**/ +EFI_STATUS +UpdateBufferInOneBlock ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN Length, + IN UINTN BlockSize, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN Size; + UINT8 *ReservedBuffer; + + // + // If we are going to update a whole block + // + if ((Offset == 0) && (Length == BlockSize)) { + Status = UpdateOneBlock ( + FvbProtocol, + Lba, + BlockSize, + Buffer + ); + return Status; + } + + // + // If it is not a full block update, we need to coalesce data in + // the block that is not going to be updated and new data together. + // + + // + // Allocate a reserved buffer to make up the final buffer for update + // + ReservedBuffer = NULL; + ReservedBuffer = AllocatePool (BlockSize); + if (ReservedBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // First get the original content of the block + // + Size = BlockSize; + Status = FvbProtocol->Read ( + FvbProtocol, + Lba, + 0, + &Size, + ReservedBuffer + ); + if ((EFI_ERROR (Status)) || (Size != BlockSize)) { + FreePool (ReservedBuffer); + return Status; + } + + // + // Overwrite the reserved buffer with new content + // + CopyMem (ReservedBuffer + Offset, Buffer, Length); + + Status = UpdateOneBlock ( + FvbProtocol, + Lba, + BlockSize, + ReservedBuffer + ); + + FreePool (ReservedBuffer); + + return Status; +} + +/** + Get the last write log, and check the status of last write. + If not complete, restart will be taken. + + @param FvbHandle Handle of FVB protocol. + @param FtwProtocol FTW protocol instance. + @param ConfigData Config data on updating driver. + @param PrivateDataSize bytes from the private data + stored for this write. + @param PrivateData A pointer to a buffer. The function will copy. + @param Lba The logical block address of the last write. + @param Offset The offset within the block of the last write. + @param Length The length of the last write. + @param Pending A Boolean value with TRUE indicating + that the write was completed. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_ABORTED The FTW work space is damaged. + @retval EFI_NOT_FOUND The last write is not done by this driver. + @retval EFI_SUCCESS Last write log is got. + +**/ +EFI_STATUS +RetrieveLastWrite ( + IN EFI_HANDLE FvbHandle, + IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINTN PrivateDataSize, + IN OUT UPDATE_PRIVATE_DATA *PrivateData, + IN OUT EFI_LBA *Lba, + IN OUT UINTN *Offset, + IN OUT UINTN *Length, + IN OUT BOOLEAN *Pending + ) +{ + EFI_STATUS Status; + EFI_GUID CallerId; + UINTN PrivateBufferSize; + BOOLEAN Complete; + VOID *PrivateDataBuffer; + + // + // Get the last write + // + *Pending = FALSE; + PrivateBufferSize = PrivateDataSize; + PrivateDataBuffer = NULL; + Status = FtwProtocol->GetLastWrite ( + FtwProtocol, + &CallerId, + Lba, + Offset, + Length, + &PrivateBufferSize, + PrivateData, + &Complete + ); + if (EFI_ERROR (Status)) { + // + // If there is no incompleted record, return success. + // + if ((Status == EFI_NOT_FOUND) && Complete) { + return EFI_SUCCESS; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + // + // If buffer too small, reallocate buffer and call getlastwrite again + // + PrivateDataBuffer = AllocatePool (PrivateBufferSize); + + if (PrivateDataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = FtwProtocol->GetLastWrite ( + FtwProtocol, + &CallerId, + Lba, + Offset, + Length, + &PrivateBufferSize, + PrivateDataBuffer, + &Complete + ); + if (EFI_ERROR (Status)) { + FreePool ( PrivateDataBuffer); + return EFI_ABORTED; + } else { + CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize); + FreePool (PrivateDataBuffer); + PrivateDataBuffer = NULL; + } + } else { + return EFI_ABORTED; + } + } + + *Pending = TRUE; + + // + // If the caller is not the update driver, then return. + // The update driver cannot continue to perform the update + // + if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) { + return EFI_NOT_FOUND; + } + + // + // Check the private data and see if it is the one I need. + // + if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) { + return EFI_NOT_FOUND; + } + + // + // If the caller is the update driver and complete is not true, then restart(). + // + if (!Complete) { + // + // Re-start the update + // + Status = FtwProtocol->Restart ( + FtwProtocol, + FvbHandle + ); + // + // If restart() error, then abort(). + // + if (EFI_ERROR (Status)) { + FtwProtocol->Abort (FtwProtocol); + // + // Now set Pending as FALSE as this record has been cleared + // + *Pending = FALSE; + return EFI_SUCCESS; + } + + } + + return Status; +} + +/** + Update the whole FV image in fault tolerant write method. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param BlockMap Block array to specify flash area. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS FV image is writed into flash. + @retval EFI_INVALID_PARAMETER Config data is not valid. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update FV. + +**/ +EFI_STATUS +FaultTolerantUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + UINTN MaxBlockSize; + UINTN FtwMaxBlockSize; + BOOLEAN Pending; + UPDATE_PRIVATE_DATA PrivateData; + EFI_LBA PendingLba; + EFI_LBA Lba; + UINTN PendingOffset; + UINTN Offset; + UINTN PendingLength; + UINTN Length; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN NumOfBlocks; + UINTN Index; + UINT8 *UpdateBuffer; + + if ((ConfigData->UpdateType != UpdateWholeFV) + || (!ConfigData->FaultTolerant)) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the FTW protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + (VOID **) &FtwProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get the maximum block size of the FV, and number of blocks + // NumOfBlocks will be the NumOfUdpates. + // + MaxBlockSize = 0; + NumOfBlocks = 0; + PtrMap = BlockMap; + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + if (MaxBlockSize < PtrMap->Length) { + MaxBlockSize = PtrMap->Length; + } + NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks; + PtrMap++; + } + + FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); + // + // Not enough backup space. return directly + // + if (FtwMaxBlockSize < MaxBlockSize) { + return EFI_OUT_OF_RESOURCES; + } + + PendingLba = 0; + PendingOffset = 0; + PendingLength = 0; + Pending = FALSE; + + // + // Fault Tolerant Write can only support actual fault tolerance if the write + // is a reclaim operation, which means the data buffer (new and old) are + // acutally both stored in flash. But for component update write, the data + // are now in memory. So we cannot actually recover the data after power + // failure. + // + Status = RetrieveLastWrite ( + FvbHandle, + FtwProtocol, + ConfigData, + sizeof (UPDATE_PRIVATE_DATA), + &PrivateData, + &PendingLba, + &PendingOffset, + &PendingLength, + &Pending + ); + + if (Pending && (Status == EFI_NOT_FOUND)) { + // + // Cannot continue with the write operation + // + return EFI_ABORTED; + } + + if (EFI_ERROR(Status)) { + return EFI_ABORTED; + } + + // + // Currently we start from the pending write if there is any. But as we + // are going to update a whole FV, we can just abort last write and start + // from the very begining. + // + if (!Pending) { + // + // Now allocte the update private data in FTW. If there is pending + // write, it has already been allocated and no need to allocate here. + // + Status = FtwProtocol->Allocate ( + FtwProtocol, + &gEfiCallerIdGuid, + sizeof (UPDATE_PRIVATE_DATA), + NumOfBlocks + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Perform the update now. If there are pending writes, we need to + // start from the pending write instead of the very beginning. + // + PtrMap = BlockMap; + Lba = 0; + Offset = 0; + UpdateBuffer = ImageBuffer; + CopyMem ( + (VOID *) &PrivateData.FileGuid, + (VOID *) &ConfigData->FileGuid, + sizeof (EFI_GUID) + ); + + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + Length = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + + // + // Add an extra check here to see if the pending record is correct + // + if (Pending && (Lba == PendingLba)) { + if ((PendingOffset != Offset) || (PendingLength != Length)) { + // + // Error. + // + Status = EFI_ABORTED; + break; + } + } + + if ((!Pending) || (Lba >= PendingLba)) { + Status = FtwProtocol->Write ( + FtwProtocol, + Lba, // Lba + Offset, // Offset + Length, // Size + &PrivateData, // Private Data + FvbHandle, // FVB handle + UpdateBuffer // Buffer + ); + } + + if (EFI_ERROR (Status)) { + break; + } + Lba++; + UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length); + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + return Status; + +} + +/** + Directly update the whole FV image without fault tolerant write method. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param BlockMap Block array to specify flash area. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS FV image is writed into flash. + @retval EFI_INVALID_PARAMETER Config data is not valid. + @retval EFI_ABORTED Error happen when update FV. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN Index; + EFI_LBA UpdateLba; + UINT8 *UpdateBuffer; + UINTN UpdateSize; + + if ((ConfigData->UpdateType != UpdateWholeFV ) + || (ConfigData->FaultTolerant)) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + PtrMap = BlockMap; + UpdateLba = 0; + UpdateBuffer = ImageBuffer; + + // + // Perform the update now + // + while (TRUE) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + UpdateSize = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + Status = UpdateOneBlock ( + FvbProtocol, + UpdateLba, + UpdateSize, + UpdateBuffer + ); + if (EFI_ERROR (Status)) { + break; + } + + UpdateLba++; + UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize); + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + return Status; +} + +/** + Update the whole FV image, and reinsall FVB protocol for the updated FV image. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV. + Or Image size is not same to the size of whole FV. + @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated. + @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled. + +**/ +EFI_STATUS +PerformUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize +) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + CHAR16 *TmpStr; + + if (ConfigData->UpdateType != UpdateWholeFV) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the header of the firmware volume + // + FwVolHeader = NULL; + FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem ( + FwVolHeader, + (VOID *) ((UINTN) (ConfigData->BaseAddress)), + ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength + ); + + // + // Check if ImageSize is the same as the size of the whole FV + // + if ((UINT64)ImageSize != FwVolHeader->FvLength) { + FreePool (FwVolHeader); + return EFI_INVALID_PARAMETER; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL); + if (TmpStr != NULL) { + Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)); + FreePool (TmpStr); + } + + DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n", + ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress))); + + // + // Get the block map of the firmware volume + // + BlockMap = &(FwVolHeader->BlockMap[0]); + + // + // It is about the same if we are going to fault tolerantly update + // a certain FV in our current design. But we divide non-fault tolerant + // and fault tolerant udpate here for better maintenance as fault + // tolerance may change and may be done more wisely if we have space. + // + if (ConfigData->FaultTolerant) { + Status = FaultTolerantUpdateOnWholeFv ( + FvbHandle, + FvbProtocol, + BlockMap, + ConfigData, + ImageBuffer, + ImageSize + ); + } else { + Status = NonFaultTolerantUpdateOnWholeFv ( + FvbHandle, + FvbProtocol, + BlockMap, + ConfigData, + ImageBuffer, + ImageSize + ); + } + + FreePool (FwVolHeader); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // As the whole FV has been replaced, the FV driver shall re-parse the + // firmware volume. So re-install FVB protocol here + // + Status = gBS->ReinstallProtocolInterface ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + FvbProtocol, + FvbProtocol + ); + + return Status; +} + +/** + Update certain file in the FV. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute + + @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile. + Or Image size is not same to the size of whole FV. + @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated. + @retval EFI_SUCCESS The FFS file is added into FV. + +**/ +EFI_STATUS +PerformUpdateOnFvFile ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; + EFI_FV_WRITE_FILE_DATA FileData; + CHAR16 *TmpStr; + + if (ConfigData->UpdateType != UpdateFvFile) { + return EFI_INVALID_PARAMETER; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL); + if (TmpStr != NULL) { + Print (TmpStr, &(ConfigData->FileGuid)); + FreePool (TmpStr); + } + + DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n", + &(ConfigData->FileGuid))); + + // + // Get Firmware volume protocol on this FVB protocol + // + Status = gBS->HandleProtocol ( + FvbHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FwVolProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If it is a PEIM, we need first to rebase it before committing + // the write to target + // + if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM ) + || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { + return EFI_UNSUPPORTED; + } + + FileData.NameGuid = &(ConfigData->FileGuid); + FileData.Type = FileType; + FileData.FileAttributes = FileAttributes; + FileData.Buffer = ImageBuffer; + FileData.BufferSize = (UINT32) ImageSize; + + Status = FwVolProtocol->WriteFile ( + FwVolProtocol, + 1, // NumberOfFiles + (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant, + &FileData + ); + return Status; +} + +/** + Update the buffer into flash area in fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param ConfigData Config data on updating driver. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update flash area. + +**/ +EFI_STATUS +FaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN UPDATE_CONFIG_DATA *ConfigData, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS FvBase; + EFI_PHYSICAL_ADDRESS NextBlock; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_FV_BLOCK_MAP_ENTRY *PtrMap; + UINTN NumOfUpdates; + UINTN TotalSize; + EFI_PHYSICAL_ADDRESS StartAddress; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + UINTN MaxBlockSize; + UINTN FtwMaxBlockSize; + BOOLEAN Pending; + UPDATE_PRIVATE_DATA PrivateData; + EFI_LBA PendingLba; + EFI_LBA Lba; + UINTN BlockSize; + UINTN PendingOffset; + UINTN Offset; + UINTN PendingLength; + UINTN Length; + UINTN Index; + UINT8 *Image; + + // + // Get the block map to update the block one by one + // + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &FvBase + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) { + return EFI_INVALID_PARAMETER; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( + FwVolHeaderTmp->HeaderLength, + FwVolHeaderTmp + ); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // For fault tolerant write, we have to know how many blocks we need to + // update. So we will calculate number of updates and max block size first + // + NumOfUpdates = 0; + MaxBlockSize = 0; + TotalSize = SizeLeft; + StartAddress = FlashAddress; + BaseAddress = FvBase; + BlockMap = &(FwVolHeader->BlockMap[0]); + PtrMap = BlockMap; + + while (TotalSize > 0) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + + BlockSize = PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + NextBlock = BaseAddress + BlockSize; + // + // Check if this block need to be updated + // + if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { + // + // Get the maximum block size + // + if (MaxBlockSize < BlockSize) { + MaxBlockSize = BlockSize; + } + + // + // This block shall be udpated. So increment number of updates + // + NumOfUpdates++; + Offset = (UINTN) (StartAddress - BaseAddress); + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + StartAddress = StartAddress + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + } + PtrMap++; + } + + // + // Get the FTW protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + (VOID **) &FtwProtocol + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return EFI_NOT_FOUND; + } + + FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); + + // + // Not enough backup space. return directly + // + if (FtwMaxBlockSize < MaxBlockSize) { + FreePool (FwVolHeader); + return EFI_OUT_OF_RESOURCES; + } + + PendingLba = 0; + PendingOffset = 0; + PendingLength = 0; + Pending = FALSE; + + // + // Fault Tolerant Write can only support actual fault tolerance if the write + // is a reclaim operation, which means the data buffer (new and old) are + // acutally both stored in flash. But for component update write, the data + // are now in memory. So we cannot actually recover the data after power + // failure. + // + Status = RetrieveLastWrite ( + FvbHandle, + FtwProtocol, + ConfigData, + sizeof (UPDATE_PRIVATE_DATA), + &PrivateData, + &PendingLba, + &PendingOffset, + &PendingLength, + &Pending + ); + if (Pending && (Status == EFI_NOT_FOUND)) { + // + // I'm not the owner of the pending fault tolerant write record + // Cannot continue with the write operation + // + FreePool (FwVolHeader); + return EFI_ABORTED; + } + + if (EFI_ERROR(Status)) { + FreePool (FwVolHeader); + return EFI_ABORTED; + } + + // + // Currently we start from the pending write if there is any. But if the + // caller is exactly the same, and the new data is already a in memory, (it + // cannot be stored in flash in last write,) we can just abort last write + // and start from the very begining. + // + if (!Pending) { + // + // Now allocte the update private data in FTW. If there is pending + // write, it has already been allocated and no need to allocate here. + // + Status = FtwProtocol->Allocate ( + FtwProtocol, + &gEfiCallerIdGuid, + sizeof (UPDATE_PRIVATE_DATA), + NumOfUpdates + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return Status; + } + } + + // + // Perform the update now. If there are pending writes, we need to + // start from the pending write instead of the very beginning. + // + TotalSize = SizeLeft; + Lba = 0; + StartAddress = FlashAddress; + BaseAddress = FvBase; + PtrMap = BlockMap; + Image = ImageBuffer; + CopyMem ( + (VOID *) &PrivateData.FileGuid, + (VOID *) &ConfigData->FileGuid, + sizeof (EFI_GUID) + ); + + while (TotalSize > 0) { + if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { + break; + } + + BlockSize = (UINTN)PtrMap->Length; + for (Index = 0; Index < PtrMap->NumBlocks; Index++) { + NextBlock = BaseAddress + BlockSize; + if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { + // + // So we need to update this block + // + Offset = (UINTN) (StartAddress - BaseAddress); + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + // + // Add an extra check here to see if the pending record is correct + // + if (Pending && (Lba == PendingLba)) { + if ((PendingOffset != Offset) || (PendingLength != Length)) { + // + // Error. + // + Status = EFI_ABORTED; + break; + } + } + + if ((!Pending) || (Lba >= PendingLba)) { + DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length)); + Status = FtwProtocol->Write ( + FtwProtocol, + Lba, // Lba + Offset, // Offset + Length, // Size + &PrivateData, // Private Data + FvbHandle, // FVB handle + Image // Buffer + ); + if (EFI_ERROR (Status)) { + break; + } + } + + // + // Now increment StartAddress, ImageBuffer and decrease the + // left size to prepare for the next block update. + // + StartAddress = StartAddress + Length; + Image = Image + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + Lba++; + } + + if (EFI_ERROR (Status)) { + break; + } + PtrMap++; + } + + FreePool (FwVolHeader); + + *UpdatedSize = SizeLeft - TotalSize; + + return EFI_SUCCESS; +} + +/** + Directly update the buffer into flash area without fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_PHYSICAL_ADDRESS NextBlock; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + UINTN Index; + UINTN TotalSize; + UINTN BlockSize; + EFI_LBA Lba; + UINTN Offset; + UINTN Length; + UINT8 *Image; + + // + // Get the block map to update the block one by one + // + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) { + return EFI_INVALID_PARAMETER; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( + FwVolHeaderTmp->HeaderLength, + FwVolHeaderTmp + ); + if (FwVolHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Image = ImageBuffer; + TotalSize = SizeLeft; + BlockMap = &(FwVolHeader->BlockMap[0]); + Lba = 0; + + while (TotalSize > 0) { + if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) { + break; + } + + BlockSize = BlockMap->Length; + for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) { + NextBlock = BaseAddress + BlockSize; + if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) { + // + // So we need to update this block + // + Offset = (UINTN) FlashAddress - (UINTN) BaseAddress; + Length = TotalSize; + if ((Length + Offset ) > BlockSize) { + Length = BlockSize - Offset; + } + + DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length)); + // + // Update the block + // + Status = UpdateBufferInOneBlock ( + FvbProtocol, + Lba, + Offset, + Length, + BlockSize, + Image + ); + if (EFI_ERROR (Status)) { + FreePool (FwVolHeader); + return Status; + } + + // + // Now increment FlashAddress, ImageBuffer and decrease the + // left size to prepare for the next block update. + // + FlashAddress = FlashAddress + Length; + Image = Image + Length; + TotalSize = TotalSize - Length; + if (TotalSize <= 0) { + break; + } + } + BaseAddress = NextBlock; + Lba++; + } + + if (EFI_ERROR (Status)) { + break; + } + BlockMap++; + } + + FreePool (FwVolHeader); + + *UpdatedSize = SizeLeft - TotalSize; + + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/ParseUpdateProfile.c b/Vlv2TbltDevicePkg/UpdateDriverDxe/ParseUpdateProfile.c new file mode 100644 index 0000000000..503d055598 --- /dev/null +++ b/Vlv2TbltDevicePkg/UpdateDriverDxe/ParseUpdateProfile.c @@ -0,0 +1,1134 @@ +/** @file + Source file for the component update driver. It parse the update + configuration file and pass the information to the update driver + so that the driver can perform updates accordingly. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "UpdateDriver.h" + +/** + Copy one line data from buffer data to the line buffer. + + @param Buffer Buffer data. + @param BufferSize Buffer Size. + @param LineBuffer Line buffer to store the found line data. + @param LineSize On input, size of the input line buffer. + On output, size of the actual line buffer. + + @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough. + @retval EFI_SUCCESS Copy line data into the line buffer. + +**/ +EFI_STATUS +ProfileGetLine ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT UINT8 *LineBuffer, + IN OUT UINTN *LineSize + ) +{ + UINTN Length; + UINT8 *PtrBuf; + UINTN PtrEnd; + + PtrBuf = Buffer; + PtrEnd = (UINTN)Buffer + BufferSize; + + // + // 0x0D indicates a line break. Otherwise there is no line break + // + while ((UINTN)PtrBuf < PtrEnd) { + if (*PtrBuf == 0x0D) { + break; + } + PtrBuf++; + } + + if ((UINTN)PtrBuf >= (PtrEnd - 1)) { + // + // The buffer ends without any line break + // or it is the last character of the buffer + // + Length = BufferSize; + } else if (*(PtrBuf + 1) == 0x0A) { + // + // Further check if a 0x0A follows. If yes, count 0xA + // + Length = (UINTN) PtrBuf - (UINTN) Buffer + 2; + } else { + Length = (UINTN) PtrBuf - (UINTN) Buffer + 1; + } + + if (Length > (*LineSize)) { + *LineSize = Length; + return EFI_BUFFER_TOO_SMALL; + } + + SetMem (LineBuffer, *LineSize, 0x0); + *LineSize = Length; + CopyMem (LineBuffer, Buffer, Length); + + return EFI_SUCCESS; +} + +/** + Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail. + + @param Buffer On input, buffer data to be trimed. + On output, the trimmed buffer. + @param BufferSize On input, size of original buffer data. + On output, size of the trimmed buffer. + +**/ +VOID +ProfileTrim ( + IN OUT UINT8 *Buffer, + IN OUT UINTN *BufferSize + ) +{ + UINTN Length; + UINT8 *PtrBuf; + UINT8 *PtrEnd; + + if (*BufferSize == 0) { + return; + } + + // + // Trim the tail first, include CR, LF, TAB, and SPACE. + // + Length = *BufferSize; + PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1); + while (PtrBuf >= Buffer) { + if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) + && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { + break; + } + PtrBuf --; + } + + // + // all spaces, a blank line, return directly; + // + if (PtrBuf < Buffer) { + *BufferSize = 0; + return; + } + + Length = (UINTN)PtrBuf - (UINTN)Buffer + 1; + PtrEnd = PtrBuf; + PtrBuf = Buffer; + + // + // Now skip the heading CR, LF, TAB and SPACE + // + while (PtrBuf <= PtrEnd) { + if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) + && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { + break; + } + PtrBuf++; + } + + // + // If no heading CR, LF, TAB or SPACE, directly return + // + if (PtrBuf == Buffer) { + *BufferSize = Length; + return; + } + + *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1; + + // + // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE. + // Now move out all these characters. + // + while (PtrBuf <= PtrEnd) { + *Buffer = *PtrBuf; + Buffer++; + PtrBuf++; + } + + return; +} + +/** + Insert new comment item into comment head. + + @param Buffer Comment buffer to be added. + @param BufferSize Size of comment buffer. + @param CommentHead Comment Item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS New comment item is inserted. + +**/ +EFI_STATUS +ProfileGetComments ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT COMMENT_LINE **CommentHead + ) +{ + COMMENT_LINE *CommentItem; + + CommentItem = NULL; + CommentItem = AllocatePool (sizeof (COMMENT_LINE)); + if (CommentItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CommentItem->ptrNext = *CommentHead; + *CommentHead = CommentItem; + + // + // Add a trailing '\0' + // + CommentItem->ptrComment = AllocatePool (BufferSize + 1); + if (CommentItem->ptrComment == NULL) { + FreePool (CommentItem); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (CommentItem->ptrComment, Buffer, BufferSize); + *(CommentItem->ptrComment + BufferSize) = '\0'; + + return EFI_SUCCESS; +} + +/** + Add new section item into Section head. + + @param Buffer Section item data buffer. + @param BufferSize Size of section item. + @param SectionHead Section item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Section item is NULL or Section item is added. + +**/ +EFI_STATUS +ProfileGetSection ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead + ) +{ + EFI_STATUS Status; + SECTION_ITEM *SectionItem; + UINTN Length; + UINT8 *PtrBuf; + + Status = EFI_SUCCESS; + // + // The first character of Buffer is '[', now we want for ']' + // + PtrBuf = (UINT8 *)((UINTN)Buffer + BufferSize - 1); + while (PtrBuf > Buffer) { + if (*PtrBuf == ']') { + break; + } + PtrBuf --; + } + if (PtrBuf <= Buffer) { + // + // Not found. Omit this line + // + return Status; + } + + // + // excluding the heading '[' and tailing ']' + // + Length = PtrBuf - Buffer - 1; + ProfileTrim ( + Buffer + 1, + &Length + ); + + // + // omit this line if the section name is null + // + if (Length == 0) { + return Status; + } + + SectionItem = AllocatePool (sizeof (SECTION_ITEM)); + if (SectionItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SectionItem->ptrSection = NULL; + SectionItem->SecNameLen = Length; + SectionItem->ptrEntry = NULL; + SectionItem->ptrValue = NULL; + SectionItem->ptrNext = *SectionHead; + *SectionHead = SectionItem; + + // + // Add a trailing '\0' + // + SectionItem->ptrSection = AllocatePool (Length + 1); + if (SectionItem->ptrSection == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // excluding the heading '[' + // + CopyMem (SectionItem->ptrSection, Buffer + 1, Length); + *(SectionItem->ptrSection + Length) = '\0'; + + return EFI_SUCCESS; +} + +/** + Add new section entry and entry value into Section head. + + @param Buffer Section entry data buffer. + @param BufferSize Size of section entry. + @param SectionHead Section item head entry. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Section entry is NULL or Section entry is added. + +**/ +EFI_STATUS +ProfileGetEntry ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead + ) +{ + EFI_STATUS Status; + SECTION_ITEM *SectionItem; + SECTION_ITEM *PtrSection; + UINTN Length; + UINT8 *PtrBuf; + UINT8 *PtrEnd; + + Status = EFI_SUCCESS; + PtrBuf = Buffer; + PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1); + + // + // First search for '=' + // + while (PtrBuf <= PtrEnd) { + if (*PtrBuf == '=') { + break; + } + PtrBuf++; + } + if (PtrBuf > PtrEnd) { + // + // Not found. Omit this line + // + return Status; + } + + // + // excluding the tailing '=' + // + Length = PtrBuf - Buffer; + ProfileTrim ( + Buffer, + &Length + ); + + // + // Omit this line if the entry name is null + // + if (Length == 0) { + return Status; + } + + // + // Omit this line if no section header has been found before + // + if (*SectionHead == NULL) { + return Status; + } + PtrSection = *SectionHead; + + SectionItem = AllocatePool (sizeof (SECTION_ITEM)); + if (SectionItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SectionItem->ptrSection = NULL; + SectionItem->ptrEntry = NULL; + SectionItem->ptrValue = NULL; + SectionItem->SecNameLen = PtrSection->SecNameLen; + SectionItem->ptrNext = *SectionHead; + *SectionHead = SectionItem; + + // + // SectionName, add a trailing '\0' + // + SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1); + if (SectionItem->ptrSection == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1); + + // + // EntryName, add a trailing '\0' + // + SectionItem->ptrEntry = AllocatePool (Length + 1); + if (SectionItem->ptrEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrEntry, Buffer, Length); + *(SectionItem->ptrEntry + Length) = '\0'; + + // + // Next search for '#' + // + PtrBuf = PtrBuf + 1; + Buffer = PtrBuf; + while (PtrBuf <= PtrEnd) { + if (*PtrBuf == '#') { + break; + } + PtrBuf++; + } + Length = PtrBuf - Buffer; + ProfileTrim ( + Buffer, + &Length + ); + + if (Length > 0) { + // + // EntryValue, add a trailing '\0' + // + SectionItem->ptrValue = AllocatePool (Length + 1); + if (SectionItem->ptrValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (SectionItem->ptrValue, Buffer, Length); + *(SectionItem->ptrValue + Length) = '\0'; + } + + return EFI_SUCCESS; +} + +/** + Free all comment entry and section entry. + + @param Section Section entry list. + @param Comment Comment entry list. + +**/ +VOID +FreeAllList ( + IN SECTION_ITEM *Section, + IN COMMENT_LINE *Comment + ) +{ + SECTION_ITEM *PtrSection; + COMMENT_LINE *PtrComment; + + while (Section != NULL) { + PtrSection = Section; + Section = Section->ptrNext; + if (PtrSection->ptrEntry != NULL) { + FreePool (PtrSection->ptrEntry); + } + if (PtrSection->ptrSection != NULL) { + FreePool (PtrSection->ptrSection); + } + if (PtrSection->ptrValue != NULL) { + FreePool (PtrSection->ptrValue); + } + FreePool (PtrSection); + } + + while (Comment != NULL) { + PtrComment = Comment; + Comment = Comment->ptrNext; + if (PtrComment->ptrComment != NULL) { + FreePool (PtrComment->ptrComment); + } + FreePool (PtrComment); + } + + return; +} + +/** + Get section entry value. + + @param Section Section entry list. + @param SectionName Section name. + @param EntryName Section entry name. + @param EntryValue Point to the got entry value. + + @retval EFI_NOT_FOUND Section is not found. + @retval EFI_SUCCESS Section entry value is got. + +**/ +EFI_STATUS +UpdateGetProfileString ( + IN SECTION_ITEM *Section, + IN UINT8 *SectionName, + IN UINT8 *EntryName, + OUT UINT8 **EntryValue + ) +{ + *EntryValue = NULL; + + while (Section != NULL) { + if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) { + if (Section->ptrEntry != NULL) { + if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) { + break; + } + } + } + Section = Section->ptrNext; + } + + if (Section == NULL) { + return EFI_NOT_FOUND; + } + + *EntryValue = (UINT8 *) Section->ptrValue; + + return EFI_SUCCESS; +} + +/** + Convert the dec or hex ascii string to value. + + @param Str ascii string to be converted. + + @return the converted value. + +**/ +UINTN +UpdateAtoi ( + IN UINT8 *Str + ) +{ + UINTN Number; + + Number = 0; + + // + // Skip preceeding while spaces + // + while (*Str != '\0') { + if (*Str != 0x20) { + break; + } + Str++; + } + + if (*Str == '\0') { + return Number; + } + + // + // Find whether the string is prefixed by 0x. + // That is, it should be xtoi or atoi. + // + if (*Str == '0') { + if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) { + return AsciiStrHexToUintn ((CONST CHAR8 *) Str); + } + } + + while (*Str != '\0') { + if ((*Str >= '0') && (*Str <= '9')) { + Number = Number * 10 + *Str - '0'; + } else { + break; + } + Str++; + } + + return Number; +} + +/** + Converts a decimal value to a Null-terminated ascii string. + + @param Buffer Pointer to the output buffer for the produced Null-terminated + ASCII string. + @param Value The 64-bit sgned value to convert to a string. + + @return The number of ASCII characters in Buffer not including the Null-terminator. + +**/ +UINTN +UpdateValueToString ( + IN OUT UINT8 *Buffer, + IN INT64 Value + ) +{ + UINT8 TempBuffer[30]; + UINT8 *TempStr; + UINT8 *BufferPtr; + UINTN Count; + UINT32 Remainder; + + TempStr = TempBuffer; + BufferPtr = Buffer; + Count = 0; + + if (Value < 0) { + *BufferPtr = '-'; + BufferPtr++; + Value = -Value; + Count++; + } + + do { + Value = (INT64) DivU64x32Remainder ((UINT64)Value, 10, &Remainder); + // + // The first item of TempStr is not occupied. It's kind of flag + // + TempStr++; + Count++; + *TempStr = (UINT8) ((UINT8)Remainder + '0'); + } while (Value != 0); + + // + // Reverse temp string into Buffer. + // + while (TempStr != TempBuffer) { + *BufferPtr = *TempStr; + BufferPtr++; + TempStr --; + } + + *BufferPtr = 0; + + return Count; +} + +/** + Convert the input value to a ascii string, + and concatenates this string to the input string. + + @param Str Pointer to a Null-terminated ASCII string. + @param Number The unsgned value to convert to a string. + +**/ +VOID +UpdateStrCatNumber ( + IN OUT UINT8 *Str, + IN UINTN Number + ) +{ + UINTN Count; + + while (*Str != '\0') { + Str++; + } + + Count = UpdateValueToString (Str, (INT64)Number); + + *(Str + Count) = '\0'; + + return; +} + +/** + Convert the input ascii string into GUID value. + + @param Str Ascii GUID string to be converted. + @param Guid Pointer to the converted GUID value. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string. + @retval EFI_SUCCESS GUID value is got. + +**/ +EFI_STATUS +UpdateStringToGuid ( + IN UINT8 *Str, + IN OUT EFI_GUID *Guid + ) +{ + UINT8 *PtrBuffer; + UINT8 *PtrPosition; + UINT8 *Buffer; + UINTN Data; + UINTN StrLen; + UINTN Index; + UINT8 Digits[3]; + + StrLen = AsciiStrLen ((CONST CHAR8 *) Str); + Buffer = AllocatePool (StrLen + 1); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AsciiStrCpy ((CHAR8 *)Buffer, (CHAR8 *)Str); + + // + // Data1 + // + PtrBuffer = Buffer; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data1 = (UINT32)Data; + + // + // Data2 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data2 = (UINT16)Data; + + // + // Data3 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != '\0') { + if (*PtrBuffer == '-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == '\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); + Guid->Data3 = (UINT16)Data; + + // + // Data4[0..1] + // + for ( Index = 0 ; Index < 2 ; Index++) { + PtrBuffer++; + if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + // + // skip the '-' + // + PtrBuffer++; + if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) { + return EFI_NOT_FOUND; + } + + // + // Data4[2..7] + // + for ( ; Index < 8; Index++) { + PtrBuffer++; + if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = '\0'; + Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + FreePool (Buffer); + + return EFI_SUCCESS; +} + +/** + Pre process config data buffer into Section entry list and Comment entry list. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param SectionHead Pointer to the section entry list. + @param CommentHead Pointer to the comment entry list. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Config data buffer is preprocessed. + +**/ +EFI_STATUS +PreProcessDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT SECTION_ITEM **SectionHead, + IN OUT COMMENT_LINE **CommentHead + ) +{ + EFI_STATUS Status; + CHAR8 *Source; + CHAR8 *CurrentPtr; + CHAR8 *BufferEnd; + CHAR8 *PtrLine; + UINTN LineLength; + UINTN SourceLength; + UINTN MaxLineLength; + + *SectionHead = NULL; + *CommentHead = NULL; + BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize); + CurrentPtr = (CHAR8 *) DataBuffer; + MaxLineLength = MAX_LINE_LENGTH; + Status = EFI_SUCCESS; + + PtrLine = AllocatePool (MaxLineLength); + if (PtrLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + while (CurrentPtr < BufferEnd) { + Source = CurrentPtr; + SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr; + LineLength = MaxLineLength; + // + // With the assumption that line length is less than 512 + // characters. Otherwise BUFFER_TOO_SMALL will be returned. + // + Status = ProfileGetLine ( + (UINT8 *) Source, + SourceLength, + (UINT8 *) PtrLine, + &LineLength + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // If buffer too small, re-allocate the buffer according + // to the returned LineLength and try again. + // + FreePool (PtrLine); + PtrLine = NULL; + PtrLine = AllocatePool (LineLength); + if (PtrLine == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + SourceLength = LineLength; + Status = ProfileGetLine ( + (UINT8 *) Source, + SourceLength, + (UINT8 *) PtrLine, + &LineLength + ); + if (EFI_ERROR (Status)) { + break; + } + MaxLineLength = LineLength; + } else { + break; + } + } + CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength); + + // + // Line got. Trim the line before processing it. + // + ProfileTrim ( + (UINT8 *) PtrLine, + &LineLength + ); + + // + // Blank line + // + if (LineLength == 0) { + continue; + } + + if (PtrLine[0] == '#') { + Status = ProfileGetComments ( + (UINT8 *) PtrLine, + LineLength, + CommentHead + ); + } else if (PtrLine[0] == '[') { + Status = ProfileGetSection ( + (UINT8 *) PtrLine, + LineLength, + SectionHead + ); + } else { + Status = ProfileGetEntry ( + (UINT8 *) PtrLine, + LineLength, + SectionHead + ); + } + + if (EFI_ERROR (Status)) { + break; + } + } + + // + // Free buffer + // + FreePool (PtrLine); + + return Status; +} + +/** + Parse Config data file to get the updated data array. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param NumOfUpdates Pointer to the number of update data. + @param UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT UINTN *NumOfUpdates, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ) +{ + EFI_STATUS Status; + CHAR8 *Value; + CHAR8 *SectionName; + CHAR8 Entry[MAX_LINE_LENGTH]; + SECTION_ITEM *SectionHead; + COMMENT_LINE *CommentHead; + UINTN Num; + UINTN Index; + EFI_GUID FileGuid; + + SectionHead = NULL; + CommentHead = NULL; + + // + // First process the data buffer and get all sections and entries + // + Status = PreProcessDataFile ( + DataBuffer, + BufferSize, + &SectionHead, + &CommentHead + ); + if (EFI_ERROR (Status)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + + // + // Now get NumOfUpdate + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) "Head", + (UINT8 *) "NumOfUpdate", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + Num = UpdateAtoi((UINT8 *) Value); + if (Num <= 0) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + *NumOfUpdates = Num; + *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num)); + if (*UpdateArray == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_OUT_OF_RESOURCES; + } + + for ( Index = 0 ; Index < *NumOfUpdates ; Index++) { + // + // Get the section name of each update + // + AsciiStrCpy (Entry, "Update"); + UpdateStrCatNumber ((UINT8 *) Entry, Index); + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) "Head", + (UINT8 *) Entry, + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + // + // The section name of this update has been found. + // Now looks for all the config data of this update + // + SectionName = Value; + + // + // UpdateType + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "UpdateType", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = UpdateAtoi((UINT8 *) Value); + if (( Num >= (UINTN) UpdateOperationMaximum)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + (*UpdateArray)[Index].Index = Index; + (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num; + + // + // FvBaseAddress + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FvBaseAddress", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); + (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num; + + // + // FileBuid + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FileGuid", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid); + if (EFI_ERROR (Status)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } + CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID)); + + // + // FaultTolerant + // Default value is FALSE + // + Value = NULL; + (*UpdateArray)[Index].FaultTolerant = FALSE; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "FaultTolerant", + (UINT8 **) &Value + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + FreeAllList (SectionHead, CommentHead); + return Status; + } else if (Value != NULL) { + if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) { + (*UpdateArray)[Index].FaultTolerant = TRUE; + } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) { + (*UpdateArray)[Index].FaultTolerant = FALSE; + } + } + + if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) { + // + // Length + // + Value = NULL; + Status = UpdateGetProfileString ( + SectionHead, + (UINT8 *) SectionName, + (UINT8 *) "Length", + (UINT8 **) &Value + ); + if (Value == NULL) { + FreeAllList (SectionHead, CommentHead); + return EFI_NOT_FOUND; + } + + Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); + (*UpdateArray)[Index].Length = (UINTN) Num; + } + } + + // + // Now all configuration data got. Free those temporary buffers + // + FreeAllList (SectionHead, CommentHead); + + return EFI_SUCCESS; +} + diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDispatcher.c b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDispatcher.c new file mode 100644 index 0000000000..f189bc109d --- /dev/null +++ b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDispatcher.c @@ -0,0 +1,897 @@ +/** @file + Functions in this file will mainly focus on looking through the capsule + for the image to be programmed, and the flash area that is going to be + programed. + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UpdateDriver.h" + +EFI_HII_HANDLE gHiiHandle; +EFI_SYSTEM_RESOURCE_ENTRY NewEsrtTemplate = + // System Firmware Entry + { + SYSTEM_FW_CLASS_GUID, + ESRT_FW_TYPE_SYSTEMFIRMWARE, + 0x0003, + 0x0001, + 0x0000, + 0x0003, + LAST_ATTEMPT_STATUS_SUCCESS + }; + +/** + Update the whole FV, or certain files in the FV. + + @param ConfigData Pointer to the config data on updating file. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute. + + @retval EFI_NOT_FOUND The matched FVB protocol is not found. + @retval EFI_SUCCESS The image buffer is updated into FV. + +**/ +EFI_STATUS +PerformUpdateOnFirmwareVolume ( + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + UINTN Index; + UINTN NumOfHandles; + EFI_HANDLE *HandleBuffer; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FVB_ATTRIBUTES_2 Attributes; + + // + // Locate all Fvb protocol + // + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &NumOfHandles, + &HandleBuffer + ); + if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return EFI_NOT_FOUND; + } + + // + // Check the FVB protocol one by one + // + Found = FALSE; + FvbProtocol = NULL; + for (Index = 0; Index < NumOfHandles; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &FvbProtocol + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Ensure this FVB protocol supported Write operation. + // + Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { + continue; + } + + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + break; + } + if (BaseAddress == ConfigData->BaseAddress) { + Found = TRUE; + break; + } + } + + if (!Found) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return EFI_NOT_FOUND; + } + + // + // Now we have got the corresponding FVB protocol. Use the FVB protocol + // to update the whole FV, or certain files in the FV. + // + if (ConfigData->UpdateType == UpdateWholeFV) { + if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = PerformUpdateOnWholeFv ( + HandleBuffer[Index], + FvbProtocol, + ConfigData, + ImageBuffer, + ImageSize + ); + } + } else if (ConfigData->UpdateType == UpdateFvFile) { + Status = PerformUpdateOnFvFile ( + HandleBuffer[Index], + FvbProtocol, + ConfigData, + ImageBuffer, + ImageSize, + FileType, + FileAttributes + ); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + + return Status; +} + +/** + Update the file directly into flash area. + + @param ConfigData Pointer to the config data on updating file. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_SUCCESS The file is updated into flash area. + @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found. + +**/ +EFI_STATUS +PerformUpdateOnFlashArea ( + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ) +{ + EFI_STATUS Status; + UINTN SizeLeft; + EFI_PHYSICAL_ADDRESS FlashAddress; + UINT8 *PtrImage; + BOOLEAN Found; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + UINTN Index; + UINTN NumOfHandles; + EFI_HANDLE *HandleBuffer; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_HANDLE FvbHandle; + UINTN SizeUpdated; + CHAR16 *TmpStr; + EFI_FVB_ATTRIBUTES_2 Attributes; + + SizeLeft = ImageSize; + PtrImage = ImageBuffer; + FlashAddress = ConfigData->BaseAddress; + Status = EFI_SUCCESS; + HandleBuffer = NULL; + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL); + if (TmpStr != NULL) { + Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress)); + FreePool (TmpStr); + } + + // + // Locate all Fvb protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &NumOfHandles, + &HandleBuffer + ); + if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + return EFI_NOT_FOUND; + } + + while (SizeLeft > 0) { + // + // First get the FVB protocols. If the flash area is a FV, or sub FV, + // we can directly locate all the FVB protocol. Otherwise we should use + // implementation specific method to get the alternate FVB protocol + // + Found = FALSE; + FvbProtocol = NULL; + + // + // Check the FVB protocol one by one + // + for (Index = 0; Index < NumOfHandles; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &FvbProtocol + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Ensure this FVB protocol supported Write operation. + // + Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes); + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { + continue; + } + + Status = FvbProtocol->GetPhysicalAddress ( + FvbProtocol, + &BaseAddress + ); + if (EFI_ERROR (Status)) { + break; + } + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; + + // + // This sub area entry falls in the range of the FV + // + if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) { + Found = TRUE; + break; + } + } + + if (!Found) { + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return EFI_NOT_FOUND; + } + + FvbHandle = HandleBuffer[Index]; + SizeUpdated = 0; + + // + // If the flash area is boot required, the update must be fault tolerant + // + if (ConfigData->FaultTolerant) { + // + // Finally we are here. We have got the corresponding FVB protocol. Now + // we need to convert the physical address to LBA and offset and call + // FTW write. Also check if the flash range is larger than the FV. + // + Status = FaultTolerantUpdateOnPartFv ( + PtrImage, + SizeLeft, + &SizeUpdated, + ConfigData, + FlashAddress, + FvbProtocol, + FvbHandle + ); + } else { + // + // Finally we are here. We have got the corresponding FVB protocol. Now + // we need to convert the physical address to LBA and offset and call + // FVB write. Also check if the flash range is larger than the FV. + // + Status = NonFaultTolerantUpdateOnPartFv ( + PtrImage, + SizeLeft, + &SizeUpdated, + FlashAddress, + FvbProtocol, + FvbHandle + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // As part of the FV has been replaced, the FV driver shall re-parse + // the firmware volume. So re-install FVB protocol here + // + Status = gBS->ReinstallProtocolInterface ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + FvbProtocol, + FvbProtocol + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check if we are done with the update + // + SizeLeft = SizeLeft - SizeUpdated; + FlashAddress = FlashAddress + SizeUpdated; + PtrImage = PtrImage + SizeUpdated; + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + + return Status; +} + +/** + Find the updated file, and program it into the flash area based on the config data. + + @param FwVolProtocol Pointer to FV protocol that contains the updated file. + @param ConfigData Pointer to the Config Data on updating file. + + @retval EFI_INVALID_PARAMETER The update operation is not valid. + @retval EFI_NOT_FOUND The updated file is not found. + @retval EFI_SUCCESS The file is updated into the flash area. + +**/ +EFI_STATUS +PerformUpdate ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol, + IN UPDATE_CONFIG_DATA *ConfigData + ) +{ + EFI_STATUS Status; + UINT8 *FileBuffer; + UINTN FileBufferSize; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES Attrib; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + CHAR16 *TmpStr; + BOOLEAN StartToUpdate; + + Status = EFI_SUCCESS; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &(ConfigData->FileGuid), + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + return Status; + } + + StartToUpdate = FALSE; + + // + // Check if the update image is the one we require + // and then perform the update + // + switch (ConfigData->UpdateType) { + + case UpdateWholeFV: + + // + // For UpdateWholeFv, the update file shall be a firmware volume + // image file. + // + if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n")); + Status = EFI_INVALID_PARAMETER; + } else { + if (FileBuffer != NULL) { + FreePool (FileBuffer); + } + SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadSection ( + FwVolProtocol, + &(ConfigData->FileGuid), + SectionType, + 0, + (VOID **) &FileBuffer, + &FileBufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + // + // Execute the update. For UpdateWholeFv, the update + // will always execute on a whole FV + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFirmwareVolume ( + ConfigData, + FileBuffer, + FileBufferSize, + FileType, + Attrib + ); + + } else { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n")); + } + } + break; + + case UpdateFvRange: + + // + // For UpdateFvRange, the update file shall be a raw file + // which does not contain any sections. The contents of the file + // will be directly programmed. + // + if (FileType != EFI_FV_FILETYPE_RAW) { + DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n")); + Status = EFI_INVALID_PARAMETER; + } else { + // + // For UpdateFvRange, the update may be performed on a sub area + // of a certain FV, or a flash area that is not FV, or part of FV. + // The update may also go across more than one FVs. + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFlashArea ( + ConfigData, + FileBuffer, + FileBufferSize + ); + } + break; + + case UpdateFvFile: + + // + // No check will be done the the file got. The contents of the file + // will be directly programmed. + // Though UpdateFvFile will only update a single file, but the update + // will always execute on a FV + // + StartToUpdate = TRUE; + Status = PerformUpdateOnFirmwareVolume ( + ConfigData, + FileBuffer, + FileBufferSize, + FileType, + Attrib + ); + break; + + default: + Status = EFI_INVALID_PARAMETER; + } + + if (StartToUpdate) { + if (EFI_ERROR (Status)) { + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL); + } else { + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL); + } + if (TmpStr != NULL) { + Print (TmpStr); + FreePool (TmpStr); + } + } + + if (FileBuffer != NULL) { + FreePool(FileBuffer); + FileBuffer = NULL; + } + + return Status; +} + +/** + Process the input firmware volume by using DXE service ProcessFirmwareVolume. + + @param DataBuffer Point to the FV image to be processed. + @param BufferSize Size of the FV image buffer. + @param FwVolProtocol Point to the installed FV protocol for the input FV image. + + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_VOLUME_CORRUPTED FV image is corrupted. + @retval EFI_SUCCESS FV image is processed and FV protocol is installed. + +**/ +EFI_STATUS +ProcessUpdateImage ( + UINT8 *DataBuffer, + UINTN BufferSize, + EFI_FIRMWARE_VOLUME2_PROTOCOL **FwVolProtocol + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_HANDLE FwVolHandle; + EFI_STATUS Status; + UINT8 *ProcessedDataBuffer; + UINT32 FvAlignment; + + ProcessedDataBuffer = NULL; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer; + if (FwVolHeader->FvLength != BufferSize) { + return EFI_VOLUME_CORRUPTED; + } + + FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16); + // + // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value. + // + if (FvAlignment < 8) { + FvAlignment = 8; + } + // + // Check FvImage Align is required. + // + if (((UINTN) FwVolHeader % FvAlignment) == 0) { + ProcessedDataBuffer = DataBuffer; + } else { + // + // Allocate new aligned buffer to store DataBuffer. + // + ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment); + if (ProcessedDataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize); + } + // + // Process the firmware volume + // + gDS->ProcessFirmwareVolume ( + ProcessedDataBuffer, + BufferSize, + &FwVolHandle + ); + + // + // Get the FwVol protocol + // + Status = gBS->HandleProtocol ( + FwVolHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) FwVolProtocol + ); + + return Status; +} + +/** + Find the image in the same FV and program it in a target Firmware Volume device. + After update image, it will reset system and no return. + + @param ImageHandle A handle for the image that is initializing this driver + @param SystemTable A pointer to the EFI system table + + @retval EFI_ABORTED System reset failed. + @retval EFI_NOT_FOUND The updated image is not found in the same FV. + +**/ +EFI_STATUS +EFIAPI +InitializeUpdateDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_STATUS StatusEsrt; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; + EFI_FIRMWARE_VOLUME2_PROTOCOL *DataFwVolProtocol; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *AlignedDevPathNode; + EFI_DEVICE_PATH_PROTOCOL *FilePathNode; + EFI_SECTION_TYPE SectionType; + UINT8 *FileBuffer; + UINTN FileBufferSize; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES Attrib; + UINT32 AuthenticationStatus; + UPDATE_CONFIG_DATA *ConfigData; + UPDATE_CONFIG_DATA *UpdateConfigData; + UINTN NumOfUpdates; + UINTN Index; + CHAR16 *TmpStr; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + + + ConfigData = NULL; + FileBuffer = NULL; + AlignedDevPathNode = NULL; + + NewEsrtTemplate.CapsuleFlags = PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag); + + // + // Clear screen + // + //if (gST->ConOut != NULL) { + // gST->ConOut->ClearScreen (gST->ConOut); + // gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT); + // gST->ConOut->EnableCursor (gST->ConOut, FALSE); + //} + + gHiiHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + NULL, + UpdateDriverDxeStrings, + NULL + ); + if (gHiiHandle == NULL){ + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // + // In order to look for the update data file and programmed image file + // from the same volume which this driver is dispatched from, we need + // to get the device path of this driver image. It is done by first + // locate the LoadedImageProtocol and then get its device path + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImageProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + goto EXIT; + } + // + // Get the firmware volume protocol where this file resides + // + Status = gBS->HandleProtocol ( + LoadedImageProtocol->DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + (VOID **) &FwVolProtocol + ); + if (EFI_ERROR (Status)) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + goto EXIT; + } + + // + // Shall do some extra check to see if it is really contained in the FV? + // Should be able to find the section of this driver in the the FV. + // + FilePathNode = LoadedImageProtocol->FilePath; + FwVolFilePathNode = NULL; + while (!IsDevicePathEnd (FilePathNode)) { + if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) { + FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode; + break; + } + FilePathNode = NextDevicePathNode (FilePathNode); + } + + if (FwVolFilePathNode == NULL){ + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + Status = EFI_NOT_FOUND; + goto EXIT; + } + + AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode); + + SectionType = EFI_SECTION_PE32; + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadSection ( + FwVolProtocol, + &(AlignedDevPathNode->FvFileName), + SectionType, + 0, + (VOID **) &FileBuffer, + &FileBufferSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + goto EXIT; + } + + if (FileBuffer != NULL) { + FreePool(FileBuffer); + FileBuffer = NULL; + } + + // + // Check the NameGuid of the udpate driver so that it can be + // used as the CallerId in fault tolerant write protocol + // + if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + Status = EFI_NOT_FOUND; + goto EXIT; + } + + FreePool (AlignedDevPathNode); + AlignedDevPathNode = NULL; + + + + + // + // Now try to find the script file. The script file is usually + // a raw data file which does not contain any sections. + // + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &gEfiConfigFileNameGuid, + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + goto EXIT; + } + if (FileType != EFI_FV_FILETYPE_RAW) { + return EFI_NOT_FOUND; + } + + // + // Parse the configuration file. + // + ConfigData = NULL; + NumOfUpdates = 0; + Status = ParseUpdateDataFile ( + FileBuffer, + FileBufferSize, + &NumOfUpdates, + &ConfigData + ); + if (FileBuffer != NULL) { + FreePool (FileBuffer); + FileBuffer = NULL; + } + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (ConfigData != NULL); + + // + // Now find the update image. The update image should be put in a FV, and then + // encapsulated as a raw FFS file. This is to prevent the update image from + // being dispatched. So the raw data we get here should be an FV. We need to + // process this FV and read the files that is going to be updated. + // + FileBuffer = NULL; + FileBufferSize = 0; + Status = FwVolProtocol->ReadFile ( + FwVolProtocol, + &gEfiUpdateDataFileGuid, + (VOID **) &FileBuffer, + &FileBufferSize, + &FileType, + &Attrib, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (FileType != EFI_FV_FILETYPE_RAW) { + return EFI_NOT_FOUND; + } + + // + // FileBuffer should be an FV. Process the FV + // + DataFwVolProtocol = NULL; + Status = ProcessUpdateImage ( + FileBuffer, + FileBufferSize, + &DataFwVolProtocol + ); + if (EFI_ERROR (Status)) { + FreePool (FileBuffer); + return Status; + } + + // + // Print on screen + // + TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL); + if (TmpStr != NULL) { + Print (TmpStr); + FreePool(TmpStr); + } + + // + // Execute the update + // + Index = 0; + UpdateConfigData = ConfigData; + while (Index < NumOfUpdates) { + Status = PerformUpdate ( + DataFwVolProtocol, + UpdateConfigData + ); + // + // Shall updates be serialized so that if an update is not successfully completed, + // the remaining updates won't be performed. + // + if (EFI_ERROR (Status)) { + NewEsrtTemplate.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + goto EXIT; + } + + Index++; + UpdateConfigData++; + } + + +EXIT: + + // + // Sucessfully done update job. + // Need to update system firmware Esrt entry + // + EsrtManagement = NULL; + StatusEsrt = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **) &EsrtManagement); + if (!EFI_ERROR(StatusEsrt)) { + EsrtManagement->UpdateEsrtEntry(&NewEsrtTemplate); + } + + // + // Do cleanup. + // + if (gHiiHandle != NULL) { + HiiRemovePackages (gHiiHandle); + } + + if (AlignedDevPathNode != NULL) { + FreePool (AlignedDevPathNode); + } + + if (FileBuffer != NULL) { + FreePool(FileBuffer); + } + + if (ConfigData != NULL) { + FreePool(ConfigData); + } + + return Status; +} diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriver.h b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriver.h new file mode 100644 index 0000000000..ca0bf9c702 --- /dev/null +++ b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriver.h @@ -0,0 +1,217 @@ +/** @file + Common defines and definitions for a component update driver. + + Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef _EFI_UPDATE_DRIVER_H_ +#define _EFI_UPDATE_DRIVER_H_ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE gHiiHandle; + +typedef enum { + UpdateWholeFV = 0, // 0, update whole FV + UpdateFvFile, // 1, update a set of FV files asynchronously + UpdateFvRange, // 2, update part of FV or flash + UpdateOperationMaximum // 3 +} UPDATE_OPERATION_TYPE; + +typedef struct { + UINTN Index; + UPDATE_OPERATION_TYPE UpdateType; + EFI_DEVICE_PATH_PROTOCOL DevicePath; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_GUID FileGuid; + UINTN Length; + BOOLEAN FaultTolerant; +} UPDATE_CONFIG_DATA; + +typedef struct _SECTION_ITEM SECTION_ITEM; +struct _SECTION_ITEM { + CHAR8 *ptrSection; + UINTN SecNameLen; + CHAR8 *ptrEntry; + CHAR8 *ptrValue; + SECTION_ITEM *ptrNext; +}; + +typedef struct _COMMENT_LINE COMMENT_LINE; +struct _COMMENT_LINE { + CHAR8 *ptrComment; + COMMENT_LINE *ptrNext; +}; + +typedef struct { + EFI_GUID FileGuid; +} UPDATE_PRIVATE_DATA; + +#define MAX_LINE_LENGTH 512 +#define EFI_D_UPDATE EFI_D_ERROR + +#define MIN_ALIGNMENT_SIZE 4 +#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0) + +/** + Parse Config data file to get the updated data array. + + @param DataBuffer Config raw file buffer. + @param BufferSize Size of raw buffer. + @param NumOfUpdates Pointer to the number of update data. + @param UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT UINTN *NumOfUpdates, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ); + +/** + Update the whole FV image, and reinsall FVB protocol for the updated FV image. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + + @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV. + Or Image size is not same to the size of whole FV. + @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated. + @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled. + +**/ +EFI_STATUS +PerformUpdateOnWholeFv ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize + ); + +/** + Update certain file in the FV. + + @param FvbHandle Handle of FVB protocol for the updated flash range. + @param FvbProtocol FVB protocol. + @param ConfigData Config data on updating driver. + @param ImageBuffer Image buffer to be updated. + @param ImageSize Image size. + @param FileType FFS file type. + @param FileAttributes FFS file attribute + + @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile. + Or Image size is not same to the size of whole FV. + @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated. + @retval EFI_SUCCESS The FFS file is added into FV. + +**/ +EFI_STATUS +PerformUpdateOnFvFile ( + IN EFI_HANDLE FvbHandle, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN UPDATE_CONFIG_DATA *ConfigData, + IN UINT8 *ImageBuffer, + IN UINTN ImageSize, + IN EFI_FV_FILETYPE FileType, + IN EFI_FV_FILE_ATTRIBUTES FileAttributes + ); + +/** + Update the buffer into flash area in fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param ConfigData Config data on updating driver. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_NOT_FOUND FTW protocol doesn't exist. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + @retval EFI_ABORTED Error happen when update flash area. + +**/ +EFI_STATUS +FaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN UPDATE_CONFIG_DATA *ConfigData, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ); + +/** + Directly update the buffer into flash area without fault tolerant write method. + + @param ImageBuffer Image buffer to be updated. + @param SizeLeft Size of the image buffer. + @param UpdatedSize Size of the updated buffer. + @param FlashAddress Flash address to be updated as start address. + @param FvbProtocol FVB protocol. + @param FvbHandle Handle of FVB protocol for the updated flash range. + + @retval EFI_SUCCESS Buffer data is updated into flash. + @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. + @retval EFI_OUT_OF_RESOURCES No enough backup space. + +**/ +EFI_STATUS +NonFaultTolerantUpdateOnPartFv ( + IN UINT8 *ImageBuffer, + IN UINTN SizeLeft, + IN OUT UINTN *UpdatedSize, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, + IN EFI_HANDLE FvbHandle + ); + +#endif diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.inf b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.inf new file mode 100644 index 0000000000..8ecce74596 --- /dev/null +++ b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.inf @@ -0,0 +1,82 @@ +## @file +# Update Driver for Capulse update. +# +# This driver is intended to be put in a capsule (FV). If all goes well, +# then it should be dispatched from the capsule FV, then find the image +# in the same FV and program it in a target Firmware Volume device. +# +# Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UpdateDriverDxe + MODULE_UNI_FILE = UpdateDriverDxe.uni + FILE_GUID = 0E84FC69-29CC-4C6D-92AC-6D476921850F + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeUpdateDriver + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + UpdateDriver.h + UpdateStrings.uni + UpdateDispatcher.c + ParseUpdateProfile.c + FlashUpdate.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + Vlv2TbltDevicePkg/PlatformPkg.dec + +[LibraryClasses] + BaseLib + PrintLib + HiiLib + DxeServicesTableLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + DevicePathLib + PcdLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES + +[Guids] + gEfiConfigFileNameGuid ## CONSUMES ## File # FileName to store ConfigFile + gEfiUpdateDataFileGuid ## CONSUMES ## File # FileName to store Capsule Data. + gSystemFwClassGuid ## CONSUMES + +[Protocols] + gEfiFaultTolerantWriteProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + gEsrtManagementProtocolGuid ## SOMETIMES_CONSUME + +[Depex] + gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid + diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.uni b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.uni new file mode 100644 index 0000000000..d020e42ab2 Binary files /dev/null and b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateDriverDxe.uni differ diff --git a/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateStrings.uni b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateStrings.uni new file mode 100644 index 0000000000..84e73c2386 Binary files /dev/null and b/Vlv2TbltDevicePkg/UpdateDriverDxe/UpdateStrings.uni differ -- cgit v1.2.3