summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Core/Dxe/FwVol/FwVol.c')
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVol.c170
1 files changed, 151 insertions, 19 deletions
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
index 5984b3f436..2829092e17 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
@@ -53,8 +53,114 @@ FV_DEVICE mFvDevice = {
// FFS helper functions
//
/**
- given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
- copy the volume header into it.
+ 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
+ )
+{
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN BlockIndex;
+ UINTN ReadDataSize;
+ EFI_STATUS Status;
+
+ //
+ // Try read data in current block
+ //
+ BlockIndex = 0;
+ ReadDataSize = DataSize;
+ Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
+ if (Status == EFI_SUCCESS) {
+ *Offset += DataSize;
+ return EFI_SUCCESS;
+ } else if (Status != EFI_BAD_BUFFER_SIZE) {
+ //
+ // other error will direct return
+ //
+ return Status;
+ }
+
+ //
+ // Data crosses the blocks, read data from next block
+ //
+ DataSize -= ReadDataSize;
+ Data += ReadDataSize;
+ *StartLba = *StartLba + 1;
+ while (DataSize > 0) {
+ Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read data from the crossing blocks
+ //
+ BlockIndex = 0;
+ while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Data += BlockSize;
+ DataSize -= BlockSize;
+ BlockIndex ++;
+ }
+
+ //
+ // Data doesn't exceed the current block range.
+ //
+ if (DataSize < BlockSize) {
+ break;
+ }
+
+ //
+ // Data must be got from the next block range.
+ //
+ *StartLba += NumberOfBlocks;
+ }
+
+ //
+ // read the remaining data
+ //
+ if (DataSize > 0) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Update Lba and Offset used by the following read.
+ //
+ *StartLba += BlockIndex;
+ *Offset = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
@@ -75,14 +181,17 @@ GetFwVolHeader (
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER TempFvh;
UINTN FvhLength;
+ EFI_LBA StartLba;
+ UINTN Offset;
UINT8 *Buffer;
-
-
+
//
- //Determine the real length of FV header
+ // Read the standard FV header
//
+ StartLba = 0;
+ Offset = 0;
FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
- Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -105,7 +214,7 @@ GetFwVolHeader (
//
FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
- Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
if (EFI_ERROR (Status)) {
//
// Read failed so free buffer
@@ -191,6 +300,7 @@ FvCheck (
EFI_FFS_FILE_HEADER *FfsHeader;
UINT8 *CacheLocation;
UINTN LbaOffset;
+ UINTN HeaderSize;
UINTN Index;
EFI_LBA LbaIndex;
UINTN Size;
@@ -231,24 +341,44 @@ FvCheck (
BlockMap = FwVolHeader->BlockMap;
CacheLocation = FvDevice->CachedFv;
LbaIndex = 0;
- LbaOffset = FwVolHeader->HeaderLength;
+ LbaOffset = 0;
+ HeaderSize = FwVolHeader->HeaderLength;
while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ Index = 0;
+ Size = BlockMap->Length;
+ if (HeaderSize > 0) {
+ //
+ // Skip header size
+ //
+ for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {
+ HeaderSize -= BlockMap->Length;
+ LbaIndex ++;
+ }
- for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {
-
- Size = BlockMap->Length;
- if (Index == 0) {
- //
- // Cache does not include FV Header
- //
- Size -= LbaOffset;
+ //
+ // Check whether FvHeader is crossing the multi block range.
+ //
+ if (HeaderSize > BlockMap->Length) {
+ BlockMap++;
+ continue;
+ } else if (HeaderSize > 0) {
+ LbaOffset = HeaderSize;
+ Size = BlockMap->Length - HeaderSize;
+ HeaderSize = 0;
}
+ }
+
+ //
+ // read the FV data
+ //
+ for (; Index < BlockMap->NumBlocks; Index ++) {
Status = Fvb->Read (Fvb,
LbaIndex,
LbaOffset,
&Size,
CacheLocation
);
+
//
// Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
//
@@ -256,14 +386,16 @@ FvCheck (
goto Done;
}
+ LbaIndex++;
+ CacheLocation += Size;
+
//
// After we skip Fv Header always read from start of block
//
LbaOffset = 0;
-
- LbaIndex++;
- CacheLocation += Size;
+ Size = BlockMap->Length;
}
+
BlockMap++;
}