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