// FFS helper functions\r
//\r
/**\r
- given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
- copy the volume header into it.\r
+ Read data from Firmware Block by FVB protocol Read. \r
+ The data may cross the multi block ranges.\r
+\r
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.\r
+ @param StartLba Pointer to StartLba.\r
+ On input, the start logical block index from which to read.\r
+ On output,the end logical block index after reading.\r
+ @param Offset Pointer to Offset\r
+ On input, offset into the block at which to begin reading.\r
+ On output, offset into the end block after reading.\r
+ @param DataSize Size of data to be read.\r
+ @param Data Pointer to Buffer that the data will be read into.\r
+\r
+ @retval EFI_SUCCESS Successfully read data from firmware block.\r
+ @retval others\r
+**/\r
+EFI_STATUS\r
+ReadFvbData (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
+ IN OUT EFI_LBA *StartLba,\r
+ IN OUT UINTN *Offset,\r
+ IN UINTN DataSize,\r
+ OUT UINT8 *Data\r
+ )\r
+{\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ UINTN BlockIndex;\r
+ UINTN ReadDataSize;\r
+ EFI_STATUS Status;\r
+ \r
+ //\r
+ // Try read data in current block\r
+ //\r
+ BlockIndex = 0;\r
+ ReadDataSize = DataSize;\r
+ Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);\r
+ if (Status == EFI_SUCCESS) {\r
+ *Offset += DataSize;\r
+ return EFI_SUCCESS;\r
+ } else if (Status != EFI_BAD_BUFFER_SIZE) {\r
+ //\r
+ // other error will direct return\r
+ //\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Data crosses the blocks, read data from next block\r
+ //\r
+ DataSize -= ReadDataSize;\r
+ Data += ReadDataSize;\r
+ *StartLba = *StartLba + 1;\r
+ while (DataSize > 0) {\r
+ Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Read data from the crossing blocks\r
+ //\r
+ BlockIndex = 0; \r
+ while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {\r
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Data += BlockSize;\r
+ DataSize -= BlockSize;\r
+ BlockIndex ++;\r
+ }\r
+ \r
+ //\r
+ // Data doesn't exceed the current block range.\r
+ //\r
+ if (DataSize < BlockSize) {\r
+ break;\r
+ }\r
+ \r
+ //\r
+ // Data must be got from the next block range.\r
+ //\r
+ *StartLba += NumberOfBlocks;\r
+ }\r
+ \r
+ //\r
+ // read the remaining data\r
+ //\r
+ if (DataSize > 0) {\r
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Update Lba and Offset used by the following read.\r
+ //\r
+ *StartLba += BlockIndex;\r
+ *Offset = DataSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
+ copy the real length volume header into it.\r
\r
@param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to\r
read the volume header\r
EFI_STATUS Status;\r
EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
UINTN FvhLength;\r
+ EFI_LBA StartLba;\r
+ UINTN Offset;\r
UINT8 *Buffer;\r
-\r
-\r
+ \r
//\r
- //Determine the real length of FV header\r
+ // Read the standard FV header\r
//\r
+ StartLba = 0;\r
+ Offset = 0;\r
FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
- Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);\r
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
//\r
FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
- Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);\r
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);\r
if (EFI_ERROR (Status)) {\r
//\r
// Read failed so free buffer\r
EFI_FFS_FILE_HEADER *FfsHeader;\r
UINT8 *CacheLocation;\r
UINTN LbaOffset;\r
+ UINTN HeaderSize;\r
UINTN Index;\r
EFI_LBA LbaIndex;\r
UINTN Size;\r
BlockMap = FwVolHeader->BlockMap;\r
CacheLocation = FvDevice->CachedFv;\r
LbaIndex = 0;\r
- LbaOffset = FwVolHeader->HeaderLength;\r
+ LbaOffset = 0;\r
+ HeaderSize = FwVolHeader->HeaderLength;\r
while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
+ Index = 0;\r
+ Size = BlockMap->Length;\r
+ if (HeaderSize > 0) {\r
+ //\r
+ // Skip header size\r
+ //\r
+ for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {\r
+ HeaderSize -= BlockMap->Length;\r
+ LbaIndex ++;\r
+ }\r
\r
- for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {\r
-\r
- Size = BlockMap->Length;\r
- if (Index == 0) {\r
- //\r
- // Cache does not include FV Header\r
- //\r
- Size -= LbaOffset;\r
+ //\r
+ // Check whether FvHeader is crossing the multi block range.\r
+ //\r
+ if (HeaderSize > BlockMap->Length) {\r
+ BlockMap++;\r
+ continue;\r
+ } else if (HeaderSize > 0) {\r
+ LbaOffset = HeaderSize;\r
+ Size = BlockMap->Length - HeaderSize;\r
+ HeaderSize = 0;\r
}\r
+ }\r
+ \r
+ //\r
+ // read the FV data \r
+ //\r
+ for (; Index < BlockMap->NumBlocks; Index ++) {\r
Status = Fvb->Read (Fvb,\r
LbaIndex,\r
LbaOffset,\r
&Size,\r
CacheLocation\r
);\r
+\r
//\r
// Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
//\r
goto Done;\r
}\r
\r
+ LbaIndex++;\r
+ CacheLocation += Size;\r
+\r
//\r
// After we skip Fv Header always read from start of block\r
//\r
LbaOffset = 0;\r
-\r
- LbaIndex++;\r
- CacheLocation += Size;\r
+ Size = BlockMap->Length;\r
}\r
+\r
BlockMap++;\r
}\r
\r