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