]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/TianoTools/Common/FvLib.c
9bfd84346d0ccb6f68f7374153cd3d723fcfeace
[mirror_edk2.git] / Tools / Source / TianoTools / Common / FvLib.c
1 /*++
2
3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 FvLib.c
15
16 Abstract:
17
18 These functions assist in parsing and manipulating a Firmware Volume.
19
20 --*/
21
22 //
23 // Include files
24 //
25 #include "FvLib.h"
26 #include "CommonLib.h"
27 #include "EfiUtilityMsgs.h"
28 #include "MultiPhase.h"
29 /*
30 #include <CommonBuild.h>
31 */
32
33 /*
34 #include EFI_GUID_DEFINITION (FirmwareFileSystem)
35 */
36
37 //
38 // Module global variables
39 //
40 EFI_FIRMWARE_VOLUME_HEADER *mFvHeader = NULL;
41 UINT32 mFvLength = 0;
42
43 //
44 // External function implementations
45 //
46 EFI_STATUS
47 InitializeFvLib (
48 IN VOID *Fv,
49 IN UINT32 FvLength
50 )
51 /*++
52
53 Routine Description:
54
55 This initializes the FV lib with a pointer to the FV and length. It does not
56 verify the FV in any way.
57
58 Arguments:
59
60 Fv Buffer containing the FV.
61 FvLength Length of the FV
62
63 Returns:
64
65 EFI_SUCCESS Function Completed successfully.
66 EFI_INVALID_PARAMETER A required parameter was NULL.
67
68 --*/
69 {
70 //
71 // Verify input arguments
72 //
73 if (Fv == NULL) {
74 return EFI_INVALID_PARAMETER;
75 }
76
77 mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv;
78 mFvLength = FvLength;
79
80 return EFI_SUCCESS;
81 }
82
83 EFI_STATUS
84 GetFvHeader (
85 OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader,
86 OUT UINT32 *FvLength
87 )
88 /*++
89
90 Routine Description:
91
92 This function returns a pointer to the current FV and the size.
93
94 Arguments:
95
96 FvHeader Pointer to the FV buffer.
97 FvLength Length of the FV
98
99 Returns:
100
101 EFI_SUCCESS Function Completed successfully.
102 EFI_INVALID_PARAMETER A required parameter was NULL.
103 EFI_ABORTED The library needs to be initialized.
104
105 --*/
106 {
107 //
108 // Verify library has been initialized.
109 //
110 if (mFvHeader == NULL || mFvLength == 0) {
111 return EFI_ABORTED;
112 }
113 //
114 // Verify input arguments
115 //
116 if (FvHeader == NULL) {
117 return EFI_INVALID_PARAMETER;
118 }
119
120 *FvHeader = mFvHeader;
121 return EFI_SUCCESS;
122 }
123
124 EFI_STATUS
125 GetNextFile (
126 IN EFI_FFS_FILE_HEADER *CurrentFile,
127 OUT EFI_FFS_FILE_HEADER **NextFile
128 )
129 /*++
130
131 Routine Description:
132
133 This function returns the next file. If the current file is NULL, it returns
134 the first file in the FV. If the function returns EFI_SUCCESS and the file
135 pointer is NULL, then there are no more files in the FV.
136
137 Arguments:
138
139 CurrentFile Pointer to the current file, must be within the current FV.
140 NextFile Pointer to the next file in the FV.
141
142 Returns:
143
144 EFI_SUCCESS Function completed successfully.
145 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
146 EFI_ABORTED The library needs to be initialized.
147
148 --*/
149 {
150 EFI_STATUS Status;
151
152 //
153 // Verify library has been initialized.
154 //
155 if (mFvHeader == NULL || mFvLength == 0) {
156 return EFI_ABORTED;
157 }
158 //
159 // Verify input arguments
160 //
161 if (NextFile == NULL) {
162 return EFI_INVALID_PARAMETER;
163 }
164 //
165 // Verify FV header
166 //
167 Status = VerifyFv (mFvHeader);
168 if (EFI_ERROR (Status)) {
169 return EFI_ABORTED;
170 }
171 //
172 // Get first file
173 //
174 if (CurrentFile == NULL) {
175 CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength);
176
177 //
178 // Verify file is valid
179 //
180 Status = VerifyFfsFile (CurrentFile);
181 if (EFI_ERROR (Status)) {
182 //
183 // no files in this FV
184 //
185 *NextFile = NULL;
186 return EFI_SUCCESS;
187 } else {
188 //
189 // Verify file is in this FV.
190 //
191 if ((UINTN) CurrentFile >= (UINTN) mFvHeader + mFvLength - sizeof (EFI_FFS_FILE_HEADER)) {
192 *NextFile = NULL;
193 return EFI_SUCCESS;
194 }
195
196 *NextFile = CurrentFile;
197 return EFI_SUCCESS;
198 }
199 }
200 //
201 // Verify current file is in range
202 //
203 if (((UINTN) CurrentFile < (UINTN) mFvHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER)) ||
204 ((UINTN) CurrentFile >= (UINTN) mFvHeader + mFvLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
205 ) {
206 return EFI_INVALID_PARAMETER;
207 }
208 //
209 // Get next file, compensate for 8 byte alignment if necessary.
210 //
211 *NextFile = (EFI_FFS_FILE_HEADER *) (((UINTN) CurrentFile + GetLength (CurrentFile->Size) + 0x07) & (-1 << 3));
212
213 //
214 // Verify file is in this FV.
215 //
216 if ((UINTN) *NextFile >= (UINTN) mFvHeader + mFvLength - sizeof (EFI_FFS_FILE_HEADER)) {
217 *NextFile = NULL;
218 return EFI_SUCCESS;
219 }
220 //
221 // Verify file is valid
222 //
223 Status = VerifyFfsFile (*NextFile);
224 if (EFI_ERROR (Status)) {
225 //
226 // no more files in this FV
227 //
228 *NextFile = NULL;
229 return EFI_SUCCESS;
230 }
231
232 return EFI_SUCCESS;
233 }
234
235 EFI_STATUS
236 GetFileByName (
237 IN EFI_GUID *FileName,
238 OUT EFI_FFS_FILE_HEADER **File
239 )
240 /*++
241
242 Routine Description:
243
244 Find a file by name. The function will return NULL if the file is not found.
245
246 Arguments:
247
248 FileName The GUID file name of the file to search for.
249 File Return pointer. In the case of an error, contents are undefined.
250
251 Returns:
252
253 EFI_SUCCESS The function completed successfully.
254 EFI_ABORTED An error was encountered.
255 EFI_INVALID_PARAMETER One of the parameters was NULL.
256
257 --*/
258 {
259 EFI_FFS_FILE_HEADER *CurrentFile;
260 EFI_STATUS Status;
261
262 //
263 // Verify library has been initialized.
264 //
265 if (mFvHeader == NULL || mFvLength == 0) {
266 return EFI_ABORTED;
267 }
268 //
269 // Verify input parameters
270 //
271 if (FileName == NULL || File == NULL) {
272 return EFI_INVALID_PARAMETER;
273 }
274 //
275 // Verify FV header
276 //
277 Status = VerifyFv (mFvHeader);
278 if (EFI_ERROR (Status)) {
279 return EFI_ABORTED;
280 }
281 //
282 // Get the first file
283 //
284 Status = GetNextFile (NULL, &CurrentFile);
285 if (EFI_ERROR (Status)) {
286 Error (NULL, 0, 0, "error parsing the FV", NULL);
287 return EFI_ABORTED;
288 }
289 //
290 // Loop as long as we have a valid file
291 //
292 while (CurrentFile) {
293 if (!CompareGuid (&CurrentFile->Name, FileName)) {
294 *File = CurrentFile;
295 return EFI_SUCCESS;
296 }
297
298 Status = GetNextFile (CurrentFile, &CurrentFile);
299 if (EFI_ERROR (Status)) {
300 Error (NULL, 0, 0, "error parsing the FV", NULL);
301 return EFI_ABORTED;
302 }
303 }
304 //
305 // File not found in this FV.
306 //
307 *File = NULL;
308 return EFI_SUCCESS;
309 }
310
311 EFI_STATUS
312 GetFileByType (
313 IN EFI_FV_FILETYPE FileType,
314 IN UINTN Instance,
315 OUT EFI_FFS_FILE_HEADER **File
316 )
317 /*++
318
319 Routine Description:
320
321 Find a file by type and instance. An instance of 1 is the first instance.
322 The function will return NULL if a matching file cannot be found.
323 File type EFI_FV_FILETYPE_ALL means any file type is valid.
324
325 Arguments:
326
327 FileType Type of file to search for.
328 Instance Instace of the file type to return.
329 File Return pointer. In the case of an error, contents are undefined.
330
331 Returns:
332
333 EFI_SUCCESS The function completed successfully.
334 EFI_ABORTED An error was encountered.
335 EFI_INVALID_PARAMETER One of the parameters was NULL.
336
337 --*/
338 {
339 EFI_FFS_FILE_HEADER *CurrentFile;
340 EFI_STATUS Status;
341 UINTN FileCount;
342
343 //
344 // Verify library has been initialized.
345 //
346 if (mFvHeader == NULL || mFvLength == 0) {
347 return EFI_ABORTED;
348 }
349 //
350 // Verify input parameters
351 //
352 if (File == NULL) {
353 return EFI_INVALID_PARAMETER;
354 }
355 //
356 // Verify FV header
357 //
358 Status = VerifyFv (mFvHeader);
359 if (EFI_ERROR (Status)) {
360 return EFI_ABORTED;
361 }
362 //
363 // Initialize the number of matching files found.
364 //
365 FileCount = 0;
366
367 //
368 // Get the first file
369 //
370 Status = GetNextFile (NULL, &CurrentFile);
371 if (EFI_ERROR (Status)) {
372 Error (NULL, 0, 0, "error parsing FV", NULL);
373 return EFI_ABORTED;
374 }
375 //
376 // Loop as long as we have a valid file
377 //
378 while (CurrentFile) {
379 if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) {
380 FileCount++;
381 }
382
383 if (FileCount == Instance) {
384 *File = CurrentFile;
385 return EFI_SUCCESS;
386 }
387
388 Status = GetNextFile (CurrentFile, &CurrentFile);
389 if (EFI_ERROR (Status)) {
390 Error (NULL, 0, 0, "error parsing the FV", NULL);
391 return EFI_ABORTED;
392 }
393 }
394
395 *File = NULL;
396 return EFI_SUCCESS;
397 }
398
399 EFI_STATUS
400 GetSectionByType (
401 IN EFI_FFS_FILE_HEADER *File,
402 IN EFI_SECTION_TYPE SectionType,
403 IN UINTN Instance,
404 OUT EFI_FILE_SECTION_POINTER *Section
405 )
406 /*++
407
408 Routine Description:
409
410 Find a section in a file by type and instance. An instance of 1 is the first
411 instance. The function will return NULL if a matching section cannot be found.
412 The function will not handle encapsulating sections.
413
414 Arguments:
415
416 File The file to search.
417 SectionType Type of file to search for.
418 Instance Instace of the section to return.
419 Section Return pointer. In the case of an error, contents are undefined.
420
421 Returns:
422
423 EFI_SUCCESS The function completed successfully.
424 EFI_ABORTED An error was encountered.
425 EFI_INVALID_PARAMETER One of the parameters was NULL.
426 EFI_NOT_FOUND No found.
427 --*/
428 {
429 EFI_FILE_SECTION_POINTER CurrentSection;
430 EFI_STATUS Status;
431 UINTN SectionCount;
432
433 //
434 // Verify input parameters
435 //
436 if (File == NULL || Instance == 0) {
437 return EFI_INVALID_PARAMETER;
438 }
439 //
440 // Verify FFS header
441 //
442 Status = VerifyFfsFile (File);
443 if (EFI_ERROR (Status)) {
444 Error (NULL, 0, 0, "invalid FFS file", NULL);
445 return EFI_ABORTED;
446 }
447 //
448 // Initialize the number of matching sections found.
449 //
450 SectionCount = 0;
451
452 //
453 // Get the first section
454 //
455 CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + sizeof (EFI_FFS_FILE_HEADER));
456
457 //
458 // Loop as long as we have a valid file
459 //
460 while ((UINTN) CurrentSection.CommonHeader < (UINTN) File + GetLength (File->Size)) {
461 if (CurrentSection.CommonHeader->Type == SectionType) {
462 SectionCount++;
463 }
464
465 if (SectionCount == Instance) {
466 *Section = CurrentSection;
467 return EFI_SUCCESS;
468 }
469 //
470 // Find next section (including compensating for alignment issues.
471 //
472 CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetLength (CurrentSection.CommonHeader->Size) + 0x03) & (-1 << 2));
473 }
474 //
475 // Section not found
476 //
477 (*Section).Code16Section = NULL;
478 return EFI_NOT_FOUND;
479 }
480 //
481 // will not parse compressed sections
482 //
483 EFI_STATUS
484 VerifyFv (
485 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
486 )
487 /*++
488
489 Routine Description:
490
491 Verify the current pointer points to a valid FV header.
492
493 Arguments:
494
495 FvHeader Pointer to an alleged FV file.
496
497 Returns:
498
499 EFI_SUCCESS The FV header is valid.
500 EFI_VOLUME_CORRUPTED The FV header is not valid.
501 EFI_INVALID_PARAMETER A required parameter was NULL.
502 EFI_ABORTED Operation aborted.
503
504 --*/
505 {
506 UINT16 Checksum;
507
508 //
509 // Verify input parameters
510 //
511 if (FvHeader == NULL) {
512 return EFI_INVALID_PARAMETER;
513 }
514
515 if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
516 Error (NULL, 0, 0, "invalid FV header signature", NULL);
517 return EFI_VOLUME_CORRUPTED;
518 }
519 //
520 // Verify header checksum
521 //
522 Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
523
524 if (Checksum != 0) {
525 Error (NULL, 0, 0, "invalid FV header checksum", NULL);
526 return EFI_ABORTED;
527 }
528
529 return EFI_SUCCESS;
530 }
531
532 EFI_STATUS
533 VerifyFfsFile (
534 IN EFI_FFS_FILE_HEADER *FfsHeader
535 )
536 /*++
537
538 Routine Description:
539
540 Verify the current pointer points to a FFS file header.
541
542 Arguments:
543
544 FfsHeader Pointer to an alleged FFS file.
545
546 Returns:
547
548 EFI_SUCCESS The Ffs header is valid.
549 EFI_NOT_FOUND This "file" is the beginning of free space.
550 EFI_VOLUME_CORRUPTED The Ffs header is not valid.
551 EFI_ABORTED The erase polarity is not known.
552
553 --*/
554 {
555 BOOLEAN ErasePolarity;
556 EFI_STATUS Status;
557 EFI_FFS_FILE_HEADER BlankHeader;
558 UINT8 Checksum;
559 UINT32 FileLength;
560 UINT32 OccupiedFileLength;
561 EFI_FFS_FILE_TAIL *Tail;
562 UINT8 SavedChecksum;
563 UINT8 SavedState;
564 UINT8 FileGuidString[80];
565 UINT32 TailSize;
566 //
567 // Verify library has been initialized.
568 //
569 if (mFvHeader == NULL || mFvLength == 0) {
570 return EFI_ABORTED;
571 }
572 //
573 // Verify FV header
574 //
575 Status = VerifyFv (mFvHeader);
576 if (EFI_ERROR (Status)) {
577 return EFI_ABORTED;
578 }
579 //
580 // Get the erase polarity.
581 //
582 Status = GetErasePolarity (&ErasePolarity);
583 if (EFI_ERROR (Status)) {
584 return EFI_ABORTED;
585 }
586 //
587 // Check if we have free space
588 //
589 if (ErasePolarity) {
590 memset (&BlankHeader, -1, sizeof (EFI_FFS_FILE_HEADER));
591 } else {
592 memset (&BlankHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
593 }
594
595 if (memcmp (&BlankHeader, FfsHeader, sizeof (EFI_FFS_FILE_HEADER)) == 0) {
596 return EFI_NOT_FOUND;
597 }
598 //
599 // Convert the GUID to a string so we can at least report which file
600 // if we find an error.
601 //
602 PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE);
603 if (FfsHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
604 TailSize = sizeof (EFI_FFS_FILE_TAIL);
605 } else {
606 TailSize = 0;
607 }
608 //
609 // Verify file header checksum
610 //
611 SavedState = FfsHeader->State;
612 FfsHeader->State = 0;
613 SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File;
614 FfsHeader->IntegrityCheck.Checksum.File = 0;
615 Checksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
616 FfsHeader->State = SavedState;
617 FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum;
618 if (Checksum != 0) {
619 Error (NULL, 0, 0, FileGuidString, "invalid FFS file header checksum");
620 return EFI_ABORTED;
621 }
622 //
623 // Verify file checksum
624 //
625 if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
626 //
627 // Verify file data checksum
628 //
629 FileLength = GetLength (FfsHeader->Size);
630 OccupiedFileLength = (FileLength + 0x07) & (-1 << 3);
631 Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FileLength - TailSize);
632 Checksum = (UINT8) (Checksum - FfsHeader->State);
633 if (Checksum != 0) {
634 Error (NULL, 0, 0, FileGuidString, "invalid FFS file checksum");
635 return EFI_ABORTED;
636 }
637 } else {
638 //
639 // File does not have a checksum
640 // Verify contents are 0x5A as spec'd
641 //
642 if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
643 Error (NULL, 0, 0, FileGuidString, "invalid fixed FFS file header checksum");
644 return EFI_ABORTED;
645 }
646 }
647 //
648 // Check if the tail is present and verify it if it is.
649 //
650 if (FfsHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
651 //
652 // Verify tail is complement of integrity check field in the header.
653 //
654 Tail = (EFI_FFS_FILE_TAIL *) ((UINTN) FfsHeader + GetLength (FfsHeader->Size) - sizeof (EFI_FFS_FILE_TAIL));
655 if (FfsHeader->IntegrityCheck.TailReference != (EFI_FFS_FILE_TAIL)~(*Tail)) {
656 Error (NULL, 0, 0, FileGuidString, "invalid FFS file tail");
657 return EFI_ABORTED;
658 }
659 }
660
661 return EFI_SUCCESS;
662 }
663
664 UINT32
665 GetLength (
666 UINT8 *ThreeByteLength
667 )
668 /*++
669
670 Routine Description:
671
672 Converts a three byte length value into a UINT32.
673
674 Arguments:
675
676 ThreeByteLength Pointer to the first of the 3 byte length.
677
678 Returns:
679
680 UINT32 Size of the section
681
682 --*/
683 {
684 UINT32 Length;
685
686 if (ThreeByteLength == NULL) {
687 return 0;
688 }
689
690 Length = *((UINT32 *) ThreeByteLength);
691 Length = Length & 0x00FFFFFF;
692
693 return Length;
694 }
695
696 EFI_STATUS
697 GetErasePolarity (
698 OUT BOOLEAN *ErasePolarity
699 )
700 /*++
701
702 Routine Description:
703
704 This function returns with the FV erase polarity. If the erase polarity
705 for a bit is 1, the function return TRUE.
706
707 Arguments:
708
709 ErasePolarity A pointer to the erase polarity.
710
711 Returns:
712
713 EFI_SUCCESS The function completed successfully.
714 EFI_INVALID_PARAMETER One of the input parameters was invalid.
715 EFI_ABORTED Operation aborted.
716
717 --*/
718 {
719 EFI_STATUS Status;
720
721 //
722 // Verify library has been initialized.
723 //
724 if (mFvHeader == NULL || mFvLength == 0) {
725 return EFI_ABORTED;
726 }
727 //
728 // Verify FV header
729 //
730 Status = VerifyFv (mFvHeader);
731 if (EFI_ERROR (Status)) {
732 return EFI_ABORTED;
733 }
734 //
735 // Verify input parameters.
736 //
737 if (ErasePolarity == NULL) {
738 return EFI_INVALID_PARAMETER;
739 }
740
741 if (mFvHeader->Attributes & EFI_FVB_ERASE_POLARITY) {
742 *ErasePolarity = TRUE;
743 } else {
744 *ErasePolarity = FALSE;
745 }
746
747 return EFI_SUCCESS;
748 }
749
750 UINT8
751 GetFileState (
752 IN BOOLEAN ErasePolarity,
753 IN EFI_FFS_FILE_HEADER *FfsHeader
754 )
755 /*++
756
757 Routine Description:
758
759 This function returns a the highest state bit in the FFS that is set.
760 It in no way validate the FFS file.
761
762 Arguments:
763
764 ErasePolarity The erase polarity for the file state bits.
765 FfsHeader Pointer to a FFS file.
766
767 Returns:
768
769 UINT8 The hightest set state of the file.
770
771 --*/
772 {
773 UINT8 FileState;
774 UINT8 HighestBit;
775
776 FileState = FfsHeader->State;
777
778 if (ErasePolarity) {
779 FileState = (UINT8)~FileState;
780 }
781
782 HighestBit = 0x80;
783 while (HighestBit != 0 && (HighestBit & FileState) == 0) {
784 HighestBit >>= 1;
785 }
786
787 return HighestBit;
788 }