]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/PrePiLib/FwVol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 Caller also can provide a SectionCheckHook to do additional checking.
463
464 @param SectionType The value of the section type to find.
465 @param SectionCheckHook A hook which can check if the section is the target one.
466 @param FileHandle A pointer to the file header that contains the set of sections to
467 be searched.
468 @param SectionData A pointer to the discovered section, if successful.
469
470 @retval EFI_SUCCESS The section was found.
471 @retval EFI_NOT_FOUND The section was not found.
472
473 **/
474 EFI_STATUS
475 EFIAPI
476 FfsFindSectionDataWithHook (
477 IN EFI_SECTION_TYPE SectionType,
478 IN FFS_CHECK_SECTION_HOOK SectionCheckHook,
479 IN EFI_PEI_FILE_HANDLE FileHandle,
480 OUT VOID **SectionData
481 )
482 {
483 EFI_FFS_FILE_HEADER *FfsFileHeader;
484 UINT32 FileSize;
485 EFI_COMMON_SECTION_HEADER *Section;
486
487 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
488
489 //
490 // Size is 24 bits wide so mask upper 8 bits.
491 // Does not include FfsFileHeader header size
492 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
493 //
494 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
495 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
496 FileSize -= sizeof (EFI_FFS_FILE_HEADER);
497
498 return FfsProcessSection (
499 SectionType,
500 SectionCheckHook,
501 Section,
502 FileSize,
503 SectionData
504 );
505 }
506
507 /**
508 This service enables discovery sections of a given type within a valid FFS file.
509
510 @param SectionType The value of the section type to find.
511 @param FileHandle A pointer to the file header that contains the set of sections to
512 be searched.
513 @param SectionData A pointer to the discovered section, if successful.
514
515 @retval EFI_SUCCESS The section was found.
516 @retval EFI_NOT_FOUND The section was not found.
517
518 **/
519 EFI_STATUS
520 EFIAPI
521 FfsFindSectionData (
522 IN EFI_SECTION_TYPE SectionType,
523 IN EFI_PEI_FILE_HANDLE FileHandle,
524 OUT VOID **SectionData
525 )
526 {
527 return FfsFindSectionDataWithHook (SectionType, NULL, FileHandle, SectionData);
528 }
529
530 /**
531 This service enables discovery of additional firmware files.
532
533 @param SearchType A filter to find files only of this type.
534 @param FwVolHeader Pointer to the firmware volume header of the volume to search.
535 This parameter must point to a valid FFS volume.
536 @param FileHeader Pointer to the current file from which to begin searching.
537
538 @retval EFI_SUCCESS The file was found.
539 @retval EFI_NOT_FOUND The file was not found.
540 @retval EFI_NOT_FOUND The header checksum was not zero.
541
542 **/
543 EFI_STATUS
544 EFIAPI
545 FfsFindNextFile (
546 IN UINT8 SearchType,
547 IN EFI_PEI_FV_HANDLE VolumeHandle,
548 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
549 )
550 {
551 return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);
552 }
553
554 /**
555 This service enables discovery of additional firmware volumes.
556
557 @param Instance This instance of the firmware volume to find. The value 0 is the
558 Boot Firmware Volume (BFV).
559 @param FwVolHeader Pointer to the firmware volume header of the volume to return.
560
561 @retval EFI_SUCCESS The volume was found.
562 @retval EFI_NOT_FOUND The volume was not found.
563
564 **/
565 EFI_STATUS
566 EFIAPI
567 FfsFindNextVolume (
568 IN UINTN Instance,
569 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
570 )
571 {
572 EFI_PEI_HOB_POINTERS Hob;
573
574 Hob.Raw = GetHobList ();
575 if (Hob.Raw == NULL) {
576 return EFI_NOT_FOUND;
577 }
578
579 do {
580 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
581 if (Hob.Raw != NULL) {
582 if (Instance-- == 0) {
583 *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);
584 return EFI_SUCCESS;
585 }
586
587 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
588 }
589 } while (Hob.Raw != NULL);
590
591 return EFI_NOT_FOUND;
592 }
593
594 /**
595 Find a file in the volume by name
596
597 @param FileName A pointer to the name of the file to
598 find within the firmware volume.
599
600 @param VolumeHandle The firmware volume to search FileHandle
601 Upon exit, points to the found file's
602 handle or NULL if it could not be found.
603
604 @retval EFI_SUCCESS File was found.
605
606 @retval EFI_NOT_FOUND File was not found.
607
608 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or
609 FileName was NULL.
610
611 **/
612 EFI_STATUS
613 EFIAPI
614 FfsFindFileByName (
615 IN CONST EFI_GUID *FileName,
616 IN EFI_PEI_FV_HANDLE VolumeHandle,
617 OUT EFI_PEI_FILE_HANDLE *FileHandle
618 )
619 {
620 EFI_STATUS Status;
621
622 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
623 return EFI_INVALID_PARAMETER;
624 }
625
626 Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);
627 if (Status == EFI_NOT_FOUND) {
628 *FileHandle = NULL;
629 }
630
631 return Status;
632 }
633
634 /**
635 Get information about the file by name.
636
637 @param FileHandle Handle of the file.
638
639 @param FileInfo Upon exit, points to the file's
640 information.
641
642 @retval EFI_SUCCESS File information returned.
643
644 @retval EFI_INVALID_PARAMETER If FileHandle does not
645 represent a valid file.
646
647 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
648
649 **/
650 EFI_STATUS
651 EFIAPI
652 FfsGetFileInfo (
653 IN EFI_PEI_FILE_HANDLE FileHandle,
654 OUT EFI_FV_FILE_INFO *FileInfo
655 )
656 {
657 UINT8 FileState;
658 UINT8 ErasePolarity;
659 EFI_FFS_FILE_HEADER *FileHeader;
660 EFI_PEI_FV_HANDLE VolumeHandle;
661
662 if ((FileHandle == NULL) || (FileInfo == NULL)) {
663 return EFI_INVALID_PARAMETER;
664 }
665
666 VolumeHandle = 0;
667 //
668 // Retrieve the FirmwareVolume which the file resides in.
669 //
670 if (!FileHandleToVolume (FileHandle, &VolumeHandle)) {
671 return EFI_INVALID_PARAMETER;
672 }
673
674 if (((EFI_FIRMWARE_VOLUME_HEADER *)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
675 ErasePolarity = 1;
676 } else {
677 ErasePolarity = 0;
678 }
679
680 //
681 // Get FileState which is the highest bit of the State
682 //
683 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)FileHandle);
684
685 switch (FileState) {
686 case EFI_FILE_DATA_VALID:
687 case EFI_FILE_MARKED_FOR_UPDATE:
688 break;
689 default:
690 return EFI_INVALID_PARAMETER;
691 }
692
693 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
694 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof (EFI_GUID));
695 FileInfo->FileType = FileHeader->Type;
696 FileInfo->FileAttributes = FileHeader->Attributes;
697 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
698 FileInfo->Buffer = (FileHeader + 1);
699 return EFI_SUCCESS;
700 }
701
702 /**
703 Get Information about the volume by name
704
705 @param VolumeHandle Handle of the volume.
706
707 @param VolumeInfo Upon exit, points to the volume's
708 information.
709
710 @retval EFI_SUCCESS File information returned.
711
712 @retval EFI_INVALID_PARAMETER If FileHandle does not
713 represent a valid file.
714
715 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
716
717 **/
718 EFI_STATUS
719 EFIAPI
720 FfsGetVolumeInfo (
721 IN EFI_PEI_FV_HANDLE VolumeHandle,
722 OUT EFI_FV_INFO *VolumeInfo
723 )
724 {
725 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
726 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
727
728 if (VolumeInfo == NULL) {
729 return EFI_INVALID_PARAMETER;
730 }
731
732 //
733 // VolumeHandle may not align at 8 byte,
734 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
735 // So, Copy FvHeader into the local FvHeader structure.
736 //
737 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
738 //
739 // Check Fv Image Signature
740 //
741 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 VolumeInfo->FvAttributes = FwVolHeader.Attributes;
746 VolumeInfo->FvStart = (VOID *)VolumeHandle;
747 VolumeInfo->FvSize = FwVolHeader.FvLength;
748 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof (EFI_GUID));
749
750 if (FwVolHeader.ExtHeaderOffset != 0) {
751 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
752 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof (EFI_GUID));
753 }
754
755 return EFI_SUCCESS;
756 }
757
758 /**
759 Search through every FV until you find a file of type FileType
760
761 @param FileType File handle of a Fv type file.
762 @param Volumehandle On success Volume Handle of the match
763 @param FileHandle On success File Handle of the match
764
765 @retval EFI_NOT_FOUND FV image can't be found.
766 @retval EFI_SUCCESS Successfully found FileType
767
768 **/
769 EFI_STATUS
770 EFIAPI
771 FfsAnyFvFindFirstFile (
772 IN EFI_FV_FILETYPE FileType,
773 OUT EFI_PEI_FV_HANDLE *VolumeHandle,
774 OUT EFI_PEI_FILE_HANDLE *FileHandle
775 )
776 {
777 EFI_STATUS Status;
778 UINTN Instance;
779
780 //
781 // Search every FV for the DXE Core
782 //
783 Instance = 0;
784 *FileHandle = NULL;
785
786 while (1) {
787 Status = FfsFindNextVolume (Instance++, VolumeHandle);
788 if (EFI_ERROR (Status)) {
789 break;
790 }
791
792 Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);
793 if (!EFI_ERROR (Status)) {
794 break;
795 }
796 }
797
798 return Status;
799 }
800
801 /**
802 Get Fv image from the FV type file, then add FV & FV2 Hob.
803
804 @param FileHandle File handle of a Fv type file.
805
806
807 @retval EFI_NOT_FOUND FV image can't be found.
808 @retval EFI_SUCCESS Successfully to process it.
809
810 **/
811 EFI_STATUS
812 EFIAPI
813 FfsProcessFvFile (
814 IN EFI_PEI_FILE_HANDLE FvFileHandle
815 )
816 {
817 EFI_STATUS Status;
818 EFI_PEI_FV_HANDLE FvImageHandle;
819 EFI_FV_INFO FvImageInfo;
820 UINT32 FvAlignment;
821 VOID *FvBuffer;
822 EFI_PEI_HOB_POINTERS HobFv2;
823
824 FvBuffer = NULL;
825
826 //
827 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
828 // been extracted.
829 //
830 HobFv2.Raw = GetHobList ();
831 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
832 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {
833 //
834 // this FILE has been dispatched, it will not be dispatched again.
835 //
836 return EFI_SUCCESS;
837 }
838
839 HobFv2.Raw = GET_NEXT_HOB (HobFv2);
840 }
841
842 //
843 // Find FvImage in FvFile
844 //
845 Status = FfsFindSectionDataWithHook (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, NULL, FvFileHandle, (VOID **)&FvImageHandle);
846 if (EFI_ERROR (Status)) {
847 return Status;
848 }
849
850 //
851 // Collect FvImage Info.
852 //
853 ZeroMem (&FvImageInfo, sizeof (FvImageInfo));
854 Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
855 ASSERT_EFI_ERROR (Status);
856
857 //
858 // FvAlignment must be more than 8 bytes required by FvHeader structure.
859 //
860 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
861 if (FvAlignment < 8) {
862 FvAlignment = 8;
863 }
864
865 //
866 // Check FvImage
867 //
868 if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {
869 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);
870 if (FvBuffer == NULL) {
871 return EFI_OUT_OF_RESOURCES;
872 }
873
874 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);
875 //
876 // Update FvImageInfo after reload FvImage to new aligned memory
877 //
878 FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);
879 }
880
881 //
882 // Inform HOB consumer phase, i.e. DXE core, the existence of this FV
883 //
884 BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);
885
886 //
887 // Makes the encapsulated volume show up in DXE phase to skip processing of
888 // encapsulated file again.
889 //
890 BuildFv2Hob (
891 (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,
892 FvImageInfo.FvSize,
893 &FvImageInfo.FvName,
894 &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
895 );
896
897 return EFI_SUCCESS;
898 }