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