]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/PrePiLib/FwVol.c
EmbeddedPkg: Apply uncrustify changes
[mirror_edk2.git] / EmbeddedPkg / Library / PrePiLib / FwVol.c
CommitLineData
1e57a462 1/** @file\r
2 Implementation of the 6 PEI Ffs (FV) APIs in library form.\r
3402aac7 3\r
1e57a462 4 This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list\r
5\r
6 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 7\r
878b807a 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 9\r
10**/\r
11\r
12#include <PrePi.h>\r
13#include <Library/ExtractGuidedSectionLib.h>\r
14\r
1e57a462 15#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \\r
16 (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))\r
17\r
1e57a462 18/**\r
19 Returns the highest bit set of the State field\r
3402aac7 20\r
1e57a462 21 @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY\r
22 in the Attributes field.\r
23 @param FfsHeader Pointer to FFS File Header\r
3402aac7 24\r
1e57a462 25\r
26 @retval the highest bit in the State field\r
27\r
28**/\r
29STATIC\r
30EFI_FFS_FILE_STATE\r
e7108d0e 31GetFileState (\r
1e57a462 32 IN UINT8 ErasePolarity,\r
33 IN EFI_FFS_FILE_HEADER *FfsHeader\r
34 )\r
35{\r
36 EFI_FFS_FILE_STATE FileState;\r
37 EFI_FFS_FILE_STATE HighestBit;\r
38\r
39 FileState = FfsHeader->State;\r
40\r
41 if (ErasePolarity != 0) {\r
e7108d0e 42 FileState = (EFI_FFS_FILE_STATE) ~FileState;\r
1e57a462 43 }\r
44\r
45 HighestBit = 0x80;\r
46 while (HighestBit != 0 && (HighestBit & FileState) == 0) {\r
47 HighestBit >>= 1;\r
48 }\r
49\r
50 return HighestBit;\r
3402aac7 51}\r
1e57a462 52\r
1e57a462 53/**\r
54 Calculates the checksum of the header of a file.\r
55 The header is a zero byte checksum, so zero means header is good\r
3402aac7 56\r
1e57a462 57 @param FfsHeader Pointer to FFS File Header\r
3402aac7 58\r
1e57a462 59 @retval Checksum of the header\r
60\r
61**/\r
62STATIC\r
63UINT8\r
64CalculateHeaderChecksum (\r
65 IN EFI_FFS_FILE_HEADER *FileHeader\r
66 )\r
67{\r
e7108d0e
MK
68 UINT8 *Ptr;\r
69 UINTN Index;\r
70 UINT8 Sum;\r
3402aac7 71\r
1e57a462 72 Sum = 0;\r
73 Ptr = (UINT8 *)FileHeader;\r
74\r
e7108d0e 75 for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) {\r
1e57a462 76 Sum = (UINT8)(Sum + Ptr[Index]);\r
77 Sum = (UINT8)(Sum + Ptr[Index+1]);\r
78 Sum = (UINT8)(Sum + Ptr[Index+2]);\r
79 Sum = (UINT8)(Sum + Ptr[Index+3]);\r
80 }\r
81\r
e7108d0e 82 for ( ; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) {\r
1e57a462 83 Sum = (UINT8)(Sum + Ptr[Index]);\r
84 }\r
3402aac7 85\r
1e57a462 86 //\r
3402aac7 87 // State field (since this indicates the different state of file).\r
1e57a462 88 //\r
89 Sum = (UINT8)(Sum - FileHeader->State);\r
90 //\r
91 // Checksum field of the file is not part of the header checksum.\r
92 //\r
93 Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);\r
94\r
95 return Sum;\r
96}\r
97\r
1e57a462 98/**\r
99 Given a FileHandle return the VolumeHandle\r
3402aac7 100\r
1e57a462 101 @param FileHandle File handle to look up\r
102 @param VolumeHandle Match for FileHandle\r
3402aac7 103\r
1e57a462 104 @retval TRUE VolumeHandle is valid\r
105\r
106**/\r
107STATIC\r
108BOOLEAN\r
109EFIAPI\r
110FileHandleToVolume (\r
e7108d0e
MK
111 IN EFI_PEI_FILE_HANDLE FileHandle,\r
112 OUT EFI_PEI_FV_HANDLE *VolumeHandle\r
1e57a462 113 )\r
114{\r
115 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
116 EFI_PEI_HOB_POINTERS Hob;\r
117\r
118 Hob.Raw = GetHobList ();\r
119 if (Hob.Raw == NULL) {\r
120 return FALSE;\r
121 }\r
3402aac7 122\r
1e57a462 123 do {\r
124 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r
125 if (Hob.Raw != NULL) {\r
126 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r
e7108d0e
MK
127 if (((UINT64)(UINTN)FileHandle > (UINT64)(UINTN)FwVolHeader) && \\r
128 ((UINT64)(UINTN)FileHandle <= ((UINT64)(UINTN)FwVolHeader + FwVolHeader->FvLength - 1)))\r
129 {\r
1e57a462 130 *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;\r
131 return TRUE;\r
132 }\r
133\r
134 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r
135 }\r
136 } while (Hob.Raw != NULL);\r
3402aac7 137\r
1e57a462 138 return FALSE;\r
139}\r
140\r
1e57a462 141/**\r
142 Given the input file pointer, search for the next matching file in the\r
143 FFS volume as defined by SearchType. The search starts from FileHeader inside\r
144 the Firmware Volume defined by FwVolHeader.\r
3402aac7 145\r
1e57a462 146 @param FileHandle File handle to look up\r
147 @param VolumeHandle Match for FileHandle\r
3402aac7 148\r
1e57a462 149\r
150**/\r
151EFI_STATUS\r
152FindFileEx (\r
e7108d0e
MK
153 IN CONST EFI_PEI_FV_HANDLE FvHandle,\r
154 IN CONST EFI_GUID *FileName OPTIONAL,\r
155 IN EFI_FV_FILETYPE SearchType,\r
156 IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 157 )\r
158{\r
e7108d0e
MK
159 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
160 EFI_FFS_FILE_HEADER **FileHeader;\r
161 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
162 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r
163 UINT32 FileLength;\r
164 UINT32 FileOccupiedSize;\r
165 UINT32 FileOffset;\r
166 UINT64 FvLength;\r
167 UINT8 ErasePolarity;\r
168 UINT8 FileState;\r
1e57a462 169\r
170 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;\r
171 FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;\r
172\r
173 FvLength = FwVolHeader->FvLength;\r
174 if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {\r
175 ErasePolarity = 1;\r
176 } else {\r
177 ErasePolarity = 0;\r
178 }\r
179\r
180 //\r
181 // If FileHeader is not specified (NULL) or FileName is not NULL,\r
182 // start with the first file in the firmware volume. Otherwise,\r
183 // start from the FileHeader.\r
184 //\r
185 if ((*FileHeader == NULL) || (FileName != NULL)) {\r
186 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);\r
187 if (FwVolHeader->ExtHeaderOffset != 0) {\r
188 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset);\r
e7108d0e 189 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize);\r
1e57a462 190 }\r
191 } else {\r
192 //\r
193 // Length is 24 bits wide so mask upper 8 bits\r
194 // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.\r
195 //\r
e7108d0e 196 FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;\r
1e57a462 197 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r
e7108d0e 198 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);\r
1e57a462 199 }\r
3402aac7 200\r
5a44a766
OM
201 // FFS files begin with a header that is aligned on an 8-byte boundary\r
202 FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8);\r
203\r
e7108d0e 204 FileOffset = (UINT32)((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);\r
1e57a462 205 ASSERT (FileOffset <= 0xFFFFFFFF);\r
206\r
207 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {\r
208 //\r
3402aac7 209 // Get FileState which is the highest bit of the State\r
1e57a462 210 //\r
211 FileState = GetFileState (ErasePolarity, FfsFileHeader);\r
212\r
213 switch (FileState) {\r
e7108d0e
MK
214 case EFI_FILE_HEADER_INVALID:\r
215 FileOffset += sizeof (EFI_FFS_FILE_HEADER);\r
216 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));\r
217 break;\r
218\r
219 case EFI_FILE_DATA_VALID:\r
220 case EFI_FILE_MARKED_FOR_UPDATE:\r
221 if (CalculateHeaderChecksum (FfsFileHeader) != 0) {\r
222 ASSERT (FALSE);\r
223 *FileHeader = NULL;\r
224 return EFI_NOT_FOUND;\r
225 }\r
1e57a462 226\r
e7108d0e
MK
227 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r
228 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r
1e57a462 229\r
e7108d0e
MK
230 if (FileName != NULL) {\r
231 if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID *)FileName)) {\r
232 *FileHeader = FfsFileHeader;\r
233 return EFI_SUCCESS;\r
234 }\r
235 } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&\r
236 (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD))\r
237 {\r
1e57a462 238 *FileHeader = FfsFileHeader;\r
239 return EFI_SUCCESS;\r
240 }\r
1e57a462 241\r
e7108d0e
MK
242 FileOffset += FileOccupiedSize;\r
243 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r
244 break;\r
3402aac7 245\r
e7108d0e
MK
246 case EFI_FILE_DELETED:\r
247 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r
248 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r
249 FileOffset += FileOccupiedSize;\r
250 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r
251 break;\r
1e57a462 252\r
e7108d0e
MK
253 default:\r
254 *FileHeader = NULL;\r
255 return EFI_NOT_FOUND;\r
3402aac7 256 }\r
1e57a462 257 }\r
258\r
1e57a462 259 *FileHeader = NULL;\r
3402aac7 260 return EFI_NOT_FOUND;\r
1e57a462 261}\r
262\r
1e57a462 263/**\r
264 Go through the file to search SectionType section,\r
3402aac7
RC
265 when meeting an encapsuled section.\r
266\r
1e57a462 267 @param SectionType - Filter to find only section of this type.\r
268 @param Section - From where to search.\r
269 @param SectionSize - The file size to search.\r
270 @param OutputBuffer - Pointer to the section to search.\r
3402aac7 271\r
1e57a462 272 @retval EFI_SUCCESS\r
273**/\r
274EFI_STATUS\r
275FfsProcessSection (\r
276 IN EFI_SECTION_TYPE SectionType,\r
277 IN EFI_COMMON_SECTION_HEADER *Section,\r
278 IN UINTN SectionSize,\r
279 OUT VOID **OutputBuffer\r
280 )\r
281{\r
e7108d0e
MK
282 EFI_STATUS Status;\r
283 UINT32 SectionLength;\r
284 UINT32 ParsedLength;\r
285 EFI_COMPRESSION_SECTION *CompressionSection;\r
286 EFI_COMPRESSION_SECTION2 *CompressionSection2;\r
287 UINT32 DstBufferSize;\r
288 VOID *ScratchBuffer;\r
289 UINT32 ScratchBufferSize;\r
290 VOID *DstBuffer;\r
291 UINT16 SectionAttribute;\r
292 UINT32 AuthenticationStatus;\r
293 CHAR8 *CompressedData;\r
294 UINTN CompressedDataLength;\r
1e57a462 295\r
296 *OutputBuffer = NULL;\r
297 ParsedLength = 0;\r
298 Status = EFI_NOT_FOUND;\r
299 while (ParsedLength < SectionSize) {\r
4efc8a40
MZ
300 if (IS_SECTION2 (Section)) {\r
301 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);\r
302 }\r
303\r
1e57a462 304 if (Section->Type == SectionType) {\r
4efc8a40 305 if (IS_SECTION2 (Section)) {\r
e7108d0e 306 *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));\r
4efc8a40 307 } else {\r
e7108d0e 308 *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
4efc8a40 309 }\r
1e57a462 310\r
311 return EFI_SUCCESS;\r
312 } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {\r
1e57a462 313 if (Section->Type == EFI_SECTION_COMPRESSION) {\r
4efc8a40 314 if (IS_SECTION2 (Section)) {\r
e7108d0e 315 CompressionSection2 = (EFI_COMPRESSION_SECTION2 *)Section;\r
4efc8a40
MZ
316 SectionLength = SECTION2_SIZE (Section);\r
317\r
318 if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {\r
319 return EFI_UNSUPPORTED;\r
320 }\r
321\r
e7108d0e
MK
322 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r
323 CompressedDataLength = (UINT32)SectionLength - sizeof (EFI_COMPRESSION_SECTION2);\r
4efc8a40 324 } else {\r
e7108d0e
MK
325 CompressionSection = (EFI_COMPRESSION_SECTION *)Section;\r
326 SectionLength = SECTION_SIZE (Section);\r
4efc8a40
MZ
327\r
328 if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {\r
329 return EFI_UNSUPPORTED;\r
330 }\r
331\r
e7108d0e
MK
332 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r
333 CompressedDataLength = (UINT32)SectionLength - sizeof (EFI_COMPRESSION_SECTION);\r
1e57a462 334 }\r
335\r
336 Status = UefiDecompressGetInfo (\r
4efc8a40
MZ
337 CompressedData,\r
338 CompressedDataLength,\r
c1cdcab9 339 &DstBufferSize,\r
1e57a462 340 &ScratchBufferSize\r
341 );\r
342 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
343 Status = ExtractGuidedSectionGetInfo (\r
344 Section,\r
c1cdcab9 345 &DstBufferSize,\r
1e57a462 346 &ScratchBufferSize,\r
347 &SectionAttribute\r
348 );\r
349 }\r
3402aac7 350\r
1e57a462 351 if (EFI_ERROR (Status)) {\r
352 //\r
353 // GetInfo failed\r
354 //\r
a1878955 355 DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r
1e57a462 356 return EFI_NOT_FOUND;\r
357 }\r
e7108d0e 358\r
1e57a462 359 //\r
360 // Allocate scratch buffer\r
361 //\r
362 ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
363 if (ScratchBuffer == NULL) {\r
364 return EFI_OUT_OF_RESOURCES;\r
365 }\r
e7108d0e 366\r
1e57a462 367 //\r
3402aac7 368 // Allocate destination buffer, extra one page for adjustment\r
1e57a462 369 //\r
370 DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r
371 if (DstBuffer == NULL) {\r
372 return EFI_OUT_OF_RESOURCES;\r
373 }\r
e7108d0e 374\r
1e57a462 375 //\r
376 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header\r
377 // to make section data at page alignment.\r
378 //\r
e7108d0e 379 if (IS_SECTION2 (Section)) {\r
4efc8a40 380 DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);\r
e7108d0e 381 } else {\r
4efc8a40 382 DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r
e7108d0e
MK
383 }\r
384\r
1e57a462 385 //\r
386 // Call decompress function\r
387 //\r
388 if (Section->Type == EFI_SECTION_COMPRESSION) {\r
4efc8a40 389 if (IS_SECTION2 (Section)) {\r
e7108d0e
MK
390 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r
391 } else {\r
392 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r
4efc8a40
MZ
393 }\r
394\r
1e57a462 395 Status = UefiDecompress (\r
e7108d0e
MK
396 CompressedData,\r
397 DstBuffer,\r
398 ScratchBuffer\r
399 );\r
1e57a462 400 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
401 Status = ExtractGuidedSectionDecode (\r
e7108d0e
MK
402 Section,\r
403 &DstBuffer,\r
404 ScratchBuffer,\r
405 &AuthenticationStatus\r
406 );\r
1e57a462 407 }\r
3402aac7 408\r
1e57a462 409 if (EFI_ERROR (Status)) {\r
410 //\r
411 // Decompress failed\r
412 //\r
a1878955 413 DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));\r
1e57a462 414 return EFI_NOT_FOUND;\r
415 } else {\r
416 return FfsProcessSection (\r
e7108d0e
MK
417 SectionType,\r
418 DstBuffer,\r
419 DstBufferSize,\r
420 OutputBuffer\r
421 );\r
422 }\r
1e57a462 423 }\r
424\r
4efc8a40
MZ
425 if (IS_SECTION2 (Section)) {\r
426 SectionLength = SECTION2_SIZE (Section);\r
427 } else {\r
428 SectionLength = SECTION_SIZE (Section);\r
429 }\r
e7108d0e 430\r
1e57a462 431 //\r
1e57a462 432 // SectionLength is adjusted it is 4 byte aligned.\r
433 // Go to the next section\r
434 //\r
1e57a462 435 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r
436 ASSERT (SectionLength != 0);\r
437 ParsedLength += SectionLength;\r
e7108d0e 438 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);\r
1e57a462 439 }\r
3402aac7 440\r
1e57a462 441 return EFI_NOT_FOUND;\r
442}\r
443\r
1e57a462 444/**\r
445 This service enables discovery sections of a given type within a valid FFS file.\r
446\r
447 @param SearchType The value of the section type to find.\r
448 @param FfsFileHeader A pointer to the file header that contains the set of sections to\r
449 be searched.\r
450 @param SectionData A pointer to the discovered section, if successful.\r
451\r
452 @retval EFI_SUCCESS The section was found.\r
453 @retval EFI_NOT_FOUND The section was not found.\r
454\r
455**/\r
456EFI_STATUS\r
457EFIAPI\r
458FfsFindSectionData (\r
e7108d0e
MK
459 IN EFI_SECTION_TYPE SectionType,\r
460 IN EFI_PEI_FILE_HANDLE FileHandle,\r
461 OUT VOID **SectionData\r
1e57a462 462 )\r
463{\r
e7108d0e
MK
464 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
465 UINT32 FileSize;\r
466 EFI_COMMON_SECTION_HEADER *Section;\r
1e57a462 467\r
468 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);\r
469\r
470 //\r
3402aac7 471 // Size is 24 bits wide so mask upper 8 bits.\r
1e57a462 472 // Does not include FfsFileHeader header size\r
473 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.\r
474 //\r
e7108d0e
MK
475 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);\r
476 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r
1e57a462 477 FileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
478\r
479 return FfsProcessSection (\r
e7108d0e
MK
480 SectionType,\r
481 Section,\r
482 FileSize,\r
483 SectionData\r
484 );\r
1e57a462 485}\r
486\r
1e57a462 487/**\r
488 This service enables discovery of additional firmware files.\r
489\r
490 @param SearchType A filter to find files only of this type.\r
491 @param FwVolHeader Pointer to the firmware volume header of the volume to search.\r
492 This parameter must point to a valid FFS volume.\r
493 @param FileHeader Pointer to the current file from which to begin searching.\r
494\r
495 @retval EFI_SUCCESS The file was found.\r
496 @retval EFI_NOT_FOUND The file was not found.\r
497 @retval EFI_NOT_FOUND The header checksum was not zero.\r
498\r
499**/\r
500EFI_STATUS\r
501EFIAPI\r
502FfsFindNextFile (\r
e7108d0e
MK
503 IN UINT8 SearchType,\r
504 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
505 IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 506 )\r
507{\r
508 return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);\r
509}\r
510\r
1e57a462 511/**\r
512 This service enables discovery of additional firmware volumes.\r
513\r
514 @param Instance This instance of the firmware volume to find. The value 0 is the\r
515 Boot Firmware Volume (BFV).\r
516 @param FwVolHeader Pointer to the firmware volume header of the volume to return.\r
517\r
518 @retval EFI_SUCCESS The volume was found.\r
519 @retval EFI_NOT_FOUND The volume was not found.\r
520\r
521**/\r
522EFI_STATUS\r
523EFIAPI\r
524FfsFindNextVolume (\r
e7108d0e
MK
525 IN UINTN Instance,\r
526 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle\r
1e57a462 527 )\r
528{\r
e7108d0e 529 EFI_PEI_HOB_POINTERS Hob;\r
1e57a462 530\r
531 Hob.Raw = GetHobList ();\r
532 if (Hob.Raw == NULL) {\r
533 return EFI_NOT_FOUND;\r
534 }\r
3402aac7 535\r
1e57a462 536 do {\r
537 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r
538 if (Hob.Raw != NULL) {\r
539 if (Instance-- == 0) {\r
540 *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r
541 return EFI_SUCCESS;\r
542 }\r
543\r
544 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r
545 }\r
546 } while (Hob.Raw != NULL);\r
3402aac7 547\r
1e57a462 548 return EFI_NOT_FOUND;\r
1e57a462 549}\r
550\r
1e57a462 551/**\r
552 Find a file in the volume by name\r
3402aac7 553\r
1e57a462 554 @param FileName A pointer to the name of the file to\r
555 find within the firmware volume.\r
556\r
557 @param VolumeHandle The firmware volume to search FileHandle\r
558 Upon exit, points to the found file's\r
559 handle or NULL if it could not be found.\r
560\r
561 @retval EFI_SUCCESS File was found.\r
562\r
563 @retval EFI_NOT_FOUND File was not found.\r
564\r
565 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or\r
566 FileName was NULL.\r
567\r
568**/\r
569EFI_STATUS\r
3402aac7 570EFIAPI\r
1e57a462 571FfsFindFileByName (\r
e7108d0e
MK
572 IN CONST EFI_GUID *FileName,\r
573 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
574 OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 575 )\r
576{\r
577 EFI_STATUS Status;\r
e7108d0e 578\r
1e57a462 579 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {\r
580 return EFI_INVALID_PARAMETER;\r
581 }\r
e7108d0e 582\r
1e57a462 583 Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);\r
584 if (Status == EFI_NOT_FOUND) {\r
585 *FileHandle = NULL;\r
586 }\r
e7108d0e 587\r
1e57a462 588 return Status;\r
589}\r
590\r
1e57a462 591/**\r
592 Get information about the file by name.\r
593\r
594 @param FileHandle Handle of the file.\r
595\r
596 @param FileInfo Upon exit, points to the file's\r
597 information.\r
598\r
599 @retval EFI_SUCCESS File information returned.\r
3402aac7 600\r
1e57a462 601 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
602 represent a valid file.\r
3402aac7 603\r
1e57a462 604 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
3402aac7 605\r
1e57a462 606**/\r
607EFI_STATUS\r
3402aac7 608EFIAPI\r
1e57a462 609FfsGetFileInfo (\r
610 IN EFI_PEI_FILE_HANDLE FileHandle,\r
611 OUT EFI_FV_FILE_INFO *FileInfo\r
612 )\r
613{\r
e7108d0e
MK
614 UINT8 FileState;\r
615 UINT8 ErasePolarity;\r
616 EFI_FFS_FILE_HEADER *FileHeader;\r
617 EFI_PEI_FV_HANDLE VolumeHandle;\r
1e57a462 618\r
619 if ((FileHandle == NULL) || (FileInfo == NULL)) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622\r
623 VolumeHandle = 0;\r
624 //\r
625 // Retrieve the FirmwareVolume which the file resides in.\r
626 //\r
e7108d0e 627 if (!FileHandleToVolume (FileHandle, &VolumeHandle)) {\r
1e57a462 628 return EFI_INVALID_PARAMETER;\r
629 }\r
630\r
e7108d0e 631 if (((EFI_FIRMWARE_VOLUME_HEADER *)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {\r
1e57a462 632 ErasePolarity = 1;\r
633 } else {\r
634 ErasePolarity = 0;\r
635 }\r
636\r
637 //\r
3402aac7 638 // Get FileState which is the highest bit of the State\r
1e57a462 639 //\r
e7108d0e 640 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)FileHandle);\r
1e57a462 641\r
642 switch (FileState) {\r
643 case EFI_FILE_DATA_VALID:\r
644 case EFI_FILE_MARKED_FOR_UPDATE:\r
3402aac7 645 break;\r
1e57a462 646 default:\r
647 return EFI_INVALID_PARAMETER;\r
e7108d0e 648 }\r
1e57a462 649\r
650 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r
e7108d0e
MK
651 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof (EFI_GUID));\r
652 FileInfo->FileType = FileHeader->Type;\r
1e57a462 653 FileInfo->FileAttributes = FileHeader->Attributes;\r
e7108d0e
MK
654 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r
655 FileInfo->Buffer = (FileHeader + 1);\r
1e57a462 656 return EFI_SUCCESS;\r
657}\r
658\r
1e57a462 659/**\r
660 Get Information about the volume by name\r
661\r
662 @param VolumeHandle Handle of the volume.\r
663\r
664 @param VolumeInfo Upon exit, points to the volume's\r
665 information.\r
666\r
667 @retval EFI_SUCCESS File information returned.\r
3402aac7 668\r
1e57a462 669 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
670 represent a valid file.\r
3402aac7 671\r
1e57a462 672 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
673\r
674**/\r
675EFI_STATUS\r
3402aac7 676EFIAPI\r
1e57a462 677FfsGetVolumeInfo (\r
678 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
679 OUT EFI_FV_INFO *VolumeInfo\r
680 )\r
681{\r
e7108d0e
MK
682 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;\r
683 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r
1e57a462 684\r
685 if (VolumeInfo == NULL) {\r
686 return EFI_INVALID_PARAMETER;\r
687 }\r
3402aac7 688\r
1e57a462 689 //\r
3402aac7
RC
690 // VolumeHandle may not align at 8 byte,\r
691 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.\r
1e57a462 692 // So, Copy FvHeader into the local FvHeader structure.\r
693 //\r
694 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
695 //\r
696 // Check Fv Image Signature\r
697 //\r
698 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {\r
699 return EFI_INVALID_PARAMETER;\r
700 }\r
e7108d0e 701\r
1e57a462 702 VolumeInfo->FvAttributes = FwVolHeader.Attributes;\r
e7108d0e
MK
703 VolumeInfo->FvStart = (VOID *)VolumeHandle;\r
704 VolumeInfo->FvSize = FwVolHeader.FvLength;\r
705 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof (EFI_GUID));\r
1e57a462 706\r
707 if (FwVolHeader.ExtHeaderOffset != 0) {\r
e7108d0e
MK
708 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);\r
709 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof (EFI_GUID));\r
1e57a462 710 }\r
e7108d0e 711\r
1e57a462 712 return EFI_SUCCESS;\r
713}\r
714\r
1e57a462 715/**\r
716 Search through every FV until you find a file of type FileType\r
717\r
91c38d4e 718 @param FileType File handle of a Fv type file.\r
c6a72cd7 719 @param Volumehandle On success Volume Handle of the match\r
91c38d4e 720 @param FileHandle On success File Handle of the match\r
3402aac7 721\r
91c38d4e
RC
722 @retval EFI_NOT_FOUND FV image can't be found.\r
723 @retval EFI_SUCCESS Successfully found FileType\r
1e57a462 724\r
725**/\r
726EFI_STATUS\r
727EFIAPI\r
728FfsAnyFvFindFirstFile (\r
e7108d0e
MK
729 IN EFI_FV_FILETYPE FileType,\r
730 OUT EFI_PEI_FV_HANDLE *VolumeHandle,\r
731 OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 732 )\r
733{\r
e7108d0e
MK
734 EFI_STATUS Status;\r
735 UINTN Instance;\r
1e57a462 736\r
737 //\r
738 // Search every FV for the DXE Core\r
739 //\r
740 Instance = 0;\r
741 *FileHandle = NULL;\r
742\r
e7108d0e 743 while (1) {\r
1e57a462 744 Status = FfsFindNextVolume (Instance++, VolumeHandle);\r
e7108d0e 745 if (EFI_ERROR (Status)) {\r
1e57a462 746 break;\r
747 }\r
748\r
749 Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);\r
e7108d0e 750 if (!EFI_ERROR (Status)) {\r
1e57a462 751 break;\r
752 }\r
753 }\r
3402aac7 754\r
1e57a462 755 return Status;\r
756}\r
757\r
1e57a462 758/**\r
759 Get Fv image from the FV type file, then add FV & FV2 Hob.\r
760\r
91c38d4e 761 @param FileHandle File handle of a Fv type file.\r
1e57a462 762\r
763\r
91c38d4e
RC
764 @retval EFI_NOT_FOUND FV image can't be found.\r
765 @retval EFI_SUCCESS Successfully to process it.\r
1e57a462 766\r
767**/\r
768EFI_STATUS\r
769EFIAPI\r
770FfsProcessFvFile (\r
e7108d0e 771 IN EFI_PEI_FILE_HANDLE FvFileHandle\r
1e57a462 772 )\r
773{\r
774 EFI_STATUS Status;\r
775 EFI_PEI_FV_HANDLE FvImageHandle;\r
776 EFI_FV_INFO FvImageInfo;\r
777 UINT32 FvAlignment;\r
778 VOID *FvBuffer;\r
779 EFI_PEI_HOB_POINTERS HobFv2;\r
780\r
e7108d0e 781 FvBuffer = NULL;\r
1e57a462 782\r
783 //\r
784 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r
785 // been extracted.\r
786 //\r
787 HobFv2.Raw = GetHobList ();\r
788 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r
789 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {\r
790 //\r
791 // this FILE has been dispatched, it will not be dispatched again.\r
792 //\r
793 return EFI_SUCCESS;\r
794 }\r
e7108d0e 795\r
1e57a462 796 HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r
797 }\r
798\r
799 //\r
800 // Find FvImage in FvFile\r
801 //\r
802 Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle);\r
803 if (EFI_ERROR (Status)) {\r
804 return Status;\r
805 }\r
3402aac7 806\r
1e57a462 807 //\r
808 // Collect FvImage Info.\r
809 //\r
810 ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r
811 Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);\r
812 ASSERT_EFI_ERROR (Status);\r
3402aac7 813\r
1e57a462 814 //\r
815 // FvAlignment must be more than 8 bytes required by FvHeader structure.\r
816 //\r
817 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);\r
818 if (FvAlignment < 8) {\r
819 FvAlignment = 8;\r
820 }\r
3402aac7 821\r
1e57a462 822 //\r
823 // Check FvImage\r
824 //\r
e7108d0e
MK
825 if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {\r
826 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);\r
1e57a462 827 if (FvBuffer == NULL) {\r
828 return EFI_OUT_OF_RESOURCES;\r
829 }\r
e7108d0e
MK
830\r
831 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);\r
1e57a462 832 //\r
833 // Update FvImageInfo after reload FvImage to new aligned memory\r
834 //\r
e7108d0e 835 FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);\r
1e57a462 836 }\r
837\r
1e57a462 838 //\r
c6a72cd7 839 // Inform HOB consumer phase, i.e. DXE core, the existence of this FV\r
1e57a462 840 //\r
e7108d0e 841 BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);\r
3402aac7 842\r
1e57a462 843 //\r
844 // Makes the encapsulated volume show up in DXE phase to skip processing of\r
845 // encapsulated file again.\r
846 //\r
847 BuildFv2Hob (\r
e7108d0e 848 (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,\r
1e57a462 849 FvImageInfo.FvSize,\r
850 &FvImageInfo.FvName,\r
851 &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)\r
852 );\r
853\r
854 return EFI_SUCCESS;\r
855}\r