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