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