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