]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/FirmwareVolumeBuffer.c
Sync EDKII BaseTools to BaseTools project r1971
[mirror_edk2.git] / BaseTools / Source / C / Common / FirmwareVolumeBuffer.c
1 /** @file
2
3 Copyright (c) 1999 - 2008, Intel Corporation. All rights reserved.<BR>
4 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 FirmwareVolumeBuffer.c
15
16 Abstract:
17
18 EFI Firmware Volume routines which work on a Fv image in buffers.
19
20 **/
21
22 #include "FirmwareVolumeBufferLib.h"
23 #include "BinderFuncs.h"
24
25 //
26 // Local macros
27 //
28 #define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
29 ( \
30 (BOOLEAN) ( \
31 (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
32 ) \
33 )
34
35
36 //
37 // Local prototypes
38 //
39
40 STATIC
41 UINT16
42 FvBufCalculateChecksum16 (
43 IN UINT16 *Buffer,
44 IN UINTN Size
45 );
46
47 STATIC
48 UINT8
49 FvBufCalculateChecksum8 (
50 IN UINT8 *Buffer,
51 IN UINTN Size
52 );
53
54 //
55 // Procedures start
56 //
57
58 EFI_STATUS
59 FvBufRemoveFileNew (
60 IN OUT VOID *Fv,
61 IN EFI_GUID *Name
62 )
63 /*++
64
65 Routine Description:
66
67 Clears out all files from the Fv buffer in memory
68
69 Arguments:
70
71 SourceFv - Address of the Fv in memory, this firmware volume volume will
72 be modified, if SourceFfsFile exists
73 SourceFfsFile - Input FFS file to replace
74
75 Returns:
76
77 EFI_SUCCESS
78 EFI_NOT_FOUND
79
80 --*/
81 {
82 EFI_STATUS Status;
83 EFI_FFS_FILE_HEADER* FileToRm;
84 UINTN FileToRmLength;
85
86 Status = FvBufFindFileByName(
87 Fv,
88 Name,
89 (VOID **)&FileToRm
90 );
91 if (EFI_ERROR (Status)) {
92 return Status;
93 }
94
95 FileToRmLength = FvBufExpand3ByteSize (FileToRm->Size);
96
97 CommonLibBinderSetMem (
98 FileToRm,
99 FileToRmLength,
100 (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY)
101 ? 0xFF : 0
102 );
103
104 return EFI_SUCCESS;
105 }
106
107
108 EFI_STATUS
109 FvBufRemoveFile (
110 IN OUT VOID *Fv,
111 IN EFI_GUID *Name
112 )
113 /*++
114
115 Routine Description:
116
117 Clears out all files from the Fv buffer in memory
118
119 Arguments:
120
121 SourceFv - Address of the Fv in memory, this firmware volume volume will
122 be modified, if SourceFfsFile exists
123 SourceFfsFile - Input FFS file to replace
124
125 Returns:
126
127 EFI_SUCCESS
128 EFI_NOT_FOUND
129
130 --*/
131 {
132 EFI_STATUS Status;
133 EFI_FFS_FILE_HEADER *NextFile;
134 EFI_FIRMWARE_VOLUME_HEADER *TempFv;
135 UINTN FileKey;
136 UINTN FvLength;
137
138 Status = FvBufFindFileByName(
139 Fv,
140 Name,
141 NULL
142 );
143 if (EFI_ERROR (Status)) {
144 return Status;
145 }
146
147 Status = FvBufGetSize (Fv, &FvLength);
148 if (EFI_ERROR (Status)) {
149 return Status;
150 }
151
152 TempFv = NULL;
153 Status = FvBufDuplicate (Fv, (VOID **)&TempFv);
154 if (EFI_ERROR (Status)) {
155 return Status;
156 }
157
158 Status = FvBufClearAllFiles (TempFv);
159 if (EFI_ERROR (Status)) {
160 return Status;
161 }
162
163 // TempFv has been allocated. It must now be freed
164 // before returning.
165
166 FileKey = 0;
167 while (TRUE) {
168
169 Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile);
170 if (Status == EFI_NOT_FOUND) {
171 break;
172 } else if (EFI_ERROR (Status)) {
173 CommonLibBinderFree (TempFv);
174 return Status;
175 }
176
177 if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
178 continue;
179 }
180 else {
181 Status = FvBufAddFile (TempFv, NextFile);
182 if (EFI_ERROR (Status)) {
183 CommonLibBinderFree (TempFv);
184 return Status;
185 }
186 }
187 }
188
189 CommonLibBinderCopyMem (Fv, TempFv, FvLength);
190 CommonLibBinderFree (TempFv);
191
192 return EFI_SUCCESS;
193 }
194
195
196 EFI_STATUS
197 FvBufChecksumFile (
198 IN OUT VOID *FfsFile
199 )
200 /*++
201
202 Routine Description:
203
204 Clears out all files from the Fv buffer in memory
205
206 Arguments:
207
208 SourceFfsFile - Input FFS file to update the checksum for
209
210 Returns:
211
212 EFI_SUCCESS
213 EFI_NOT_FOUND
214
215 --*/
216 {
217 EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile;
218 EFI_FFS_FILE_STATE StateBackup;
219 UINT32 FileSize;
220
221 FileSize = FvBufExpand3ByteSize (File->Size);
222
223 //
224 // Fill in checksums and state, they must be 0 for checksumming.
225 //
226 File->IntegrityCheck.Checksum.Header = 0;
227 File->IntegrityCheck.Checksum.File = 0;
228 StateBackup = File->State;
229 File->State = 0;
230
231 File->IntegrityCheck.Checksum.Header =
232 FvBufCalculateChecksum8 (
233 (UINT8 *) File,
234 sizeof (EFI_FFS_FILE_HEADER)
235 );
236
237 if (File->Attributes & FFS_ATTRIB_CHECKSUM) {
238 File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 (
239 (VOID*)(File + 1),
240 FileSize - sizeof (EFI_FFS_FILE_HEADER)
241 );
242 } else {
243 File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
244 }
245
246 File->State = StateBackup;
247
248 return EFI_SUCCESS;
249 }
250
251
252 EFI_STATUS
253 FvBufChecksumHeader (
254 IN OUT VOID *Fv
255 )
256 /*++
257
258 Routine Description:
259
260 Clears out all files from the Fv buffer in memory
261
262 Arguments:
263
264 SourceFv - Address of the Fv in memory, this firmware volume volume will
265 be modified, if SourceFfsFile exists
266 SourceFfsFile - Input FFS file to replace
267
268 Returns:
269
270 EFI_SUCCESS
271 EFI_NOT_FOUND
272
273 --*/
274 {
275 EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
276
277 FvHeader->Checksum = 0;
278 FvHeader->Checksum =
279 FvBufCalculateChecksum16 (
280 (UINT16*) FvHeader,
281 FvHeader->HeaderLength / sizeof (UINT16)
282 );
283
284 return EFI_SUCCESS;
285 }
286
287
288 EFI_STATUS
289 FvBufDuplicate (
290 IN VOID *SourceFv,
291 IN OUT VOID **DestinationFv
292 )
293 /*++
294
295 Routine Description:
296
297 Clears out all files from the Fv buffer in memory
298
299 Arguments:
300
301 SourceFv - Address of the Fv in memory
302 DestinationFv - Output for destination Fv
303 DestinationFv == NULL - invalid parameter
304 *DestinationFv == NULL - memory will be allocated
305 *DestinationFv != NULL - this address will be the destination
306
307 Returns:
308
309 EFI_SUCCESS
310
311 --*/
312 {
313 EFI_STATUS Status;
314 UINTN size;
315
316 if (DestinationFv == NULL) {
317 return EFI_INVALID_PARAMETER;
318 }
319
320 Status = FvBufGetSize (SourceFv, &size);
321 if (EFI_ERROR (Status)) {
322 return Status;
323 }
324
325 if (*DestinationFv == NULL) {
326 *DestinationFv = CommonLibBinderAllocate (size);
327 }
328
329 CommonLibBinderCopyMem (*DestinationFv, SourceFv, size);
330
331 return EFI_SUCCESS;
332 }
333
334
335 EFI_STATUS
336 FvBufExtend (
337 IN VOID **Fv,
338 IN UINTN Size
339 )
340 /*++
341
342 Routine Description:
343
344 Extends a firmware volume by the given number of bytes.
345
346 BUGBUG: Does not handle the case where the firmware volume has a
347 VTF (Volume Top File). The VTF will not be moved to the
348 end of the extended FV.
349
350 Arguments:
351
352 Fv - Source and destination firmware volume.
353 Note: The original firmware volume buffer is freed!
354
355 Size - The minimum size that the firmware volume is to be extended by.
356 The FV may be extended more than this size.
357
358 Returns:
359
360 EFI_SUCCESS
361
362 --*/
363 {
364 EFI_STATUS Status;
365 UINTN OldSize;
366 UINTN NewSize;
367 UINTN BlockCount;
368 VOID* NewFv;
369
370 EFI_FIRMWARE_VOLUME_HEADER* hdr;
371 EFI_FV_BLOCK_MAP_ENTRY* blk;
372
373 Status = FvBufGetSize (*Fv, &OldSize);
374 if (EFI_ERROR (Status)) {
375 return Status;
376 }
377
378 //
379 // Locate the block map in the fv header
380 //
381 hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv;
382 blk = hdr->BlockMap;
383
384 //
385 // Calculate the number of blocks needed to achieve the requested
386 // size extension
387 //
388 BlockCount = ((Size + (blk->Length - 1)) / blk->Length);
389
390 //
391 // Calculate the new size from the number of blocks that will be added
392 //
393 NewSize = OldSize + (BlockCount * blk->Length);
394
395 NewFv = CommonLibBinderAllocate (NewSize);
396 if (NewFv == NULL) {
397 return EFI_OUT_OF_RESOURCES;
398 }
399
400 //
401 // Copy the old data
402 //
403 CommonLibBinderCopyMem (NewFv, *Fv, OldSize);
404
405 //
406 // Free the old fv buffer
407 //
408 CommonLibBinderFree (*Fv);
409
410 //
411 // Locate the block map in the new fv header
412 //
413 hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv;
414 hdr->FvLength = NewSize;
415 blk = hdr->BlockMap;
416
417 //
418 // Update the block map for the new fv
419 //
420 blk->NumBlocks += (UINT32)BlockCount;
421
422 //
423 // Update the FV header checksum
424 //
425 FvBufChecksumHeader (NewFv);
426
427 //
428 // Clear out the new area of the FV
429 //
430 CommonLibBinderSetMem (
431 (UINT8*)NewFv + OldSize,
432 (NewSize - OldSize),
433 (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
434 );
435
436 //
437 // Set output with new fv that was created
438 //
439 *Fv = NewFv;
440
441 return EFI_SUCCESS;
442
443 }
444
445
446 EFI_STATUS
447 FvBufClearAllFiles (
448 IN OUT VOID *Fv
449 )
450 /*++
451
452 Routine Description:
453
454 Clears out all files from the Fv buffer in memory
455
456 Arguments:
457
458 Fv - Address of the Fv in memory
459
460 Returns:
461
462 EFI_SUCCESS
463
464 --*/
465
466 {
467 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
468 EFI_STATUS Status;
469 UINTN size = 0;
470
471 Status = FvBufGetSize (Fv, &size);
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475
476 CommonLibBinderSetMem(
477 (UINT8*)hdr + hdr->HeaderLength,
478 size - hdr->HeaderLength,
479 (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
480 );
481
482 return EFI_SUCCESS;
483 }
484
485
486 EFI_STATUS
487 FvBufGetSize (
488 IN VOID *Fv,
489 OUT UINTN *Size
490 )
491 /*++
492
493 Routine Description:
494
495 Clears out all files from the Fv buffer in memory
496
497 Arguments:
498
499 Fv - Address of the Fv in memory
500
501 Returns:
502
503 EFI_SUCCESS
504
505 --*/
506
507 {
508 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
509 EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
510
511 *Size = 0;
512
513 while (blk->Length != 0 || blk->NumBlocks != 0) {
514 *Size = *Size + (blk->Length * blk->NumBlocks);
515 if (*Size >= 0x40000000) {
516 // If size is greater than 1GB, then assume it is corrupted
517 return EFI_VOLUME_CORRUPTED;
518 }
519 blk++;
520 }
521
522 if (*Size == 0) {
523 // If size is 0, then assume the volume is corrupted
524 return EFI_VOLUME_CORRUPTED;
525 }
526
527 return EFI_SUCCESS;
528 }
529
530
531 EFI_STATUS
532 FvBufAddFile (
533 IN OUT VOID *Fv,
534 IN VOID *File
535 )
536 /*++
537
538 Routine Description:
539
540 Adds a new FFS file
541
542 Arguments:
543
544 Fv - Address of the Fv in memory
545 File - FFS file to add to Fv
546
547 Returns:
548
549 EFI_SUCCESS
550
551 --*/
552 {
553 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
554
555 EFI_FFS_FILE_HEADER *fhdr = NULL;
556 EFI_FVB_ATTRIBUTES FvbAttributes;
557 UINTN offset;
558 UINTN fsize;
559 UINTN newSize;
560 UINTN clearLoop;
561
562 EFI_STATUS Status;
563 UINTN fvSize;
564
565 Status = FvBufGetSize (Fv, &fvSize);
566 if (EFI_ERROR (Status)) {
567 return Status;
568 }
569
570 FvbAttributes = hdr->Attributes;
571 newSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
572
573 for(
574 offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8);
575 offset + newSize <= fvSize;
576 offset = (UINTN)ALIGN_POINTER (offset, 8)
577 ) {
578
579 fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset);
580
581 if (EFI_TEST_FFS_ATTRIBUTES_BIT(
582 FvbAttributes,
583 fhdr->State,
584 EFI_FILE_HEADER_VALID
585 )
586 ) {
587 // BUGBUG: Need to make sure that the new file does not already
588 // exist.
589
590 fsize = FvBufExpand3ByteSize (fhdr->Size);
591 if (fsize == 0 || (offset + fsize > fvSize)) {
592 return EFI_VOLUME_CORRUPTED;
593 }
594
595 offset = offset + fsize;
596 continue;
597 }
598
599 clearLoop = 0;
600 while ((clearLoop < newSize) &&
601 (((UINT8*)fhdr)[clearLoop] ==
602 (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0)
603 )
604 ) {
605 clearLoop++;
606 }
607
608 //
609 // We found a place in the FV which is empty and big enough for
610 // the new file
611 //
612 if (clearLoop >= newSize) {
613 break;
614 }
615
616 offset = offset + 1; // Make some forward progress
617 }
618
619 if (offset + newSize > fvSize) {
620 return EFI_OUT_OF_RESOURCES;
621 }
622
623 CommonLibBinderCopyMem (fhdr, File, newSize);
624
625 return EFI_SUCCESS;
626 }
627
628
629 EFI_STATUS
630 FvBufAddFileWithExtend (
631 IN OUT VOID **Fv,
632 IN VOID *File
633 )
634 /*++
635
636 Routine Description:
637
638 Adds a new FFS file. Extends the firmware volume if needed.
639
640 Arguments:
641
642 Fv - Source and destination firmware volume.
643 Note: If the FV is extended, then the original firmware volume
644 buffer is freed!
645
646 Size - The minimum size that the firmware volume is to be extended by.
647 The FV may be extended more than this size.
648
649 Returns:
650
651 EFI_SUCCESS
652
653 --*/
654 {
655 EFI_STATUS Status;
656 EFI_FFS_FILE_HEADER* NewFile;
657
658 NewFile = (EFI_FFS_FILE_HEADER*)File;
659
660 //
661 // Try to add to the capsule volume
662 //
663 Status = FvBufAddFile (*Fv, NewFile);
664 if (Status == EFI_OUT_OF_RESOURCES) {
665 //
666 // Try to extend the capsule volume by the size of the file
667 //
668 Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size));
669 if (EFI_ERROR (Status)) {
670 return Status;
671 }
672
673 //
674 // Now, try to add the file again
675 //
676 Status = FvBufAddFile (*Fv, NewFile);
677 }
678
679 return Status;
680 }
681
682
683 EFI_STATUS
684 FvBufAddVtfFile (
685 IN OUT VOID *Fv,
686 IN VOID *File
687 )
688 /*++
689
690 Routine Description:
691
692 Adds a new FFS VFT (Volume Top File) file. In other words, adds the
693 file to the end of the firmware volume.
694
695 Arguments:
696
697 Fv - Address of the Fv in memory
698 File - FFS file to add to Fv
699
700 Returns:
701
702 EFI_SUCCESS
703
704 --*/
705 {
706 EFI_STATUS Status;
707
708 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
709
710 EFI_FFS_FILE_HEADER* NewFile;
711 UINTN NewFileSize;
712
713 UINT8 erasedUint8;
714 UINTN clearLoop;
715
716 EFI_FFS_FILE_HEADER *LastFile;
717 UINTN LastFileSize;
718
719 UINTN fvSize;
720 UINTN Key;
721
722 Status = FvBufGetSize (Fv, &fvSize);
723 if (EFI_ERROR (Status)) {
724 return Status;
725 }
726
727 erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0);
728 NewFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
729
730 if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 //
735 // Find the last file in the FV
736 //
737 Key = 0;
738 LastFile = NULL;
739 LastFileSize = 0;
740 do {
741 Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile);
742 LastFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
743 } while (!EFI_ERROR (Status));
744
745 //
746 // If no files were found, then we start at the beginning of the FV
747 //
748 if (LastFile == NULL) {
749 LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength);
750 }
751
752 //
753 // We want to put the new file (VTF) at the end of the FV
754 //
755 NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize));
756
757 //
758 // Check to see if there is enough room for the VTF after the last file
759 // found in the FV
760 //
761 if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) {
762 return EFI_OUT_OF_RESOURCES;
763 }
764
765 //
766 // Loop to determine if the end of the FV is empty
767 //
768 clearLoop = 0;
769 while ((clearLoop < NewFileSize) &&
770 (((UINT8*)NewFile)[clearLoop] == erasedUint8)
771 ) {
772 clearLoop++;
773 }
774
775 //
776 // Check to see if there was not enough room for the file
777 //
778 if (clearLoop < NewFileSize) {
779 return EFI_OUT_OF_RESOURCES;
780 }
781
782 CommonLibBinderCopyMem (NewFile, File, NewFileSize);
783
784 return EFI_SUCCESS;
785 }
786
787
788 VOID
789 FvBufCompact3ByteSize (
790 OUT VOID* SizeDest,
791 IN UINT32 Size
792 )
793 /*++
794
795 Routine Description:
796
797 Expands the 3 byte size commonly used in Firmware Volume data structures
798
799 Arguments:
800
801 Size - Address of the 3 byte array representing the size
802
803 Returns:
804
805 UINT32
806
807 --*/
808 {
809 ((UINT8*)SizeDest)[0] = (UINT8)Size;
810 ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8);
811 ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16);
812 }
813
814 UINT32
815 FvBufExpand3ByteSize (
816 IN VOID* Size
817 )
818 /*++
819
820 Routine Description:
821
822 Expands the 3 byte size commonly used in Firmware Volume data structures
823
824 Arguments:
825
826 Size - Address of the 3 byte array representing the size
827
828 Returns:
829
830 UINT32
831
832 --*/
833 {
834 return (((UINT8*)Size)[2] << 16) +
835 (((UINT8*)Size)[1] << 8) +
836 ((UINT8*)Size)[0];
837 }
838
839 EFI_STATUS
840 FvBufFindNextFile (
841 IN VOID *Fv,
842 IN OUT UINTN *Key,
843 OUT VOID **File
844 )
845 /*++
846
847 Routine Description:
848
849 Iterates through the files contained within the firmware volume
850
851 Arguments:
852
853 Fv - Address of the Fv in memory
854 Key - Should be 0 to get the first file. After that, it should be
855 passed back in without modifying it's contents to retrieve
856 subsequent files.
857 File - Output file pointer
858 File == NULL - invalid parameter
859 otherwise - *File will be update to the location of the file
860
861 Returns:
862
863 EFI_SUCCESS
864 EFI_NOT_FOUND
865 EFI_VOLUME_CORRUPTED
866
867 --*/
868 {
869 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
870
871 EFI_FFS_FILE_HEADER *fhdr = NULL;
872 EFI_FVB_ATTRIBUTES FvbAttributes;
873 UINTN fsize;
874
875 EFI_STATUS Status;
876 UINTN fvSize;
877
878 if (Fv == NULL) {
879 return EFI_INVALID_PARAMETER;
880 }
881
882 Status = FvBufGetSize (Fv, &fvSize);
883 if (EFI_ERROR (Status)) {
884 return Status;
885 }
886
887 if (*Key == 0) {
888 *Key = hdr->HeaderLength;
889 }
890
891 FvbAttributes = hdr->Attributes;
892
893 for(
894 *Key = (UINTN)ALIGN_POINTER (*Key, 8);
895 (*Key + sizeof (*fhdr)) < fvSize;
896 *Key = (UINTN)ALIGN_POINTER (*Key, 8)
897 ) {
898
899 fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
900 fsize = FvBufExpand3ByteSize (fhdr->Size);
901
902 if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
903 FvbAttributes,
904 fhdr->State,
905 EFI_FILE_HEADER_VALID
906 ) ||
907 EFI_TEST_FFS_ATTRIBUTES_BIT(
908 FvbAttributes,
909 fhdr->State,
910 EFI_FILE_HEADER_INVALID
911 )
912 ) {
913 *Key = *Key + 1; // Make some forward progress
914 continue;
915 } else if(
916 EFI_TEST_FFS_ATTRIBUTES_BIT(
917 FvbAttributes,
918 fhdr->State,
919 EFI_FILE_MARKED_FOR_UPDATE
920 ) ||
921 EFI_TEST_FFS_ATTRIBUTES_BIT(
922 FvbAttributes,
923 fhdr->State,
924 EFI_FILE_DELETED
925 )
926 ) {
927 *Key = *Key + fsize;
928 continue;
929 } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
930 FvbAttributes,
931 fhdr->State,
932 EFI_FILE_DATA_VALID
933 )
934 ) {
935 *File = (UINT8*)hdr + *Key;
936 *Key = *Key + fsize;
937 return EFI_SUCCESS;
938 }
939
940 *Key = *Key + 1; // Make some forward progress
941 }
942
943 return EFI_NOT_FOUND;
944 }
945
946
947 EFI_STATUS
948 FvBufFindFileByName (
949 IN VOID *Fv,
950 IN EFI_GUID *Name,
951 OUT VOID **File
952 )
953 /*++
954
955 Routine Description:
956
957 Searches the Fv for a file by its name
958
959 Arguments:
960
961 Fv - Address of the Fv in memory
962 Name - Guid filename to search for in the firmware volume
963 File - Output file pointer
964 File == NULL - Only determine if the file exists, based on return
965 value from the function call.
966 otherwise - *File will be update to the location of the file
967
968 Returns:
969
970 EFI_SUCCESS
971 EFI_NOT_FOUND
972 EFI_VOLUME_CORRUPTED
973
974 --*/
975 {
976 EFI_STATUS Status;
977 UINTN Key;
978 EFI_FFS_FILE_HEADER *NextFile;
979
980 Key = 0;
981 while (TRUE) {
982 Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
983 if (EFI_ERROR (Status)) {
984 return Status;
985 }
986
987 if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
988 if (File != NULL) {
989 *File = NextFile;
990 }
991 return EFI_SUCCESS;
992 }
993 }
994
995 return EFI_NOT_FOUND;
996 }
997
998
999 EFI_STATUS
1000 FvBufFindFileByType (
1001 IN VOID *Fv,
1002 IN EFI_FV_FILETYPE Type,
1003 OUT VOID **File
1004 )
1005 /*++
1006
1007 Routine Description:
1008
1009 Searches the Fv for a file by its type
1010
1011 Arguments:
1012
1013 Fv - Address of the Fv in memory
1014 Type - FFS FILE type to search for
1015 File - Output file pointer
1016 (File == NULL) -> Only determine if the file exists, based on return
1017 value from the function call.
1018 otherwise -> *File will be update to the location of the file
1019
1020 Returns:
1021
1022 EFI_SUCCESS
1023 EFI_NOT_FOUND
1024 EFI_VOLUME_CORRUPTED
1025
1026 --*/
1027 {
1028 EFI_STATUS Status;
1029 UINTN Key;
1030 EFI_FFS_FILE_HEADER *NextFile;
1031
1032 Key = 0;
1033 while (TRUE) {
1034 Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
1035 if (EFI_ERROR (Status)) {
1036 return Status;
1037 }
1038
1039 if (Type == NextFile->Type) {
1040 if (File != NULL) {
1041 *File = NextFile;
1042 }
1043 return EFI_SUCCESS;
1044 }
1045 }
1046
1047 return EFI_NOT_FOUND;
1048 }
1049
1050
1051 EFI_STATUS
1052 FvBufGetFileRawData (
1053 IN VOID* FfsFile,
1054 OUT VOID** RawData,
1055 OUT UINTN* RawDataSize
1056 )
1057 /*++
1058
1059 Routine Description:
1060
1061 Searches the requested file for raw data.
1062
1063 This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file,
1064 or finds the EFI_SECTION_RAW section within the file and returns its data.
1065
1066 Arguments:
1067
1068 FfsFile - Address of the FFS file in memory
1069 RawData - Pointer to the raw data within the file
1070 (This is NOT allocated. It is within the file.)
1071 RawDataSize - Size of the raw data within the file
1072
1073 Returns:
1074
1075 EFI_STATUS
1076
1077 --*/
1078 {
1079 EFI_STATUS Status;
1080 EFI_FFS_FILE_HEADER* File;
1081 EFI_RAW_SECTION* Section;
1082
1083 File = (EFI_FFS_FILE_HEADER*)FfsFile;
1084
1085 //
1086 // Is the file type == EFI_FV_FILETYPE_RAW?
1087 //
1088 if (File->Type == EFI_FV_FILETYPE_RAW) {
1089 //
1090 // Raw filetypes don't have sections, so we just return the raw data
1091 //
1092 *RawData = (VOID*)(File + 1);
1093 *RawDataSize = FvBufExpand3ByteSize (File->Size) - sizeof (*File);
1094 return EFI_SUCCESS;
1095 }
1096
1097 //
1098 // Within the file, we now need to find the EFI_SECTION_RAW section.
1099 //
1100 Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section);
1101 if (EFI_ERROR (Status)) {
1102 return Status;
1103 }
1104
1105 *RawData = (VOID*)(Section + 1);
1106 *RawDataSize =
1107 FvBufExpand3ByteSize (Section->Size) - sizeof (*Section);
1108
1109 return EFI_SUCCESS;
1110
1111 }
1112
1113
1114 EFI_STATUS
1115 FvBufPackageFreeformRawFile (
1116 IN EFI_GUID* Filename,
1117 IN VOID* RawData,
1118 IN UINTN RawDataSize,
1119 OUT VOID** FfsFile
1120 )
1121 /*++
1122
1123 Routine Description:
1124
1125 Packages up a FFS file containing the input raw data.
1126
1127 The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will
1128 contain one EFI_FV_FILETYPE_RAW section.
1129
1130 Arguments:
1131
1132 RawData - Pointer to the raw data to be packed
1133 RawDataSize - Size of the raw data to be packed
1134 FfsFile - Address of the packaged FFS file.
1135 Note: The called must deallocate this memory!
1136
1137 Returns:
1138
1139 EFI_STATUS
1140
1141 --*/
1142 {
1143 EFI_FFS_FILE_HEADER* NewFile;
1144 UINT32 NewFileSize;
1145 EFI_RAW_SECTION* NewSection;
1146 UINT32 NewSectionSize;
1147
1148 //
1149 // The section size is the DataSize + the size of the section header
1150 //
1151 NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize;
1152
1153 //
1154 // The file size is the size of the file header + the section size
1155 //
1156 NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize;
1157
1158 //
1159 // Try to allocate a buffer to build the new FFS file in
1160 //
1161 NewFile = CommonLibBinderAllocate (NewFileSize);
1162 if (NewFile == NULL) {
1163 return EFI_OUT_OF_RESOURCES;
1164 }
1165 CommonLibBinderSetMem (NewFile, NewFileSize, 0);
1166
1167 //
1168 // The NewSection follow right after the FFS file header
1169 //
1170 NewSection = (EFI_RAW_SECTION*)(NewFile + 1);
1171 FvBufCompact3ByteSize (NewSection->Size, NewSectionSize);
1172 NewSection->Type = EFI_SECTION_RAW;
1173
1174 //
1175 // Copy the actual file data into the buffer
1176 //
1177 CommonLibBinderCopyMem (NewSection + 1, RawData, RawDataSize);
1178
1179 //
1180 // Initialize the FFS file header
1181 //
1182 CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID));
1183 FvBufCompact3ByteSize (NewFile->Size, NewFileSize);
1184 NewFile->Type = EFI_FV_FILETYPE_FREEFORM;
1185 NewFile->Attributes = 0;
1186 NewFile->IntegrityCheck.Checksum.Header =
1187 FvBufCalculateChecksum8 ((UINT8*)NewFile, sizeof (*NewFile));
1188 NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1189 NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION |
1190 EFI_FILE_HEADER_VALID |
1191 EFI_FILE_DATA_VALID
1192 );
1193
1194 *FfsFile = NewFile;
1195
1196 return EFI_SUCCESS;
1197 }
1198
1199
1200 EFI_STATUS
1201 FvBufFindNextSection (
1202 IN VOID *SectionsStart,
1203 IN UINTN TotalSectionsSize,
1204 IN OUT UINTN *Key,
1205 OUT VOID **Section
1206 )
1207 /*++
1208
1209 Routine Description:
1210
1211 Iterates through the sections contained within a given array of sections
1212
1213 Arguments:
1214
1215 SectionsStart - Address of the start of the FFS sections array
1216 TotalSectionsSize - Total size of all the sections
1217 Key - Should be 0 to get the first section. After that, it should be
1218 passed back in without modifying it's contents to retrieve
1219 subsequent files.
1220 Section - Output section pointer
1221 (Section == NULL) -> invalid parameter
1222 otherwise -> *Section will be update to the location of the file
1223
1224 Returns:
1225
1226 EFI_SUCCESS
1227 EFI_NOT_FOUND
1228 EFI_VOLUME_CORRUPTED
1229
1230 --*/
1231 {
1232 EFI_COMMON_SECTION_HEADER *sectionHdr;
1233 UINTN sectionSize;
1234
1235 *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned
1236
1237 if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) {
1238 return EFI_NOT_FOUND;
1239 }
1240
1241 sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key);
1242 sectionSize = FvBufExpand3ByteSize (sectionHdr->Size);
1243
1244 if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) {
1245 return EFI_NOT_FOUND;
1246 }
1247
1248 if ((*Key + sectionSize) > TotalSectionsSize) {
1249 return EFI_NOT_FOUND;
1250 }
1251
1252 *Section = (UINT8*)sectionHdr;
1253 *Key = *Key + sectionSize;
1254 return EFI_SUCCESS;
1255
1256 }
1257
1258
1259 EFI_STATUS
1260 FvBufCountSections (
1261 IN VOID* FfsFile,
1262 IN UINTN* Count
1263 )
1264 /*++
1265
1266 Routine Description:
1267
1268 Searches the FFS file and counts the number of sections found.
1269 The sections are NOT recursed.
1270
1271 Arguments:
1272
1273 FfsFile - Address of the FFS file in memory
1274 Count - The location to store the section count in
1275
1276 Returns:
1277
1278 EFI_SUCCESS
1279 EFI_NOT_FOUND
1280 EFI_VOLUME_CORRUPTED
1281
1282 --*/
1283 {
1284 EFI_STATUS Status;
1285 UINTN Key;
1286 VOID* SectionStart;
1287 UINTN TotalSectionsSize;
1288 EFI_COMMON_SECTION_HEADER* NextSection;
1289
1290 SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));
1291 TotalSectionsSize =
1292 FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -
1293 sizeof (EFI_FFS_FILE_HEADER);
1294 Key = 0;
1295 *Count = 0;
1296 while (TRUE) {
1297 Status = FvBufFindNextSection (
1298 SectionStart,
1299 TotalSectionsSize,
1300 &Key,
1301 (VOID **)&NextSection
1302 );
1303 if (Status == EFI_NOT_FOUND) {
1304 return EFI_SUCCESS;
1305 } else if (EFI_ERROR (Status)) {
1306 return Status;
1307 }
1308
1309 //
1310 // Increment the section counter
1311 //
1312 *Count += 1;
1313
1314 }
1315
1316 return EFI_NOT_FOUND;
1317 }
1318
1319
1320 EFI_STATUS
1321 FvBufFindSectionByType (
1322 IN VOID *FfsFile,
1323 IN UINT8 Type,
1324 OUT VOID **Section
1325 )
1326 /*++
1327
1328 Routine Description:
1329
1330 Searches the FFS file for a section by its type
1331
1332 Arguments:
1333
1334 FfsFile - Address of the FFS file in memory
1335 Type - FFS FILE section type to search for
1336 Section - Output section pointer
1337 (Section == NULL) -> Only determine if the section exists, based on return
1338 value from the function call.
1339 otherwise -> *Section will be update to the location of the file
1340
1341 Returns:
1342
1343 EFI_SUCCESS
1344 EFI_NOT_FOUND
1345 EFI_VOLUME_CORRUPTED
1346
1347 --*/
1348 {
1349 EFI_STATUS Status;
1350 UINTN Key;
1351 VOID* SectionStart;
1352 UINTN TotalSectionsSize;
1353 EFI_COMMON_SECTION_HEADER* NextSection;
1354
1355 SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));
1356 TotalSectionsSize =
1357 FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -
1358 sizeof (EFI_FFS_FILE_HEADER);
1359 Key = 0;
1360 while (TRUE) {
1361 Status = FvBufFindNextSection (
1362 SectionStart,
1363 TotalSectionsSize,
1364 &Key,
1365 (VOID **)&NextSection
1366 );
1367 if (EFI_ERROR (Status)) {
1368 return Status;
1369 }
1370
1371 if (Type == NextSection->Type) {
1372 if (Section != NULL) {
1373 *Section = NextSection;
1374 }
1375 return EFI_SUCCESS;
1376 }
1377 }
1378
1379 return EFI_NOT_FOUND;
1380 }
1381
1382
1383 EFI_STATUS
1384 FvBufShrinkWrap (
1385 IN VOID *Fv
1386 )
1387 /*++
1388
1389 Routine Description:
1390
1391 Shrinks a firmware volume (in place) to provide a minimal FV.
1392
1393 BUGBUG: Does not handle the case where the firmware volume has a
1394 VTF (Volume Top File). The VTF will not be moved to the
1395 end of the extended FV.
1396
1397 Arguments:
1398
1399 Fv - Firmware volume.
1400
1401 Returns:
1402
1403 EFI_SUCCESS
1404
1405 --*/
1406 {
1407 EFI_STATUS Status;
1408 UINTN OldSize;
1409 UINT32 BlockCount;
1410 UINT32 NewBlockSize = 128;
1411 UINTN Key;
1412 EFI_FFS_FILE_HEADER* FileIt;
1413 VOID* EndOfLastFile;
1414
1415 EFI_FIRMWARE_VOLUME_HEADER* FvHdr;
1416
1417 Status = FvBufGetSize (Fv, &OldSize);
1418 if (EFI_ERROR (Status)) {
1419 return Status;
1420 }
1421
1422 Status = FvBufUnifyBlockSizes (Fv, NewBlockSize);
1423 if (EFI_ERROR (Status)) {
1424 return Status;
1425 }
1426
1427 //
1428 // Locate the block map in the fv header
1429 //
1430 FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
1431
1432 //
1433 // Find the end of the last file
1434 //
1435 Key = 0;
1436 EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength;
1437 while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) {
1438 EndOfLastFile =
1439 (VOID*)((UINT8*)FileIt + FvBufExpand3ByteSize (FileIt->Size));
1440 }
1441
1442 //
1443 // Set the BlockCount to have the minimal number of blocks for the Fv.
1444 //
1445 BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv);
1446 BlockCount = BlockCount + NewBlockSize - 1;
1447 BlockCount = BlockCount / NewBlockSize;
1448
1449 //
1450 // Adjust the block count to shrink the Fv in place.
1451 //
1452 FvHdr->BlockMap[0].NumBlocks = BlockCount;
1453 FvHdr->FvLength = BlockCount * NewBlockSize;
1454
1455 //
1456 // Update the FV header checksum
1457 //
1458 FvBufChecksumHeader (Fv);
1459
1460 return EFI_SUCCESS;
1461
1462 }
1463
1464
1465 EFI_STATUS
1466 FvBufUnifyBlockSizes (
1467 IN OUT VOID *Fv,
1468 IN UINTN BlockSize
1469 )
1470 /*++
1471
1472 Routine Description:
1473
1474 Searches the FFS file for a section by its type
1475
1476 Arguments:
1477
1478 Fv - Address of the Fv in memory
1479 BlockSize - The size of the blocks to convert the Fv to. If the total size
1480 of the Fv is not evenly divisible by this size, then
1481 EFI_INVALID_PARAMETER will be returned.
1482
1483 Returns:
1484
1485 EFI_SUCCESS
1486 EFI_NOT_FOUND
1487 EFI_VOLUME_CORRUPTED
1488
1489 --*/
1490 {
1491 EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
1492 EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
1493 UINT32 Size;
1494
1495 Size = 0;
1496
1497 //
1498 // Scan through the block map list, performing error checking, and adding
1499 // up the total Fv size.
1500 //
1501 while( blk->Length != 0 ||
1502 blk->NumBlocks != 0
1503 ) {
1504 Size = Size + (blk->Length * blk->NumBlocks);
1505 blk++;
1506 if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) {
1507 return EFI_VOLUME_CORRUPTED;
1508 }
1509 }
1510
1511 //
1512 // Make sure that the Fv size is a multiple of the new block size.
1513 //
1514 if ((Size % BlockSize) != 0) {
1515 return EFI_INVALID_PARAMETER;
1516 }
1517
1518 //
1519 // Zero out the entire block map.
1520 //
1521 CommonLibBinderSetMem (
1522 &hdr->BlockMap,
1523 (UINTN)blk - (UINTN)&hdr->BlockMap,
1524 0
1525 );
1526
1527 //
1528 // Write out the single block map entry.
1529 //
1530 hdr->BlockMap[0].Length = (UINT32)BlockSize;
1531 hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize;
1532
1533 return EFI_SUCCESS;
1534 }
1535
1536 STATIC
1537 UINT16
1538 FvBufCalculateSum16 (
1539 IN UINT16 *Buffer,
1540 IN UINTN Size
1541 )
1542 /*++
1543
1544 Routine Description:
1545
1546 This function calculates the UINT16 sum for the requested region.
1547
1548 Arguments:
1549
1550 Buffer Pointer to buffer containing byte data of component.
1551 Size Size of the buffer
1552
1553 Returns:
1554
1555 The 16 bit checksum
1556
1557 --*/
1558 {
1559 UINTN Index;
1560 UINT16 Sum;
1561
1562 Sum = 0;
1563
1564 //
1565 // Perform the word sum for buffer
1566 //
1567 for (Index = 0; Index < Size; Index++) {
1568 Sum = (UINT16) (Sum + Buffer[Index]);
1569 }
1570
1571 return (UINT16) Sum;
1572 }
1573
1574
1575 STATIC
1576 UINT16
1577 FvBufCalculateChecksum16 (
1578 IN UINT16 *Buffer,
1579 IN UINTN Size
1580 )
1581 /*++
1582
1583 Routine Description::
1584
1585 This function calculates the value needed for a valid UINT16 checksum
1586
1587 Arguments:
1588
1589 Buffer Pointer to buffer containing byte data of component.
1590 Size Size of the buffer
1591
1592 Returns:
1593
1594 The 16 bit checksum value needed.
1595
1596 --*/
1597 {
1598 return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size));
1599 }
1600
1601
1602 STATIC
1603 UINT8
1604 FvBufCalculateSum8 (
1605 IN UINT8 *Buffer,
1606 IN UINTN Size
1607 )
1608 /*++
1609
1610 Description:
1611
1612 This function calculates the UINT8 sum for the requested region.
1613
1614 Input:
1615
1616 Buffer Pointer to buffer containing byte data of component.
1617 Size Size of the buffer
1618
1619 Return:
1620
1621 The 8 bit checksum value needed.
1622
1623 --*/
1624 {
1625 UINTN Index;
1626 UINT8 Sum;
1627
1628 Sum = 0;
1629
1630 //
1631 // Perform the byte sum for buffer
1632 //
1633 for (Index = 0; Index < Size; Index++) {
1634 Sum = (UINT8) (Sum + Buffer[Index]);
1635 }
1636
1637 return Sum;
1638 }
1639
1640
1641 STATIC
1642 UINT8
1643 FvBufCalculateChecksum8 (
1644 IN UINT8 *Buffer,
1645 IN UINTN Size
1646 )
1647 /*++
1648
1649 Description:
1650
1651 This function calculates the value needed for a valid UINT8 checksum
1652
1653 Input:
1654
1655 Buffer Pointer to buffer containing byte data of component.
1656 Size Size of the buffer
1657
1658 Return:
1659
1660 The 8 bit checksum value needed.
1661
1662 --*/
1663 {
1664 return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size));
1665 }
1666
1667