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