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