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