From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id A58FA81886 for ; Fri, 23 Dec 2016 23:51:18 -0800 (PST) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP; 23 Dec 2016 23:51:18 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,398,1477983600"; d="scan'208";a="206359288" Received: from jyao1-mobl.ccr.corp.intel.com ([10.254.214.50]) by fmsmga004.fm.intel.com with ESMTP; 23 Dec 2016 23:51:15 -0800 From: Jiewen Yao To: edk2-devel@lists.01.org Cc: Feng Tian , Star Zeng , Chao Zhang Date: Sat, 24 Dec 2016 15:51:05 +0800 Message-Id: <1482565865-9500-1-git-send-email-jiewen.yao@intel.com> X-Mailer: git-send-email 2.7.4.windows.1 Subject: [PATCH] MdeModulePkg/CapsuleLib: Follow UEFI 22.2.3 to process FMP. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 24 Dec 2016 07:51:18 -0000 Previous logic does not follow UEFI 22.2.3 to process FMP strictly. It may cause FMP image not be processed in some corner case. The updated logic follows UEFI 22.2.3. The way to check if a capsule is processed is also simplified. The function - ProcessFmpCapsuleImage() is too big, so that we created sub-functions - StartFmpImage(), DumpAllFmpInfo(), GetFmpHandleBufferByType(), SetFmpImageData(), RecordFmpCapsuleStatus() to improve the readability. The function - ProcessTheseCapsules() is too big, so that we created sub-functions - InitCapsulePtr(), AreAllImagesProcessed(), PopulateCapsuleInConfigurationTable() to improve the readability. Cc: Feng Tian Cc: Star Zeng Cc: Chao Zhang Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao --- MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c | 883 +++++++++++++------- MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c | 333 ++++---- MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c | 109 +-- MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c | 20 - 4 files changed, 785 insertions(+), 560 deletions(-) diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c index 2bb6ac8..71e05bd 100644 --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c @@ -47,8 +47,6 @@ #include #include -BOOLEAN mAreAllImagesProcessed; - EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL; BOOLEAN mIsVirtualAddrConverted = FALSE; BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE; @@ -62,23 +60,6 @@ InitCapsuleVariable ( ); /** - Check if this FMP capsule is processed. - - @param[in] CapsuleHeader The capsule image header - @param[in] PayloadIndex FMP payload index - @param[in] ImageHeader FMP image header - - @retval TRUE This FMP capsule is processed. - @retval FALSE This FMP capsule is not processed. -**/ -BOOLEAN -IsFmpCapsuleProcessed ( - IN EFI_CAPSULE_HEADER *CapsuleHeader, - IN UINTN PayloadIndex, - IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader - ); - -/** Record capsule status variable. @param[in] CapsuleHeader The capsule image header @@ -769,6 +750,520 @@ DumpFmpCapsule ( } /** + Dump all FMP information. +**/ +VOID +DumpAllFmpInfo ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN Index; + UINTN ImageInfoSize; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + return ; + } + + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &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 = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + continue; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index)); + DumpFmpImageInfo( + ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + FmpImageInfoDescriptorVer, // DescriptorVersion + FmpImageInfoCount, // DescriptorCount + DescriptorSize, // DescriptorSize + PackageVersion, // PackageVersion + PackageVersionName // PackageVersionName + ); + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + FreePool(FmpImageInfoBuf); + } + + return ; +} + +/** + Get FMP handle by ImageTypeId and HardwareInstance. + + @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update. + @param[in] UpdateHardwareInstance The HardwareInstance to target with this update. + @param[in,out] NoHandles The number of handles returned in Buffer. + @param[out] Buffer[out] A pointer to the buffer to return the requested array of handles. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NoHandles. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. +**/ +EFI_STATUS +GetFmpHandleBufferByType ( + IN EFI_GUID *UpdateImageTypeId, + IN UINT64 UpdateHardwareInstance, + IN OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_HANDLE *MatchedHandleBuffer; + UINTN MatchedNumberOfHandles; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN Index; + UINTN ImageInfoSize; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + UINTN Index2; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo; + + *NoHandles = 0; + *Buffer = NULL; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + return Status; + } + + MatchedNumberOfHandles = 0; + MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles); + if (MatchedHandleBuffer == NULL) { + FreePool (HandleBuffer); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &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 = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + continue; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + TempFmpImageInfo = FmpImageInfoBuf; + for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) { + // + // Check if this FMP instance matches + // + if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) { + if ((UpdateHardwareInstance == 0) || + ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) && + (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) { + MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index]; + MatchedNumberOfHandles++; + break; + } + } + TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize); + } + FreePool(FmpImageInfoBuf); + } + + if (MatchedNumberOfHandles == 0) { + return EFI_NOT_FOUND; + } + + *NoHandles = MatchedNumberOfHandles; + *Buffer = MatchedHandleBuffer; + + return EFI_SUCCESS; +} + +/** + Return FmpImageInfoDescriptorVer by an FMP handle. + + @param[in] Handle A FMP handle. + + @return FmpImageInfoDescriptorVer associated with the FMP. +**/ +UINT32 +GetFmpImageInfoDescriptorVer ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN ImageInfoSize; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + + Status = gBS->HandleProtocol( + Handle, + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + return 0; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + return 0; + } + + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + return 0; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + return 0; + } + return FmpImageInfoDescriptorVer; +} + +/** + Set FMP image data. + + @param[in] Handle A FMP handle. + @param[in] ImageHeader The payload image header. + @param[in] PayloadIndex The index of the payload. + + @return The status of FMP->SetImage. +**/ +EFI_STATUS +SetFmpImageData ( + IN EFI_HANDLE Handle, + IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader, + IN UINTN PayloadIndex + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINT8 *Image; + VOID *VendorCode; + CHAR16 *AbortReason; + + Status = gBS->HandleProtocol( + Handle, + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + Image = (UINT8 *)(ImageHeader + 1); + } else { + // + // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, + // Header should exclude UpdateHardwareInstance field + // + Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance); + } + + if (ImageHeader->UpdateVendorCodeSize == 0) { + VendorCode = NULL; + } else { + VendorCode = Image + ImageHeader->UpdateImageSize; + } + AbortReason = NULL; + DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n")); + DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId)); + DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex)); + DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex)); + if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance)); + } + DEBUG((DEBUG_INFO, "\n")); + Status = Fmp->SetImage( + Fmp, + ImageHeader->UpdateImageIndex, // ImageIndex + Image, // Image + ImageHeader->UpdateImageSize, // ImageSize + VendorCode, // VendorCode + Update_Image_Progress, // Progress + &AbortReason // AbortReason + ); + DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status)); + if (AbortReason != NULL) { + DEBUG ((DEBUG_ERROR, "%s\n", AbortReason)); + FreePool(AbortReason); + } + + return Status; +} + +/** + Start a UEFI image in the FMP payload. + + @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded.. + @param[in] ImageSize The size in bytes of ImageBuffer. + + @return The status of gBS->LoadImage and gBS->StartImage. +**/ +EFI_STATUS +StartFmpImage ( + IN VOID *ImageBuffer, + IN UINTN ImageSize + ) +{ + MEMMAP_DEVICE_PATH MemMapNode; + EFI_STATUS Status; + EFI_HANDLE ImageHandle; + EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath; + UINTN ExitDataSize; + + 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)ImageBuffer; + MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1); + + DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header); + if (DriverDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n")); + Status = gBS->LoadImage( + FALSE, + gImageHandle, + DriverDevicePath, + ImageBuffer, + ImageSize, + &ImageHandle + ); + DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status)); + if (EFI_ERROR(Status)) { + FreePool(DriverDevicePath); + return Status; + } + + DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n")); + Status = gBS->StartImage( + ImageHandle, + &ExitDataSize, + NULL + ); + DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status)); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status)); + } + + FreePool(DriverDevicePath); + return Status; +} + +/** + Record FMP capsule status. + + @param[in] Handle A FMP handle. + @param[in] CapsuleHeader The capsule image header + @param[in] CapsuleStatus The capsule process stauts + @param[in] PayloadIndex FMP payload index + @param[in] ImageHeader FMP image header +**/ +VOID +RecordFmpCapsuleStatus ( + IN EFI_HANDLE Handle, OPTIONAL + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN EFI_STATUS CapsuleStatus, + IN UINTN PayloadIndex, + IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath; + UINT32 FmpImageInfoDescriptorVer; + EFI_STATUS StatusEsrt; + ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; + EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; + + FmpDevicePath = NULL; + if (Handle != NULL) { + gBS->HandleProtocol( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID **)&FmpDevicePath + ); + } + + RecordFmpCapsuleStatusVariable ( + CapsuleHeader, + CapsuleStatus, + PayloadIndex, + ImageHeader, + FmpDevicePath + ); + + // + // Update corresponding ESRT entry LastAttemp Status + // + Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); + if (EFI_ERROR (Status)) { + return ; + } + + if (Handle == NULL) { + return ; + } + + // + // Update EsrtEntry For V1, V2 FMP instance. + // V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface + // + FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle); + if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) { + StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry); + if (!EFI_ERROR(StatusEsrt)){ + if (!EFI_ERROR(CapsuleStatus)) { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + } else { + EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + EsrtEntry.LastAttemptVersion = 0; + EsrtProtocol->UpdateEsrtEntry(&EsrtEntry); + } + } +} + +/** Process Firmware management protocol data capsule. This function assumes the caller validated the capsule by using @@ -779,65 +1274,38 @@ DumpFmpCapsule ( This function need support nested FMP capsule. @param[in] CapsuleHeader Points to a capsule header. - @param[out] AreAllImagesProcessed If all the FMP images in the capsule are processed. @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. + @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule. **/ EFI_STATUS ProcessFmpCapsuleImage ( - IN EFI_CAPSULE_HEADER *CapsuleHeader, - OUT BOOLEAN *AreAllImagesProcessed + IN EFI_CAPSULE_HEADER *CapsuleHeader ) { EFI_STATUS Status; - EFI_STATUS StatusEsrt; - EFI_STATUS StatusRet; EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 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; + UINT64 UpdateHardwareInstance; UINTN Index2; - MEMMAP_DEVICE_PATH MemMapNode; - EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath; - EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath; - ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol; - EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry; - VOID *VendorCode; + BOOLEAN NotReady; + BOOLEAN Abort; if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) { - return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), AreAllImagesProcessed); + return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize)); } - ASSERT(AreAllImagesProcessed != NULL); - - Status = EFI_SUCCESS; - StatusRet = EFI_NOT_FOUND; - HandleBuffer = NULL; - ExitDataSize = 0; - DriverDevicePath = NULL; - EsrtProtocol = NULL; - *AreAllImagesProcessed = FALSE; + NotReady = FALSE; + Abort = FALSE; DumpFmpCapsule(CapsuleHeader); @@ -854,35 +1322,15 @@ ProcessFmpCapsuleImage ( // capsule in which driver count and payload count are both zero is not processed. // if (ItemNum == 0) { - *AreAllImagesProcessed = TRUE; return EFI_SUCCESS; } // - // Update corresponding ESRT entry LastAttemp Status - // - Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol); - if (EFI_ERROR (Status)) { - EsrtProtocol = NULL; - } - - // // 1. 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) { + 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 // @@ -891,32 +1339,13 @@ ProcessFmpCapsuleImage ( DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index]; } - DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n")); - Status = gBS->LoadImage( - FALSE, - gImageHandle, - DriverDevicePath, - (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index], - DriverLen, - &ImageHandle - ); - DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status)); - if (EFI_ERROR(Status)) { - StatusRet = Status; - goto EXIT; - } - - DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n")); - Status = gBS->StartImage( - ImageHandle, - &ExitDataSize, - NULL - ); - DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status)); + Status = StartFmpImage ( + (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index], + DriverLen + ); if (EFI_ERROR(Status)) { DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status)); - StatusRet = Status; - goto EXIT; + return Status; } } @@ -925,207 +1354,80 @@ ProcessFmpCapsuleImage ( // DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n")); - 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; - } - - FmpDevicePath = NULL; - gBS->HandleProtocol( - HandleBuffer[Index1], - &gEfiDevicePathProtocolGuid, - (VOID **)&FmpDevicePath - ); + DumpAllFmpInfo (); - ImageInfoSize = 0; - Status = Fmp->GetImageInfo ( - Fmp, - &ImageInfoSize, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - ); - if (Status != EFI_BUFFER_TOO_SMALL) { - continue; - } + // + // 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]); - FmpImageInfoBuf = NULL; - FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); - if (FmpImageInfoBuf == NULL) { - StatusRet = EFI_OUT_OF_RESOURCES; - goto EXIT; - } + UpdateHardwareInstance = 0; + if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance; + } - PackageVersionName = NULL; - Status = Fmp->GetImageInfo ( - Fmp, - &ImageInfoSize, // ImageInfoSize - FmpImageInfoBuf, // ImageInfo - &FmpImageInfoDescriptorVer, // DescriptorVersion - &FmpImageInfoCount, // DescriptorCount - &DescriptorSize, // DescriptorSize - &PackageVersion, // PackageVersion - &PackageVersionName // PackageVersionName - ); + Status = GetFmpHandleBufferByType ( + &ImageHeader->UpdateImageTypeId, + UpdateHardwareInstance, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + NotReady = TRUE; + RecordFmpCapsuleStatus ( + NULL, + CapsuleHeader, + EFI_NOT_READY, + Index - FmpCapsuleHeader->EmbeddedDriverCount, + ImageHeader + ); + continue; + } - // - // If FMP GetInformation interface failed, skip this resource - // - if (EFI_ERROR(Status)) { - FreePool(FmpImageInfoBuf); + for (Index2 = 0; Index2 < NumberOfHandles; Index2++) { + if (Abort) { + RecordFmpCapsuleStatus ( + HandleBuffer[Index2], + CapsuleHeader, + EFI_ABORTED, + Index - FmpCapsuleHeader->EmbeddedDriverCount, + ImageHeader + ); continue; } - DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index)); - DumpFmpImageInfo( - ImageInfoSize, // ImageInfoSize - FmpImageInfoBuf, // ImageInfo - FmpImageInfoDescriptorVer, // DescriptorVersion - FmpImageInfoCount, // DescriptorCount - DescriptorSize, // DescriptorSize - PackageVersion, // PackageVersion - PackageVersionName // PackageVersionName - ); - - if (PackageVersionName != NULL) { - FreePool(PackageVersionName); + Status = SetFmpImageData ( + HandleBuffer[Index2], + ImageHeader, + Index - FmpCapsuleHeader->EmbeddedDriverCount + ); + if (Status != EFI_SUCCESS) { + Abort = TRUE; } - 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 (IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) { - DEBUG((DEBUG_INFO, "FMP Capsule already processed (%g):", CapsuleHeader)); - DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId)); - DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ImageIndex - 0x%x\n", Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader->UpdateImageIndex)); - continue; - } - - if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) { - 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 + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance); - } - - if (ImageHeader->UpdateVendorCodeSize == 0) { - VendorCode = NULL; - } else { - VendorCode = Image + ImageHeader->UpdateImageSize; - } - DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n")); - Status = Fmp->SetImage( - Fmp, - ImageHeader->UpdateImageIndex, // ImageIndex - Image, // Image - ImageHeader->UpdateImageSize, // ImageSize - VendorCode, // VendorCode - Update_Image_Progress, // Progress - &AbortReason // AbortReason - ); - DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status)); - if (AbortReason != NULL) { - DEBUG ((DEBUG_ERROR, "%s\n", AbortReason)); - FreePool(AbortReason); - } - RecordFmpCapsuleStatusVariable( - CapsuleHeader, // CapsuleGuid - Status, // CapsuleStatus - Index - FmpCapsuleHeader->EmbeddedDriverCount, // PayloadIndex - ImageHeader, // ImageHeader - FmpDevicePath // FmpDevicePath - ); - if (StatusRet != EFI_SUCCESS) { - StatusRet = Status; - } - // - // 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(&TempFmpImageInfo->ImageTypeId, &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); + RecordFmpCapsuleStatus ( + HandleBuffer[Index2], + CapsuleHeader, + Status, + Index - FmpCapsuleHeader->EmbeddedDriverCount, + ImageHeader + ); } - } - - // - // final check for AreAllImagesProcessed - // - *AreAllImagesProcessed = TRUE; - for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) { - ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); - - if (!IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) { - *AreAllImagesProcessed = FALSE; - break; + if (HandleBuffer != NULL) { + FreePool(HandleBuffer); } } -EXIT: - - if (HandleBuffer != NULL) { - FreePool(HandleBuffer); - } - - if (DriverDevicePath != NULL) { - FreePool(DriverDevicePath); + if (NotReady) { + return EFI_NOT_READY; } - return StatusRet; + // + // always return SUCCESS to indicate this capsule is processed. + // The status of SetImage is recorded in capsule result variable. + // + return EFI_SUCCESS; } /** @@ -1278,9 +1580,9 @@ ProcessCapsuleImage ( ) { EFI_STATUS Status; - BOOLEAN AreAllImagesProcessed; if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) { + RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED); return EFI_UNSUPPORTED; } @@ -1303,6 +1605,7 @@ ProcessCapsuleImage ( Status = ValidateFmpCapsule(CapsuleHeader, NULL); DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status)); if (EFI_ERROR(Status)) { + RecordCapsuleStatusVariable(CapsuleHeader, Status); return Status; } @@ -1310,13 +1613,9 @@ ProcessCapsuleImage ( // Press EFI FMP Capsule // DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n")); - Status = ProcessFmpCapsuleImage(CapsuleHeader, &AreAllImagesProcessed); + Status = ProcessFmpCapsuleImage(CapsuleHeader); DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status)); - if (!AreAllImagesProcessed) { - mAreAllImagesProcessed = FALSE; - } - return Status; } diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c index 62257a4..ba3ff90 100644 --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c @@ -95,60 +95,23 @@ IsValidCapsuleHeader ( ); extern BOOLEAN mDxeCapsuleLibEndOfDxe; -extern BOOLEAN mAreAllImagesProcessed; BOOLEAN mNeedReset; -/** - - This routine is called to process capsules. - - Caution: This function may receive untrusted input. - - Each individual capsule result is recorded in capsule record variable. - - @param[in] NeedBlockDriver TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount. - FALSE: No need to skip any FMP capsules. - - @retval EFI_SUCCESS There is no error when processing capsules. - @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules. +VOID **mCapsulePtr; +EFI_STATUS *mCapsuleStatusArray; +UINT32 mCapsuleTotalNumber; +/** + This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber. **/ -EFI_STATUS -ProcessTheseCapsules ( - IN BOOLEAN NeedBlockDriver +VOID +InitCapsulePtr ( + 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; - EFI_STATUS *CapsuleStatusArray; - BOOLEAN DisplayCapsuleExist; - ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; - UINT16 EmbeddedDriverCount; - - REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin))); + UINTN Index; - CapsuleNumber = 0; - CapsuleTotalNumber = 0; - CacheIndex = 0; - CacheNumber = 0; - CapsulePtr = NULL; - CapsulePtrCache = NULL; - CapsuleGuidCache = NULL; - DisplayCapsuleExist = FALSE; - EsrtManagement = NULL; - - Status = EFI_SUCCESS; // // Find all capsule images from hob // @@ -157,61 +120,108 @@ ProcessTheseCapsules ( if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) { HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid } else { - CapsuleTotalNumber++; + mCapsuleTotalNumber++; } HobPointer.Raw = GET_NEXT_HOB (HobPointer); } - if (CapsuleTotalNumber == 0) { - // - // We didn't find a hob, so had no errors. - // - DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n")); - Status = EFI_SUCCESS; - goto Done; + DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber)); + + if (mCapsuleTotalNumber == 0) { + return ; } // // Init temp Capsule Data table. // - CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); - ASSERT (CapsulePtr != NULL); - if (CapsulePtr == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); - ASSERT (CapsulePtrCache != NULL); - if (CapsulePtrCache == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; + mCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber); + if (mCapsulePtr == NULL) { + DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n")); + mCapsuleTotalNumber = 0; + return ; } - CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber); - ASSERT (CapsuleGuidCache != NULL); - if (CapsuleGuidCache == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - CapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * CapsuleTotalNumber); - ASSERT (CapsuleStatusArray != NULL); - if (CapsuleStatusArray == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; + mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber); + if (mCapsuleStatusArray == NULL) { + DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n")); + FreePool (mCapsulePtr); + mCapsulePtr = NULL; + mCapsuleTotalNumber = 0; + return ; } + SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY); // // Find all capsule images from hob // HobPointer.Raw = GetHobList (); + Index = 0; while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { - CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress; + mCapsulePtr [Index++] = (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 - // +/** + This function returns if all capsule images are processed. + + @retval TRUE All capsule images are processed. + @retval FALSE Not all capsule images are processed. +**/ +BOOLEAN +AreAllImagesProcessed ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < mCapsuleTotalNumber; Index++) { + if (mCapsuleStatusArray[Index] == EFI_NOT_READY) { + return FALSE; + } + } + + return TRUE; +} + +/** + This function populates capsule in the configuration table. +**/ +VOID +PopulateCapsuleInConfigurationTable ( + VOID + ) +{ + VOID **CapsulePtrCache; + EFI_GUID *CapsuleGuidCache; + EFI_CAPSULE_HEADER *CapsuleHeader; + EFI_CAPSULE_TABLE *CapsuleTable; + UINT32 CacheIndex; + UINT32 CacheNumber; + UINT32 CapsuleNumber; + UINTN Index; + UINTN Size; + EFI_STATUS Status; + + if (mCapsuleTotalNumber == 0) { + return ; + } + + CapsulePtrCache = NULL; + CapsuleGuidCache = NULL; + CacheIndex = 0; + CacheNumber = 0; + + CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber); + if (CapsulePtrCache == NULL) { + DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n")); + return ; + } + CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber); + if (CapsuleGuidCache == NULL) { + DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n")); + FreePool (CapsulePtrCache); + return ; + } // // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating @@ -223,9 +233,8 @@ ProcessTheseCapsules ( // 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++) { - CapsuleStatusArray [Index] = EFI_UNSUPPORTED; - CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + for (Index = 0; Index < mCapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { // // For each capsule, we compare it with known CapsuleGuid in the CacheArray. @@ -254,38 +263,90 @@ ProcessTheseCapsules ( // 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) { + for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) { CapsuleNumber = 0; - for (Index = 0; Index < CapsuleTotalNumber; Index++) { - CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; + for (Index = 0; Index < mCapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [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; - // - // When a Capsule is listed in CapsulePtrCache, it will be reported in ConfigurationTable - // So, report the CapsuleStatus as "processed successfully". - // - CapsuleStatusArray [Index] = EFI_SUCCESS; } } } if (CapsuleNumber != 0) { Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*); CapsuleTable = AllocateRuntimePool (Size); - ASSERT (CapsuleTable != NULL); if (CapsuleTable == NULL) { - return EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex])); + continue; } CapsuleTable->CapsuleArrayNumber = CapsuleNumber; CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*)); Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable); - ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex])); + } } - CacheIndex++; + } + + FreePool(CapsuleGuidCache); + FreePool(CapsulePtrCache); +} + +/** + + This routine is called to process capsules. + + Caution: This function may receive untrusted input. + + Each individual capsule result is recorded in capsule record variable. + + @param[in] FirstRound TRUE: First round. Need skip the FMP capsules with non zero EmbeddedDriverCount. + FALSE: Process rest FMP capsules. + + @retval EFI_SUCCESS There is no error when processing capsules. + @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules. + +**/ +EFI_STATUS +ProcessTheseCapsules ( + IN BOOLEAN FirstRound + ) +{ + EFI_STATUS Status; + EFI_CAPSULE_HEADER *CapsuleHeader; + UINT32 Index; + BOOLEAN DisplayCapsuleExist; + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + UINT16 EmbeddedDriverCount; + + REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin))); + + if (FirstRound) { + InitCapsulePtr (); + } + + if (mCapsuleTotalNumber == 0) { + // + // We didn't find a hob, so had no errors. + // + DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n")); + return EFI_SUCCESS; + } + + if (AreAllImagesProcessed ()) { + return EFI_SUCCESS; + } + + // + // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install + // capsuleTable to configure table with EFI_CAPSULE_GUID + // + if (FirstRound) { + PopulateCapsuleInConfigurationTable (); } REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware))); @@ -293,15 +354,16 @@ ProcessTheseCapsules ( // // If Windows UX capsule exist, process it first // - for (Index = 0; Index < CapsuleTotalNumber; Index++) { - CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; - if (CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) { + DisplayCapsuleExist = FALSE; + for (Index = 0; Index < mCapsuleTotalNumber; Index++) { + CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index]; + if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { DEBUG ((DEBUG_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader)); DisplayCapsuleExist = TRUE; DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n")); Status = ProcessCapsuleImage (CapsuleHeader); + mCapsuleStatusArray [Index] = EFI_SUCCESS; DEBUG((DEBUG_INFO, "ProcessCapsuleImage (Ux) - %r\n", Status)); - CapsuleStatusArray [Index] = Status; break; } } @@ -316,38 +378,48 @@ ProcessTheseCapsules ( // // All capsules left are recognized by platform. // - for (Index = 0; Index < CapsuleTotalNumber; Index++) { - CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; - if (!CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) { + for (Index = 0; Index < mCapsuleTotalNumber; Index++) { + if (mCapsuleStatusArray [Index] != EFI_NOT_READY) { + // already processed + continue; + } + CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index]; + if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { // // Call capsule library to process capsule image. // EmbeddedDriverCount = 0; if (IsFmpCapsule(CapsuleHeader)) { - Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount); + Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount); if (EFI_ERROR(Status)) { DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n")); + mCapsuleStatusArray [Index] = EFI_ABORTED; continue; } + } else { + mCapsuleStatusArray [Index] = EFI_ABORTED; + continue; } - if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) { + if ((!FirstRound) || (EmbeddedDriverCount == 0)) { DEBUG((DEBUG_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader)); Status = ProcessCapsuleImage (CapsuleHeader); - CapsuleStatusArray [Index] = Status; + mCapsuleStatusArray [Index] = Status; DEBUG((DEBUG_INFO, "ProcessCapsuleImage - %r\n", Status)); - if (EFI_ERROR(Status)) { - REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed))); - DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n")); - Print (L"Firmware update failed...\r\n"); - } else { - REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess))); - } - - if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 || - IsFmpCapsule(CapsuleHeader)) { - mNeedReset = TRUE; + if (Status != EFI_NOT_READY) { + if (EFI_ERROR(Status)) { + REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed))); + DEBUG ((DEBUG_ERROR, "Capsule process failed!\n")); + Print (L"Firmware update failed...\r\n"); + } else { + REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess))); + } + + if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 || + IsFmpCapsule(CapsuleHeader)) { + mNeedReset = TRUE; + } } } } @@ -362,20 +434,6 @@ ProcessTheseCapsules ( } Status = EFI_SUCCESS; -Done: - // - // Free the allocated temp memory space. - // - if (CapsuleGuidCache != NULL) { - FreePool(CapsuleGuidCache); - } - if (CapsulePtrCache != NULL) { - FreePool(CapsulePtrCache); - } - if (CapsulePtr != NULL) { - FreePool(CapsulePtr); - } - REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd))); return Status; @@ -446,20 +504,13 @@ ProcessCapsules ( EFI_STATUS Status; if (!mDxeCapsuleLibEndOfDxe) { - // - // Initialize mAreAllImagesProcessed to be TRUE. - // - // It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(), - // if there is any FMP image in any FMP capsule not processed. - // - mAreAllImagesProcessed = TRUE; - Status = ProcessTheseCapsules(TRUE); + // // Reboot System if and only if all capsule processed. // If not, defer reset to 2nd process. // - if (mNeedReset && mAreAllImagesProcessed) { + if (mNeedReset && AreAllImagesProcessed()) { DoResetSystem(); } } else { diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c index a591beb..7c7e610 100644 --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c @@ -35,17 +35,6 @@ #include -typedef struct { - EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader; - EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp; -} CAPSULE_RESULT_VARIABLE_CACHE; - -#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10 - -CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache; -UINTN mCapsuleResultVariableCacheMaxCount; -UINTN mCapsuleResultVariableCacheCount; - /** Get current capsule last variable index. @@ -78,92 +67,6 @@ GetCurrentCapsuleLastIndex ( } /** - Check if this FMP capsule is processed. - - @param[in] CapsuleHeader The capsule image header - @param[in] PayloadIndex FMP payload index - @param[in] ImageHeader FMP image header - - @retval TRUE This FMP capsule is processed. - @retval FALSE This FMP capsule is not processed. -**/ -BOOLEAN -IsFmpCapsuleProcessed ( - IN EFI_CAPSULE_HEADER *CapsuleHeader, - IN UINTN PayloadIndex, - IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader - ) -{ - UINTN Index; - EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult; - EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp; - - for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) { - // - // Check - // - CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader; - if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) { - if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) { - if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) { - CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1); - if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) && - (CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) && - (CapsuleResultFmp->PayloadIndex == PayloadIndex) ) { - return TRUE; - } - } - } - } - } - - return FALSE; -} - -/** - Write a new capsule status variable cache. - - @param[in] CapsuleResult The capsule status variable - @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes - - @retval EFI_SUCCESS The capsule status variable is cached. - @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable. -**/ -EFI_STATUS -WriteNewCapsuleResultVariableCache ( - IN VOID *CapsuleResult, - IN UINTN CapsuleResultSize - ) -{ - if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) { - CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE); - } - - if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) { - mCapsuleResultVariableCache = ReallocatePool( - mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE), - (mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE), - mCapsuleResultVariableCache - ); - if (mCapsuleResultVariableCache == NULL) { - return EFI_OUT_OF_RESOURCES; - } - mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT; - } - - ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount); - ASSERT(mCapsuleResultVariableCache != NULL); - CopyMem( - &mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount], - CapsuleResult, - CapsuleResultSize - ); - mCapsuleResultVariableCacheCount++; - - return EFI_SUCCESS; -} - -/** Get a new capsule status variable index. @return A new capsule status variable index. @@ -262,11 +165,7 @@ RecordCapsuleStatusVariable ( gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL); CapsuleResultVariable.CapsuleStatus = CapsuleStatus; - // - // Save Local Cache - // - Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable)); - + Status = EFI_SUCCESS; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable)); } @@ -338,11 +237,7 @@ RecordFmpCapsuleStatusVariable ( DevicePathStr = NULL; } - // - // Save Local Cache - // - Status = WriteNewCapsuleResultVariableCache(CapsuleResultVariable, CapsuleResultVariableSize); - + Status = EFI_SUCCESS; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize); } diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c index 6ab198d..a6860ef 100644 --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c @@ -20,26 +20,6 @@ #include /** - Check if this FMP capsule is processed. - - @param[in] CapsuleHeader The capsule image header - @param[in] PayloadIndex FMP payload index - @param[in] ImageHeader FMP image header - - @retval TRUE This FMP capsule is processed. - @retval FALSE This FMP capsule is not processed. -**/ -BOOLEAN -IsFmpCapsuleProcessed ( - IN EFI_CAPSULE_HEADER *CapsuleHeader, - IN UINTN PayloadIndex, - IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader - ) -{ - return FALSE; -} - -/** Record capsule status variable and to local cache. @param[in] CapsuleHeader The capsule image header -- 2.7.4.windows.1