]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/PrePiLib/FwVol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
c673216f
MX
267 @param SectionType - Filter to find only section of this type.\r
268 @param SectionCheckHook - A hook which can check if the section is the target one.\r
269 @param Section - From where to search.\r
270 @param SectionSize - The file size to search.\r
271 @param OutputBuffer - Pointer to the section to search.\r
3402aac7 272\r
1e57a462 273 @retval EFI_SUCCESS\r
274**/\r
275EFI_STATUS\r
276FfsProcessSection (\r
277 IN EFI_SECTION_TYPE SectionType,\r
c673216f 278 IN FFS_CHECK_SECTION_HOOK SectionCheckHook,\r
1e57a462 279 IN EFI_COMMON_SECTION_HEADER *Section,\r
280 IN UINTN SectionSize,\r
281 OUT VOID **OutputBuffer\r
282 )\r
283{\r
e7108d0e
MK
284 EFI_STATUS Status;\r
285 UINT32 SectionLength;\r
286 UINT32 ParsedLength;\r
287 EFI_COMPRESSION_SECTION *CompressionSection;\r
288 EFI_COMPRESSION_SECTION2 *CompressionSection2;\r
289 UINT32 DstBufferSize;\r
290 VOID *ScratchBuffer;\r
291 UINT32 ScratchBufferSize;\r
292 VOID *DstBuffer;\r
293 UINT16 SectionAttribute;\r
294 UINT32 AuthenticationStatus;\r
295 CHAR8 *CompressedData;\r
6777e673 296 UINT32 CompressedDataLength;\r
c673216f 297 BOOLEAN Found;\r
1e57a462 298\r
c673216f 299 Found = FALSE;\r
1e57a462 300 *OutputBuffer = NULL;\r
301 ParsedLength = 0;\r
302 Status = EFI_NOT_FOUND;\r
303 while (ParsedLength < SectionSize) {\r
4efc8a40
MZ
304 if (IS_SECTION2 (Section)) {\r
305 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);\r
306 }\r
307\r
1e57a462 308 if (Section->Type == SectionType) {\r
c673216f
MX
309 if (SectionCheckHook != NULL) {\r
310 Found = SectionCheckHook (Section) == EFI_SUCCESS;\r
4efc8a40 311 } else {\r
c673216f 312 Found = TRUE;\r
4efc8a40 313 }\r
1e57a462 314\r
c673216f
MX
315 if (Found) {\r
316 if (IS_SECTION2 (Section)) {\r
317 *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));\r
318 } else {\r
319 *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
320 }\r
321\r
322 return EFI_SUCCESS;\r
323 } else {\r
324 goto CheckNextSection;\r
325 }\r
1e57a462 326 } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {\r
1e57a462 327 if (Section->Type == EFI_SECTION_COMPRESSION) {\r
4efc8a40 328 if (IS_SECTION2 (Section)) {\r
e7108d0e 329 CompressionSection2 = (EFI_COMPRESSION_SECTION2 *)Section;\r
4efc8a40
MZ
330 SectionLength = SECTION2_SIZE (Section);\r
331\r
332 if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {\r
333 return EFI_UNSUPPORTED;\r
334 }\r
335\r
e7108d0e 336 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r
6777e673 337 CompressedDataLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION2);\r
4efc8a40 338 } else {\r
e7108d0e
MK
339 CompressionSection = (EFI_COMPRESSION_SECTION *)Section;\r
340 SectionLength = SECTION_SIZE (Section);\r
4efc8a40
MZ
341\r
342 if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {\r
343 return EFI_UNSUPPORTED;\r
344 }\r
345\r
e7108d0e 346 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r
6777e673 347 CompressedDataLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION);\r
1e57a462 348 }\r
349\r
350 Status = UefiDecompressGetInfo (\r
4efc8a40
MZ
351 CompressedData,\r
352 CompressedDataLength,\r
c1cdcab9 353 &DstBufferSize,\r
1e57a462 354 &ScratchBufferSize\r
355 );\r
356 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
357 Status = ExtractGuidedSectionGetInfo (\r
358 Section,\r
c1cdcab9 359 &DstBufferSize,\r
1e57a462 360 &ScratchBufferSize,\r
361 &SectionAttribute\r
362 );\r
363 }\r
3402aac7 364\r
1e57a462 365 if (EFI_ERROR (Status)) {\r
366 //\r
367 // GetInfo failed\r
368 //\r
a1878955 369 DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r
1e57a462 370 return EFI_NOT_FOUND;\r
371 }\r
e7108d0e 372\r
1e57a462 373 //\r
374 // Allocate scratch buffer\r
375 //\r
376 ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
377 if (ScratchBuffer == NULL) {\r
378 return EFI_OUT_OF_RESOURCES;\r
379 }\r
e7108d0e 380\r
1e57a462 381 //\r
3402aac7 382 // Allocate destination buffer, extra one page for adjustment\r
1e57a462 383 //\r
384 DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r
385 if (DstBuffer == NULL) {\r
386 return EFI_OUT_OF_RESOURCES;\r
387 }\r
e7108d0e 388\r
1e57a462 389 //\r
390 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header\r
391 // to make section data at page alignment.\r
392 //\r
e7108d0e 393 if (IS_SECTION2 (Section)) {\r
4efc8a40 394 DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);\r
e7108d0e 395 } else {\r
4efc8a40 396 DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r
e7108d0e
MK
397 }\r
398\r
1e57a462 399 //\r
400 // Call decompress function\r
401 //\r
402 if (Section->Type == EFI_SECTION_COMPRESSION) {\r
4efc8a40 403 if (IS_SECTION2 (Section)) {\r
e7108d0e
MK
404 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r
405 } else {\r
406 CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r
4efc8a40
MZ
407 }\r
408\r
1e57a462 409 Status = UefiDecompress (\r
e7108d0e
MK
410 CompressedData,\r
411 DstBuffer,\r
412 ScratchBuffer\r
413 );\r
1e57a462 414 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
415 Status = ExtractGuidedSectionDecode (\r
e7108d0e
MK
416 Section,\r
417 &DstBuffer,\r
418 ScratchBuffer,\r
419 &AuthenticationStatus\r
420 );\r
1e57a462 421 }\r
3402aac7 422\r
1e57a462 423 if (EFI_ERROR (Status)) {\r
424 //\r
425 // Decompress failed\r
426 //\r
a1878955 427 DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));\r
1e57a462 428 return EFI_NOT_FOUND;\r
429 } else {\r
430 return FfsProcessSection (\r
e7108d0e 431 SectionType,\r
c673216f 432 SectionCheckHook,\r
e7108d0e
MK
433 DstBuffer,\r
434 DstBufferSize,\r
435 OutputBuffer\r
436 );\r
437 }\r
1e57a462 438 }\r
439\r
c673216f 440CheckNextSection:\r
4efc8a40
MZ
441 if (IS_SECTION2 (Section)) {\r
442 SectionLength = SECTION2_SIZE (Section);\r
443 } else {\r
444 SectionLength = SECTION_SIZE (Section);\r
445 }\r
e7108d0e 446\r
1e57a462 447 //\r
1e57a462 448 // SectionLength is adjusted it is 4 byte aligned.\r
449 // Go to the next section\r
450 //\r
1e57a462 451 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r
452 ASSERT (SectionLength != 0);\r
453 ParsedLength += SectionLength;\r
e7108d0e 454 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);\r
1e57a462 455 }\r
3402aac7 456\r
1e57a462 457 return EFI_NOT_FOUND;\r
458}\r
459\r
1e57a462 460/**\r
461 This service enables discovery sections of a given type within a valid FFS file.\r
0826808d 462 Caller also can provide a SectionCheckHook to do additional checking.\r
1e57a462 463\r
0826808d
MX
464 @param SectionType The value of the section type to find.\r
465 @param SectionCheckHook A hook which can check if the section is the target one.\r
466 @param FileHandle A pointer to the file header that contains the set of sections to\r
1e57a462 467 be searched.\r
468 @param SectionData A pointer to the discovered section, if successful.\r
469\r
470 @retval EFI_SUCCESS The section was found.\r
471 @retval EFI_NOT_FOUND The section was not found.\r
472\r
473**/\r
474EFI_STATUS\r
475EFIAPI\r
0826808d 476FfsFindSectionDataWithHook (\r
c673216f
MX
477 IN EFI_SECTION_TYPE SectionType,\r
478 IN FFS_CHECK_SECTION_HOOK SectionCheckHook,\r
479 IN EFI_PEI_FILE_HANDLE FileHandle,\r
480 OUT VOID **SectionData\r
1e57a462 481 )\r
482{\r
e7108d0e
MK
483 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
484 UINT32 FileSize;\r
485 EFI_COMMON_SECTION_HEADER *Section;\r
1e57a462 486\r
487 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);\r
488\r
489 //\r
3402aac7 490 // Size is 24 bits wide so mask upper 8 bits.\r
1e57a462 491 // Does not include FfsFileHeader header size\r
492 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.\r
493 //\r
e7108d0e
MK
494 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);\r
495 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r
1e57a462 496 FileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
497\r
498 return FfsProcessSection (\r
e7108d0e 499 SectionType,\r
c673216f 500 SectionCheckHook,\r
e7108d0e
MK
501 Section,\r
502 FileSize,\r
503 SectionData\r
504 );\r
51411435
MX
505}\r
506\r
507/**\r
508 This service enables discovery sections of a given type within a valid FFS file.\r
509\r
510 @param SectionType The value of the section type to find.\r
511 @param FileHandle A pointer to the file header that contains the set of sections to\r
512 be searched.\r
513 @param SectionData A pointer to the discovered section, if successful.\r
514\r
515 @retval EFI_SUCCESS The section was found.\r
516 @retval EFI_NOT_FOUND The section was not found.\r
517\r
518**/\r
519EFI_STATUS\r
520EFIAPI\r
521FfsFindSectionData (\r
522 IN EFI_SECTION_TYPE SectionType,\r
523 IN EFI_PEI_FILE_HANDLE FileHandle,\r
524 OUT VOID **SectionData\r
525 )\r
526{\r
527 return FfsFindSectionDataWithHook (SectionType, NULL, FileHandle, SectionData);\r
1e57a462 528}\r
529\r
1e57a462 530/**\r
531 This service enables discovery of additional firmware files.\r
532\r
533 @param SearchType A filter to find files only of this type.\r
534 @param FwVolHeader Pointer to the firmware volume header of the volume to search.\r
535 This parameter must point to a valid FFS volume.\r
536 @param FileHeader Pointer to the current file from which to begin searching.\r
537\r
538 @retval EFI_SUCCESS The file was found.\r
539 @retval EFI_NOT_FOUND The file was not found.\r
540 @retval EFI_NOT_FOUND The header checksum was not zero.\r
541\r
542**/\r
543EFI_STATUS\r
544EFIAPI\r
545FfsFindNextFile (\r
e7108d0e
MK
546 IN UINT8 SearchType,\r
547 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
548 IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 549 )\r
550{\r
551 return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);\r
552}\r
553\r
1e57a462 554/**\r
555 This service enables discovery of additional firmware volumes.\r
556\r
557 @param Instance This instance of the firmware volume to find. The value 0 is the\r
558 Boot Firmware Volume (BFV).\r
559 @param FwVolHeader Pointer to the firmware volume header of the volume to return.\r
560\r
561 @retval EFI_SUCCESS The volume was found.\r
562 @retval EFI_NOT_FOUND The volume was not found.\r
563\r
564**/\r
565EFI_STATUS\r
566EFIAPI\r
567FfsFindNextVolume (\r
e7108d0e
MK
568 IN UINTN Instance,\r
569 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle\r
1e57a462 570 )\r
571{\r
e7108d0e 572 EFI_PEI_HOB_POINTERS Hob;\r
1e57a462 573\r
574 Hob.Raw = GetHobList ();\r
575 if (Hob.Raw == NULL) {\r
576 return EFI_NOT_FOUND;\r
577 }\r
3402aac7 578\r
1e57a462 579 do {\r
580 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r
581 if (Hob.Raw != NULL) {\r
582 if (Instance-- == 0) {\r
583 *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r
584 return EFI_SUCCESS;\r
585 }\r
586\r
587 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r
588 }\r
589 } while (Hob.Raw != NULL);\r
3402aac7 590\r
1e57a462 591 return EFI_NOT_FOUND;\r
1e57a462 592}\r
593\r
1e57a462 594/**\r
595 Find a file in the volume by name\r
3402aac7 596\r
1e57a462 597 @param FileName A pointer to the name of the file to\r
598 find within the firmware volume.\r
599\r
600 @param VolumeHandle The firmware volume to search FileHandle\r
601 Upon exit, points to the found file's\r
602 handle or NULL if it could not be found.\r
603\r
604 @retval EFI_SUCCESS File was found.\r
605\r
606 @retval EFI_NOT_FOUND File was not found.\r
607\r
608 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or\r
609 FileName was NULL.\r
610\r
611**/\r
612EFI_STATUS\r
3402aac7 613EFIAPI\r
1e57a462 614FfsFindFileByName (\r
e7108d0e
MK
615 IN CONST EFI_GUID *FileName,\r
616 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
617 OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 618 )\r
619{\r
620 EFI_STATUS Status;\r
e7108d0e 621\r
1e57a462 622 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {\r
623 return EFI_INVALID_PARAMETER;\r
624 }\r
e7108d0e 625\r
1e57a462 626 Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);\r
627 if (Status == EFI_NOT_FOUND) {\r
628 *FileHandle = NULL;\r
629 }\r
e7108d0e 630\r
1e57a462 631 return Status;\r
632}\r
633\r
1e57a462 634/**\r
635 Get information about the file by name.\r
636\r
637 @param FileHandle Handle of the file.\r
638\r
639 @param FileInfo Upon exit, points to the file's\r
640 information.\r
641\r
642 @retval EFI_SUCCESS File information returned.\r
3402aac7 643\r
1e57a462 644 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
645 represent a valid file.\r
3402aac7 646\r
1e57a462 647 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
3402aac7 648\r
1e57a462 649**/\r
650EFI_STATUS\r
3402aac7 651EFIAPI\r
1e57a462 652FfsGetFileInfo (\r
653 IN EFI_PEI_FILE_HANDLE FileHandle,\r
654 OUT EFI_FV_FILE_INFO *FileInfo\r
655 )\r
656{\r
e7108d0e
MK
657 UINT8 FileState;\r
658 UINT8 ErasePolarity;\r
659 EFI_FFS_FILE_HEADER *FileHeader;\r
660 EFI_PEI_FV_HANDLE VolumeHandle;\r
1e57a462 661\r
662 if ((FileHandle == NULL) || (FileInfo == NULL)) {\r
663 return EFI_INVALID_PARAMETER;\r
664 }\r
665\r
666 VolumeHandle = 0;\r
667 //\r
668 // Retrieve the FirmwareVolume which the file resides in.\r
669 //\r
e7108d0e 670 if (!FileHandleToVolume (FileHandle, &VolumeHandle)) {\r
1e57a462 671 return EFI_INVALID_PARAMETER;\r
672 }\r
673\r
e7108d0e 674 if (((EFI_FIRMWARE_VOLUME_HEADER *)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {\r
1e57a462 675 ErasePolarity = 1;\r
676 } else {\r
677 ErasePolarity = 0;\r
678 }\r
679\r
680 //\r
3402aac7 681 // Get FileState which is the highest bit of the State\r
1e57a462 682 //\r
e7108d0e 683 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)FileHandle);\r
1e57a462 684\r
685 switch (FileState) {\r
686 case EFI_FILE_DATA_VALID:\r
687 case EFI_FILE_MARKED_FOR_UPDATE:\r
3402aac7 688 break;\r
1e57a462 689 default:\r
690 return EFI_INVALID_PARAMETER;\r
e7108d0e 691 }\r
1e57a462 692\r
693 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r
e7108d0e
MK
694 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof (EFI_GUID));\r
695 FileInfo->FileType = FileHeader->Type;\r
1e57a462 696 FileInfo->FileAttributes = FileHeader->Attributes;\r
e7108d0e
MK
697 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r
698 FileInfo->Buffer = (FileHeader + 1);\r
1e57a462 699 return EFI_SUCCESS;\r
700}\r
701\r
1e57a462 702/**\r
703 Get Information about the volume by name\r
704\r
705 @param VolumeHandle Handle of the volume.\r
706\r
707 @param VolumeInfo Upon exit, points to the volume's\r
708 information.\r
709\r
710 @retval EFI_SUCCESS File information returned.\r
3402aac7 711\r
1e57a462 712 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
713 represent a valid file.\r
3402aac7 714\r
1e57a462 715 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
716\r
717**/\r
718EFI_STATUS\r
3402aac7 719EFIAPI\r
1e57a462 720FfsGetVolumeInfo (\r
721 IN EFI_PEI_FV_HANDLE VolumeHandle,\r
722 OUT EFI_FV_INFO *VolumeInfo\r
723 )\r
724{\r
e7108d0e
MK
725 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;\r
726 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r
1e57a462 727\r
728 if (VolumeInfo == NULL) {\r
729 return EFI_INVALID_PARAMETER;\r
730 }\r
3402aac7 731\r
1e57a462 732 //\r
3402aac7
RC
733 // VolumeHandle may not align at 8 byte,\r
734 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.\r
1e57a462 735 // So, Copy FvHeader into the local FvHeader structure.\r
736 //\r
737 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
738 //\r
739 // Check Fv Image Signature\r
740 //\r
741 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {\r
742 return EFI_INVALID_PARAMETER;\r
743 }\r
e7108d0e 744\r
1e57a462 745 VolumeInfo->FvAttributes = FwVolHeader.Attributes;\r
e7108d0e
MK
746 VolumeInfo->FvStart = (VOID *)VolumeHandle;\r
747 VolumeInfo->FvSize = FwVolHeader.FvLength;\r
748 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof (EFI_GUID));\r
1e57a462 749\r
750 if (FwVolHeader.ExtHeaderOffset != 0) {\r
e7108d0e
MK
751 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);\r
752 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof (EFI_GUID));\r
1e57a462 753 }\r
e7108d0e 754\r
1e57a462 755 return EFI_SUCCESS;\r
756}\r
757\r
1e57a462 758/**\r
759 Search through every FV until you find a file of type FileType\r
760\r
91c38d4e 761 @param FileType File handle of a Fv type file.\r
c6a72cd7 762 @param Volumehandle On success Volume Handle of the match\r
91c38d4e 763 @param FileHandle On success File Handle of the match\r
3402aac7 764\r
91c38d4e
RC
765 @retval EFI_NOT_FOUND FV image can't be found.\r
766 @retval EFI_SUCCESS Successfully found FileType\r
1e57a462 767\r
768**/\r
769EFI_STATUS\r
770EFIAPI\r
771FfsAnyFvFindFirstFile (\r
e7108d0e
MK
772 IN EFI_FV_FILETYPE FileType,\r
773 OUT EFI_PEI_FV_HANDLE *VolumeHandle,\r
774 OUT EFI_PEI_FILE_HANDLE *FileHandle\r
1e57a462 775 )\r
776{\r
e7108d0e
MK
777 EFI_STATUS Status;\r
778 UINTN Instance;\r
1e57a462 779\r
780 //\r
781 // Search every FV for the DXE Core\r
782 //\r
783 Instance = 0;\r
784 *FileHandle = NULL;\r
785\r
e7108d0e 786 while (1) {\r
1e57a462 787 Status = FfsFindNextVolume (Instance++, VolumeHandle);\r
e7108d0e 788 if (EFI_ERROR (Status)) {\r
1e57a462 789 break;\r
790 }\r
791\r
792 Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);\r
e7108d0e 793 if (!EFI_ERROR (Status)) {\r
1e57a462 794 break;\r
795 }\r
796 }\r
3402aac7 797\r
1e57a462 798 return Status;\r
799}\r
800\r
1e57a462 801/**\r
802 Get Fv image from the FV type file, then add FV & FV2 Hob.\r
803\r
91c38d4e 804 @param FileHandle File handle of a Fv type file.\r
1e57a462 805\r
806\r
91c38d4e
RC
807 @retval EFI_NOT_FOUND FV image can't be found.\r
808 @retval EFI_SUCCESS Successfully to process it.\r
1e57a462 809\r
810**/\r
811EFI_STATUS\r
812EFIAPI\r
813FfsProcessFvFile (\r
e7108d0e 814 IN EFI_PEI_FILE_HANDLE FvFileHandle\r
1e57a462 815 )\r
816{\r
817 EFI_STATUS Status;\r
818 EFI_PEI_FV_HANDLE FvImageHandle;\r
819 EFI_FV_INFO FvImageInfo;\r
820 UINT32 FvAlignment;\r
821 VOID *FvBuffer;\r
822 EFI_PEI_HOB_POINTERS HobFv2;\r
823\r
e7108d0e 824 FvBuffer = NULL;\r
1e57a462 825\r
826 //\r
827 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r
828 // been extracted.\r
829 //\r
830 HobFv2.Raw = GetHobList ();\r
831 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r
832 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {\r
833 //\r
834 // this FILE has been dispatched, it will not be dispatched again.\r
835 //\r
836 return EFI_SUCCESS;\r
837 }\r
e7108d0e 838\r
1e57a462 839 HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r
840 }\r
841\r
842 //\r
843 // Find FvImage in FvFile\r
844 //\r
0826808d 845 Status = FfsFindSectionDataWithHook (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, NULL, FvFileHandle, (VOID **)&FvImageHandle);\r
1e57a462 846 if (EFI_ERROR (Status)) {\r
847 return Status;\r
848 }\r
3402aac7 849\r
1e57a462 850 //\r
851 // Collect FvImage Info.\r
852 //\r
853 ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r
854 Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);\r
855 ASSERT_EFI_ERROR (Status);\r
3402aac7 856\r
1e57a462 857 //\r
858 // FvAlignment must be more than 8 bytes required by FvHeader structure.\r
859 //\r
860 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);\r
861 if (FvAlignment < 8) {\r
862 FvAlignment = 8;\r
863 }\r
3402aac7 864\r
1e57a462 865 //\r
866 // Check FvImage\r
867 //\r
e7108d0e
MK
868 if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {\r
869 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);\r
1e57a462 870 if (FvBuffer == NULL) {\r
871 return EFI_OUT_OF_RESOURCES;\r
872 }\r
e7108d0e
MK
873\r
874 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);\r
1e57a462 875 //\r
876 // Update FvImageInfo after reload FvImage to new aligned memory\r
877 //\r
e7108d0e 878 FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);\r
1e57a462 879 }\r
880\r
1e57a462 881 //\r
c6a72cd7 882 // Inform HOB consumer phase, i.e. DXE core, the existence of this FV\r
1e57a462 883 //\r
e7108d0e 884 BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);\r
3402aac7 885\r
1e57a462 886 //\r
887 // Makes the encapsulated volume show up in DXE phase to skip processing of\r
888 // encapsulated file again.\r
889 //\r
890 BuildFv2Hob (\r
e7108d0e 891 (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,\r
1e57a462 892 FvImageInfo.FvSize,\r
893 &FvImageInfo.FvName,\r
894 &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)\r
895 );\r
896\r
897 return EFI_SUCCESS;\r
898}\r