summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c109
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.h61
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVol.c2
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h16
4 files changed, 161 insertions, 27 deletions
diff --git a/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
index 68f5ef5d64..5f8e383158 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 8cdfe06054..cf65c1526b 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 1e1cbae368..07cbbb94df 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 7cc775f69b..a614b93d1b 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.