From 2fc46f86f91daf139ffb1bf20500d8254f037d2b Mon Sep 17 00:00:00 2001 From: lgao4 Date: Thu, 15 Dec 2011 06:50:54 +0000 Subject: Enhance DXE dispatcher logic to check the duplicated FV image bases on FvHob2 and FvNameGuid per PI spec. Signed-off-by: lgao4 Reviewed-by: rsun3 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12874 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c | 109 +++++++++++++++++++++++--- MdeModulePkg/Core/Dxe/DxeMain.h | 61 ++++++++++++++ MdeModulePkg/Core/Dxe/FwVol/FwVol.c | 2 +- MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h | 16 ---- 4 files changed, 161 insertions(+), 27 deletions(-) diff --git a/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c index 68f5ef5..5f8e383 100644 --- a/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c @@ -708,25 +708,102 @@ FvHasBeenProcessed ( /** Remember that Fv protocol on FvHandle has had it's drivers placed on the - mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are - never removed/freed from the mFvHandleList. + mDiscoveredList. This fucntion adds entries on the mFvHandleList if new + entry is different from one in mFvHandleList by checking FvImage Guid. + Items are never removed/freed from the mFvHandleList. @param FvHandle The handle of a FV that has been processed + @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid + has been added, NULL will return. + **/ -VOID +KNOWN_HANDLE * FvIsBeingProcesssed ( IN EFI_HANDLE FvHandle ) { - KNOWN_HANDLE *KnownHandle; + EFI_STATUS Status; + EFI_GUID FvNameGuid; + BOOLEAN FvNameGuidIsFound; + UINT32 ExtHeaderOffset; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + UINTN LbaOffset; + UINTN Index; + EFI_LBA LbaIndex; + LIST_ENTRY *Link; + KNOWN_HANDLE *KnownHandle; - KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE)); + // + // Get the FirmwareVolumeBlock protocol on that handle + // + FvNameGuidIsFound = FALSE; + Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); + if (!EFI_ERROR (Status)) { + // + // Get the full FV header based on FVB protocol. + // + Status = GetFwVolHeader (Fvb, &FwVolHeader); + if (EFI_ERROR (Status)) { + FwVolHeader = NULL; + } else if (VerifyFvHeaderChecksum (FwVolHeader) && FwVolHeader->ExtHeaderOffset != 0) { + ExtHeaderOffset = (UINT32) FwVolHeader->ExtHeaderOffset; + BlockMap = FwVolHeader->BlockMap; + LbaIndex = 0; + LbaOffset = 0; + // + // Find LbaIndex and LbaOffset for FV extension header based on BlockMap. + // + while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) { + for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index ++) { + ExtHeaderOffset -= BlockMap->Length; + LbaIndex ++; + } + // + // Check whether FvExtHeader is crossing the multi block range. + // + if (Index < BlockMap->NumBlocks) { + LbaOffset = ExtHeaderOffset; + break; + } + BlockMap++; + } + // + // Read FvNameGuid from FV extension header. + // + Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid); + if (!EFI_ERROR (Status)) { + FvNameGuidIsFound = TRUE; + } + } + CoreFreePool (FwVolHeader); + } + + if (FvNameGuidIsFound) { + // + // Check whether the FV image with the found FvNameGuid has been processed. + // + for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) { + KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE); + if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) { + DEBUG ((EFI_D_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, FvNameGuid)); + return NULL; + } + } + } + + KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE)); ASSERT (KnownHandle != NULL); KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; KnownHandle->Handle = FvHandle; + if (FvNameGuidIsFound) { + CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid); + } InsertTailList (&mFvHandleList, &KnownHandle->Link); + return KnownHandle; } @@ -844,7 +921,7 @@ CoreAddToDriverList ( Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is described by a EFI_HOB_FIRMWARE_VOLUME2 Hob. - @param FvHandle The handle which FVB protocol installed on. + @param FvNameGuid The FV image guid specified. @param DriverName The driver guid specified. @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2 @@ -854,7 +931,7 @@ CoreAddToDriverList ( **/ BOOLEAN FvFoundInHobFv2 ( - IN EFI_HANDLE FvHandle, + IN CONST EFI_GUID *FvNameGuid, IN CONST EFI_GUID *DriverName ) { @@ -863,7 +940,11 @@ FvFoundInHobFv2 ( HobFv2.Raw = GetHobList (); while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { - if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName)) { + // + // Compare parent FvNameGuid and FileGuid both. + // + if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) && + CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName)) { return TRUE; } HobFv2.Raw = GET_NEXT_HOB (HobFv2); @@ -1021,6 +1102,7 @@ CoreFwVolEventProtocolNotify ( UINT32 AuthenticationStatus; UINTN SizeOfBuffer; VOID *DepexBuffer; + KNOWN_HANDLE *KnownHandle; while (TRUE) { BufferSize = sizeof (EFI_HANDLE); @@ -1048,7 +1130,14 @@ CoreFwVolEventProtocolNotify ( // // Since we are about to process this Fv mark it as processed. // - FvIsBeingProcesssed (FvHandle); + KnownHandle = FvIsBeingProcesssed (FvHandle); + if (KnownHandle == NULL) { + // + // The FV with the same FV name guid has already been processed. + // So lets skip it! + // + continue; + } Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); if (EFI_ERROR (Status) || Fv == NULL) { @@ -1131,7 +1220,7 @@ CoreFwVolEventProtocolNotify ( // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already // been extracted. // - if (FvFoundInHobFv2 (FvHandle, &NameGuid)) { + if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) { continue; } diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h index 8cdfe06..cf65c15 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.h +++ b/MdeModulePkg/Core/Dxe/DxeMain.h @@ -134,6 +134,7 @@ typedef struct { UINTN Signature; LIST_ENTRY Link; // mFvHandleList EFI_HANDLE Handle; + EFI_GUID FvNameGuid; } KNOWN_HANDLE; @@ -2489,4 +2490,64 @@ CoreEmptyCallbackFunction ( IN VOID *Context ); +/** + Read data from Firmware Block by FVB protocol Read. + The data may cross the multi block ranges. + + @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data. + @param StartLba Pointer to StartLba. + On input, the start logical block index from which to read. + On output,the end logical block index after reading. + @param Offset Pointer to Offset + On input, offset into the block at which to begin reading. + On output, offset into the end block after reading. + @param DataSize Size of data to be read. + @param Data Pointer to Buffer that the data will be read into. + + @retval EFI_SUCCESS Successfully read data from firmware block. + @retval others +**/ +EFI_STATUS +ReadFvbData ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + IN OUT EFI_LBA *StartLba, + IN OUT UINTN *Offset, + IN UINTN DataSize, + OUT UINT8 *Data + ); + +/** + Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and + copy the real length volume header into it. + + @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to + read the volume header + @param FwVolHeader Pointer to pointer to allocated buffer in which + the volume header is returned. + + @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated. + @retval EFI_SUCCESS Successfully read volume header to the allocated + buffer. + +**/ +EFI_STATUS +GetFwVolHeader ( + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader + ); + +/** + Verify checksum of the firmware volume header. + + @param FvHeader Points to the firmware volume header to be checked + + @retval TRUE Checksum verification passed + @retval FALSE Checksum verification failed + +**/ +BOOLEAN +VerifyFvHeaderChecksum ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ); + #endif diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c index 1e1cbae..07cbbb9 100644 --- a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c +++ b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c @@ -357,7 +357,7 @@ FvCheck ( // // Check whether FvHeader is crossing the multi block range. // - if (HeaderSize > BlockMap->Length) { + if (Index >= BlockMap->NumBlocks) { BlockMap++; continue; } else if (HeaderSize > 0) { diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h b/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h index 7cc775f..a614b93 100644 --- a/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h +++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h @@ -366,22 +366,6 @@ SetFileState ( IN EFI_FFS_FILE_HEADER *FfsHeader ); - -/** - Verify checksum of the firmware volume header. - - @param FvHeader Points to the firmware volume header to be checked - - @retval TRUE Checksum verification passed - @retval FALSE Checksum verification failed - -**/ -BOOLEAN -VerifyFvHeaderChecksum ( - IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader - ); - - /** Check if it's a valid FFS file header. -- cgit v1.1