]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
804f9661acb3537ab9035ba81d78b4026afbe081
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwVolWrite.c
1 /** @file
2 Implements write firmware file.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "FwVolDriver.h"
11
12 /**
13 Calculate the checksum for the FFS header.
14
15 @param FfsHeader FFS File Header which needs to calculate the checksum
16
17 **/
18 VOID
19 SetHeaderChecksum (
20 IN EFI_FFS_FILE_HEADER *FfsHeader
21 )
22 {
23 EFI_FFS_FILE_STATE State;
24 UINT8 FileChecksum;
25
26 //
27 // The state and the File checksum are not included
28 //
29 State = FfsHeader->State;
30 FfsHeader->State = 0;
31
32 FileChecksum = FfsHeader->IntegrityCheck.Checksum.File;
33 FfsHeader->IntegrityCheck.Checksum.File = 0;
34
35 FfsHeader->IntegrityCheck.Checksum.Header = 0;
36
37 if (IS_FFS_FILE2 (FfsHeader)) {
38 FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
39 (UINT8 *) FfsHeader,
40 sizeof (EFI_FFS_FILE_HEADER2)
41 );
42 } else {
43 FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
44 (UINT8 *) FfsHeader,
45 sizeof (EFI_FFS_FILE_HEADER)
46 );
47 }
48
49 FfsHeader->State = State;
50 FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;
51
52 return ;
53 }
54
55 /**
56 Calculate the checksum for the FFS File.
57
58 @param FfsHeader FFS File Header which needs to calculate the checksum
59 @param ActualFileSize The whole Ffs File Length.
60
61 **/
62 VOID
63 SetFileChecksum (
64 IN EFI_FFS_FILE_HEADER *FfsHeader,
65 IN UINTN ActualFileSize
66 )
67 {
68 if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
69
70 FfsHeader->IntegrityCheck.Checksum.File = 0;
71
72 if (IS_FFS_FILE2 (FfsHeader)) {
73 FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
74 (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2),
75 ActualFileSize - sizeof (EFI_FFS_FILE_HEADER2)
76 );
77 } else {
78 FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
79 (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER),
80 ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)
81 );
82 }
83
84 } else {
85
86 FfsHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
87
88 }
89
90 return ;
91 }
92
93 /**
94 Get the alignment value from File Attributes.
95
96 @param FfsAttributes FFS attribute
97
98 @return Alignment value.
99
100 **/
101 UINTN
102 GetRequiredAlignment (
103 IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
104 )
105 {
106 UINTN AlignmentValue;
107
108 AlignmentValue = FfsAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
109
110 if (AlignmentValue <= 3) {
111 return 0x08;
112 }
113
114 if (AlignmentValue > 16) {
115 //
116 // Anyway, we won't reach this code
117 //
118 return 0x08;
119 }
120
121 return (UINTN)1 << AlignmentValue;
122
123 }
124
125 /**
126 Calculate the leading Pad file size to meet the alignment requirement.
127
128 @param FvDevice Cached Firmware Volume.
129 @param StartAddress The starting address to write the FFS File.
130 @param BufferSize The FFS File Buffer Size.
131 @param RequiredAlignment FFS File Data alignment requirement.
132
133 @return The required Pad File Size.
134
135 **/
136 UINTN
137 CalculatePadFileSize (
138 IN FV_DEVICE *FvDevice,
139 IN EFI_PHYSICAL_ADDRESS StartAddress,
140 IN UINTN BufferSize,
141 IN UINTN RequiredAlignment
142 )
143 {
144 UINTN DataStartPos;
145 UINTN RelativePos;
146 UINTN PadSize;
147
148 if (BufferSize > 0x00FFFFFF) {
149 DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER2);
150 } else {
151 DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);
152 }
153 RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv;
154
155 PadSize = 0;
156
157 while ((RelativePos & (RequiredAlignment - 1)) != 0) {
158 RelativePos++;
159 PadSize++;
160 }
161 //
162 // If padsize is 0, no pad file needed;
163 // If padsize is great than 24, then pad file can be created
164 //
165 if ((PadSize == 0) || (PadSize >= sizeof (EFI_FFS_FILE_HEADER))) {
166 return PadSize;
167 }
168
169 //
170 // Perhaps following method can save space
171 //
172 RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv + sizeof (EFI_FFS_FILE_HEADER);
173 PadSize = sizeof (EFI_FFS_FILE_HEADER);
174
175 while ((RelativePos & (RequiredAlignment - 1)) != 0) {
176 RelativePos++;
177 PadSize++;
178 }
179
180 return PadSize;
181 }
182
183 /**
184 Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
185
186 @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
187 @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
188
189 **/
190 VOID
191 FvFileAttrib2FfsFileAttrib (
192 IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
193 OUT UINT8 *FfsFileAttrib
194 )
195 {
196 UINT8 FvFileAlignment;
197 UINT8 FfsFileAlignment;
198 UINT8 FfsFileAlignment2;
199
200 FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);
201 FfsFileAlignment = 0;
202 FfsFileAlignment2 = 0;
203
204 switch (FvFileAlignment) {
205 case 0:
206 //
207 // fall through
208 //
209 case 1:
210 //
211 // fall through
212 //
213 case 2:
214 //
215 // fall through
216 //
217 case 3:
218 //
219 // fall through
220 //
221 FfsFileAlignment = 0;
222 break;
223
224 case 4:
225 //
226 // fall through
227 //
228 case 5:
229 //
230 // fall through
231 //
232 case 6:
233 //
234 // fall through
235 //
236 FfsFileAlignment = 1;
237 break;
238
239 case 7:
240 //
241 // fall through
242 //
243 case 8:
244 //
245 // fall through
246 //
247 FfsFileAlignment = 2;
248 break;
249
250 case 9:
251 FfsFileAlignment = 3;
252 break;
253
254 case 10:
255 //
256 // fall through
257 //
258 case 11:
259 //
260 // fall through
261 //
262 FfsFileAlignment = 4;
263 break;
264
265 case 12:
266 //
267 // fall through
268 //
269 case 13:
270 //
271 // fall through
272 //
273 case 14:
274 //
275 // fall through
276 //
277 FfsFileAlignment = 5;
278 break;
279
280 case 15:
281 FfsFileAlignment = 6;
282 break;
283
284 case 16:
285 FfsFileAlignment = 7;
286 break;
287
288 case 17:
289 FfsFileAlignment = 0;
290 FfsFileAlignment2 = 1;
291 break;
292 case 18:
293 FfsFileAlignment = 1;
294 FfsFileAlignment2 = 1;
295 break;
296 case 19:
297 FfsFileAlignment = 2;
298 FfsFileAlignment2 = 1;
299 break;
300 case 20:
301 FfsFileAlignment = 3;
302 FfsFileAlignment2 = 1;
303 break;
304 case 21:
305 FfsFileAlignment = 4;
306 FfsFileAlignment2 = 1;
307 break;
308 case 22:
309 FfsFileAlignment = 5;
310 FfsFileAlignment2 = 1;
311 break;
312 case 23:
313 FfsFileAlignment = 6;
314 FfsFileAlignment2 = 1;
315 break;
316 case 24:
317 FfsFileAlignment = 7;
318 FfsFileAlignment2 = 1;
319 break;
320 }
321
322 *FfsFileAttrib = (UINT8) ((FfsFileAlignment << 3) | (FfsFileAlignment2 << 1));
323
324 return ;
325 }
326
327 /**
328 Locate a free space entry that can hold this FFS file.
329
330 @param FvDevice Cached Firmware Volume.
331 @param Size The FFS file size.
332 @param RequiredAlignment FFS File Data alignment requirement.
333 @param PadSize Pointer to the size of leading Pad File.
334 @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
335
336 @retval EFI_SUCCESS The free space entry is found.
337 @retval EFI_NOT_FOUND The free space entry can't be found.
338
339 **/
340 EFI_STATUS
341 FvLocateFreeSpaceEntry (
342 IN FV_DEVICE *FvDevice,
343 IN UINTN Size,
344 IN UINTN RequiredAlignment,
345 OUT UINTN *PadSize,
346 OUT FREE_SPACE_ENTRY **FreeSpaceEntry
347 )
348 {
349 FREE_SPACE_ENTRY *FreeSpaceListEntry;
350 LIST_ENTRY *Link;
351 UINTN PadFileSize;
352
353 Link = FvDevice->FreeSpaceHeader.ForwardLink;
354 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
355
356 //
357 // Loop the free space entry list to find one that can hold the
358 // required the file size
359 //
360 while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
361 PadFileSize = CalculatePadFileSize (
362 FvDevice,
363 (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,
364 Size,
365 RequiredAlignment
366 );
367 if (FreeSpaceListEntry->Length >= Size + PadFileSize) {
368 *FreeSpaceEntry = FreeSpaceListEntry;
369 *PadSize = PadFileSize;
370 return EFI_SUCCESS;
371 }
372
373 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
374 }
375
376 return EFI_NOT_FOUND;
377
378 }
379
380 /**
381 Locate Pad File for writing, this is got from FV Cache.
382
383 @param FvDevice Cached Firmware Volume.
384 @param Size The required FFS file size.
385 @param RequiredAlignment FFS File Data alignment requirement.
386 @param PadSize Pointer to the size of leading Pad File.
387 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
388
389 @retval EFI_SUCCESS The required pad file is found.
390 @retval EFI_NOT_FOUND The required pad file can't be found.
391
392 **/
393 EFI_STATUS
394 FvLocatePadFile (
395 IN FV_DEVICE *FvDevice,
396 IN UINTN Size,
397 IN UINTN RequiredAlignment,
398 OUT UINTN *PadSize,
399 OUT FFS_FILE_LIST_ENTRY **PadFileEntry
400 )
401 {
402 FFS_FILE_LIST_ENTRY *FileEntry;
403 EFI_FFS_FILE_STATE FileState;
404 EFI_FFS_FILE_HEADER *FileHeader;
405 UINTN PadAreaLength;
406 UINTN PadFileSize;
407 UINTN HeaderSize;
408
409 FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
410
411 //
412 // travel through the whole file list to get the pad file entry
413 //
414 while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
415
416 FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
417 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
418
419 if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
420 //
421 // we find one valid pad file, check its free area length
422 //
423 if (IS_FFS_FILE2 (FileHeader)) {
424 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
425 PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
426 } else {
427 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
428 PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
429 }
430
431 PadFileSize = CalculatePadFileSize (
432 FvDevice,
433 (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize,
434 Size,
435 RequiredAlignment
436 );
437 if (PadAreaLength >= (Size + PadFileSize)) {
438 *PadSize = PadFileSize;
439 *PadFileEntry = FileEntry;
440 return EFI_SUCCESS;
441 }
442 }
443
444 FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
445 }
446
447 return EFI_NOT_FOUND;
448 }
449
450 /**
451 Locate a suitable pad file for multiple file writing.
452
453 @param FvDevice Cached Firmware Volume.
454 @param NumOfFiles The number of Files that needed updating
455 @param BufferSize The array of each file size.
456 @param RequiredAlignment The array of of FFS File Data alignment requirement.
457 @param PadSize The array of size of each leading Pad File.
458 @param TotalSizeNeeded The totalsize that can hold these files.
459 @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
460
461 @retval EFI_SUCCESS The required pad file is found.
462 @retval EFI_NOT_FOUND The required pad file can't be found.
463
464 **/
465 EFI_STATUS
466 FvSearchSuitablePadFile (
467 IN FV_DEVICE *FvDevice,
468 IN UINTN NumOfFiles,
469 IN UINTN *BufferSize,
470 IN UINTN *RequiredAlignment,
471 OUT UINTN *PadSize,
472 OUT UINTN *TotalSizeNeeded,
473 OUT FFS_FILE_LIST_ENTRY **PadFileEntry
474 )
475 {
476 FFS_FILE_LIST_ENTRY *FileEntry;
477 EFI_FFS_FILE_STATE FileState;
478 EFI_FFS_FILE_HEADER *FileHeader;
479 UINTN PadAreaLength;
480 UINTN TotalSize;
481 UINTN Index;
482 UINTN HeaderSize;
483
484 FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
485
486 //
487 // travel through the whole file list to get the pad file entry
488 //
489 while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
490
491 FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
492 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
493
494 if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
495 //
496 // we find one valid pad file, check its length
497 //
498 if (IS_FFS_FILE2 (FileHeader)) {
499 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
500 PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
501 } else {
502 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
503 PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
504 }
505 TotalSize = 0;
506
507 for (Index = 0; Index < NumOfFiles; Index++) {
508 PadSize[Index] = CalculatePadFileSize (
509 FvDevice,
510 (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize + TotalSize,
511 BufferSize[Index],
512 RequiredAlignment[Index]
513 );
514 TotalSize += PadSize[Index];
515 TotalSize += BufferSize[Index];
516
517 if (TotalSize > PadAreaLength) {
518 break;
519 }
520 }
521
522 if (PadAreaLength >= TotalSize) {
523 *PadFileEntry = FileEntry;
524 *TotalSizeNeeded = TotalSize;
525 return EFI_SUCCESS;
526 }
527 }
528
529 FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
530 }
531
532 return EFI_NOT_FOUND;
533 }
534
535 /**
536 Locate a Free Space entry which can hold these files, including
537 meeting the alignment requirements.
538
539 @param FvDevice Cached Firmware Volume.
540 @param NumOfFiles The number of Files that needed updating
541 @param BufferSize The array of each file size.
542 @param RequiredAlignment The array of of FFS File Data alignment requirement.
543 @param PadSize The array of size of each leading Pad File.
544 @param TotalSizeNeeded The got total size that can hold these files.
545 @param FreeSpaceEntry The Free Space Entry that can hold these files.
546
547 @retval EFI_SUCCESS The free space entry is found.
548 @retval EFI_NOT_FOUND The free space entry can't be found.
549
550 **/
551 EFI_STATUS
552 FvSearchSuitableFreeSpace (
553 IN FV_DEVICE *FvDevice,
554 IN UINTN NumOfFiles,
555 IN UINTN *BufferSize,
556 IN UINTN *RequiredAlignment,
557 OUT UINTN *PadSize,
558 OUT UINTN *TotalSizeNeeded,
559 OUT FREE_SPACE_ENTRY **FreeSpaceEntry
560 )
561 {
562 FREE_SPACE_ENTRY *FreeSpaceListEntry;
563 LIST_ENTRY *Link;
564 UINTN TotalSize;
565 UINTN Index;
566 UINT8 *StartAddr;
567
568 Link = FvDevice->FreeSpaceHeader.ForwardLink;
569
570 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
571
572 while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
573 TotalSize = 0;
574 StartAddr = FreeSpaceListEntry->StartingAddress;
575
576 //
577 // Calculate the totalsize we need
578 //
579 for (Index = 0; Index < NumOfFiles; Index++) {
580 //
581 // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
582 // have had its leading pad file.
583 //
584 PadSize[Index] = CalculatePadFileSize (
585 FvDevice,
586 (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,
587 BufferSize[Index],
588 RequiredAlignment[Index]
589 );
590
591 TotalSize += PadSize[Index];
592 TotalSize += BufferSize[Index];
593
594 if (TotalSize > FreeSpaceListEntry->Length) {
595 break;
596 }
597 }
598
599 if (FreeSpaceListEntry->Length >= TotalSize) {
600 *FreeSpaceEntry = FreeSpaceListEntry;
601 *TotalSizeNeeded = TotalSize;
602 return EFI_SUCCESS;
603 }
604
605 FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
606 }
607
608 return EFI_NOT_FOUND;
609 }
610
611 /**
612 Calculate the length of the remaining space in FV.
613
614 @param FvDevice Cached Firmware Volume
615 @param Offset Current offset to FV base address.
616 @param Lba LBA number for the current offset.
617 @param LOffset Offset in block for the current offset.
618
619 @return the length of remaining space.
620
621 **/
622 UINTN
623 CalculateRemainingLength (
624 IN FV_DEVICE *FvDevice,
625 IN UINTN Offset,
626 OUT EFI_LBA *Lba,
627 OUT UINTN *LOffset
628 )
629 {
630 LIST_ENTRY *Link;
631 LBA_ENTRY *LbaEntry;
632 UINTN Count;
633
634 Count = 0;
635 *Lba = 0;
636 Link = FvDevice->LbaHeader.ForwardLink;
637 LbaEntry = (LBA_ENTRY *) Link;
638
639 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
640 if (Count > Offset) {
641 break;
642 }
643
644 Count += LbaEntry->BlockLength;
645 (*Lba)++;
646 Link = LbaEntry->Link.ForwardLink;
647 LbaEntry = (LBA_ENTRY *) Link;
648 }
649
650 if (Count <= Offset) {
651 return 0;
652 }
653
654 Link = LbaEntry->Link.BackLink;
655 LbaEntry = (LBA_ENTRY *) Link;
656
657 (*Lba)--;
658 *LOffset = (UINTN) (LbaEntry->BlockLength - (Count - Offset));
659
660 Count = 0;
661 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
662
663 Count += LbaEntry->BlockLength;
664
665 Link = LbaEntry->Link.ForwardLink;
666 LbaEntry = (LBA_ENTRY *) Link;
667 }
668
669 Count -= *LOffset;
670
671 return Count;
672 }
673
674 /**
675 Writes data beginning at Lba:Offset from FV. The write terminates either
676 when *NumBytes of data have been written, or when the firmware end is
677 reached. *NumBytes is updated to reflect the actual number of bytes
678 written.
679
680 @param FvDevice Cached Firmware Volume
681 @param Offset Offset in the block at which to begin write
682 @param NumBytes At input, indicates the requested write size.
683 At output, indicates the actual number of bytes written.
684 @param Buffer Buffer containing source data for the write.
685
686 @retval EFI_SUCCESS Data is successfully written into FV.
687 @return error Data is failed written.
688
689 **/
690 EFI_STATUS
691 FvcWrite (
692 IN FV_DEVICE *FvDevice,
693 IN UINTN Offset,
694 IN OUT UINTN *NumBytes,
695 IN UINT8 *Buffer
696 )
697 {
698 EFI_STATUS Status;
699 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
700 EFI_LBA Lba;
701 UINTN LOffset;
702 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
703 UINTN RemainingLength;
704 UINTN WriteLength;
705 UINT8 *TmpBuffer;
706
707 LOffset = 0;
708 RemainingLength = CalculateRemainingLength (FvDevice, Offset, &Lba, &LOffset);
709 if ((UINTN) (*NumBytes) > RemainingLength) {
710 *NumBytes = (UINTN) RemainingLength;
711 return EFI_INVALID_PARAMETER;
712 }
713
714 Fvb = FvDevice->Fvb;
715
716 Status = Fvb->GetAttributes (
717 Fvb,
718 &FvbAttributes
719 );
720 if (EFI_ERROR (Status)) {
721 return Status;
722 }
723
724 if ((FvbAttributes & EFI_FV2_WRITE_STATUS) == 0) {
725 return EFI_ACCESS_DENIED;
726 }
727
728 RemainingLength = *NumBytes;
729 WriteLength = RemainingLength;
730 TmpBuffer = Buffer;
731
732 do {
733 Status = Fvb->Write (
734 Fvb,
735 Lba,
736 LOffset,
737 &WriteLength,
738 TmpBuffer
739 );
740 if (!EFI_ERROR (Status)) {
741 goto Done;
742 }
743
744 if (Status == EFI_BAD_BUFFER_SIZE) {
745 Lba++;
746 LOffset = 0;
747 TmpBuffer += WriteLength;
748 RemainingLength -= WriteLength;
749 WriteLength = (UINTN) RemainingLength;
750
751 continue;
752 } else {
753 return Status;
754 }
755 } while (1);
756
757 Done:
758 return EFI_SUCCESS;
759 }
760
761 /**
762 Create a new FFS file into Firmware Volume device.
763
764 @param FvDevice Cached Firmware Volume.
765 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
766 a File Header which is in init state).
767 @param BufferSize The size of FfsFileBuffer.
768 @param ActualFileSize The actual file length, it may not be multiples of 8.
769 @param FileName The FFS File Name.
770 @param FileType The FFS File Type.
771 @param FileAttributes The Attributes of the FFS File to be created.
772
773 @retval EFI_SUCCESS FFS fle is added into FV.
774 @retval EFI_INVALID_PARAMETER File type is not valid.
775 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
776 @retval EFI_NOT_FOUND FV has no enough space for the added file.
777
778 **/
779 EFI_STATUS
780 FvCreateNewFile (
781 IN FV_DEVICE *FvDevice,
782 IN UINT8 *FfsFileBuffer,
783 IN UINTN BufferSize,
784 IN UINTN ActualFileSize,
785 IN EFI_GUID *FileName,
786 IN EFI_FV_FILETYPE FileType,
787 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
788 )
789 {
790 EFI_STATUS Status;
791 EFI_FFS_FILE_HEADER *FileHeader;
792 EFI_PHYSICAL_ADDRESS BufferPtr;
793 UINTN Offset;
794 UINTN NumBytesWritten;
795 UINTN StateOffset;
796 FREE_SPACE_ENTRY *FreeSpaceEntry;
797 UINTN RequiredAlignment;
798 UINTN PadFileSize;
799 FFS_FILE_LIST_ENTRY *PadFileEntry;
800 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
801 FFS_FILE_LIST_ENTRY *FfsFileEntry;
802 UINTN HeaderSize;
803
804 //
805 // File Type: 0x0E~0xE0 are reserved
806 //
807 if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
808 return EFI_INVALID_PARAMETER;
809 }
810
811 //
812 // First find a free space that can hold this image.
813 // Check alignment, FFS at least must be aligned at 8-byte boundary
814 //
815 RequiredAlignment = GetRequiredAlignment (FileAttributes);
816
817 Status = FvLocateFreeSpaceEntry (
818 FvDevice,
819 BufferSize,
820 RequiredAlignment,
821 &PadFileSize,
822 &FreeSpaceEntry
823 );
824 if (EFI_ERROR (Status)) {
825 //
826 // Maybe we need to find a PAD file that can hold this image
827 //
828 Status = FvCreateNewFileInsidePadFile (
829 FvDevice,
830 FfsFileBuffer,
831 BufferSize,
832 ActualFileSize,
833 FileName,
834 FileType,
835 FileAttributes
836 );
837
838 return Status;
839 }
840
841 BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
842
843 //
844 // If we need a leading PAD File, create it first.
845 //
846 if (PadFileSize != 0) {
847 Status = FvCreatePadFileInFreeSpace (
848 FvDevice,
849 FreeSpaceEntry,
850 PadFileSize - sizeof (EFI_FFS_FILE_HEADER),
851 &PadFileEntry
852 );
853 if (EFI_ERROR (Status)) {
854 return Status;
855 }
856 }
857 //
858 // Maybe we create a pad file, so re-get the free space starting address
859 // and length
860 //
861 BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
862
863 //
864 // File creation step 1: Allocate File Header,
865 // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
866 // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
867 //
868 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
869 if (ActualFileSize > 0x00FFFFFF) {
870 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
871 } else {
872 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
873 }
874 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, FileHeader);
875
876 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
877 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
878
879 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
880 Status = FvcWrite (
881 FvDevice,
882 StateOffset,
883 &NumBytesWritten,
884 &FileHeader->State
885 );
886 if (EFI_ERROR (Status)) {
887 return Status;
888 }
889 //
890 // update header 2 cache
891 //
892 CopyMem (
893 (UINT8 *) (UINTN) BufferPtr,
894 FileHeader,
895 HeaderSize
896 );
897
898 //
899 // update Free Space Entry, now need to substract the file header length
900 //
901 FreeSpaceEntry->StartingAddress += HeaderSize;
902 FreeSpaceEntry->Length -= HeaderSize;
903
904 CopyGuid (&FileHeader->Name, FileName);
905 FileHeader->Type = FileType;
906
907 //
908 // Convert FvFileAttribute to FfsFileAttributes
909 //
910 FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
911
912 FileHeader->Attributes = TmpFileAttribute;
913
914 //
915 // File size is including the FFS File Header.
916 //
917 if (ActualFileSize > 0x00FFFFFF) {
918 ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize;
919 *(UINT32 *) FileHeader->Size &= 0xFF000000;
920 FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
921 } else {
922 *(UINT32 *) FileHeader->Size &= 0xFF000000;
923 *(UINT32 *) FileHeader->Size |= ActualFileSize;
924 }
925
926 SetHeaderChecksum (FileHeader);
927
928 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
929
930 NumBytesWritten = HeaderSize;
931 Status = FvcWrite (
932 FvDevice,
933 Offset,
934 &NumBytesWritten,
935 (UINT8 *) FileHeader
936 );
937 if (EFI_ERROR (Status)) {
938 return Status;
939 }
940 //
941 // update header 2 cache
942 //
943 CopyMem (
944 (UINT8 *) (UINTN) BufferPtr,
945 FileHeader,
946 HeaderSize
947 );
948
949 //
950 // end of step 1
951 //
952 // File creation step 2:
953 // MARK EFI_FILE_HEADER_VALID bit to TRUE,
954 // Write IntegrityCheck.File, File Data
955 //
956 SetFileState (EFI_FILE_HEADER_VALID, FileHeader);
957
958 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
959 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
960
961 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
962 Status = FvcWrite (
963 FvDevice,
964 StateOffset,
965 &NumBytesWritten,
966 &FileHeader->State
967 );
968 if (EFI_ERROR (Status)) {
969 return Status;
970 }
971 //
972 // update header 2 cache
973 //
974 CopyMem (
975 (UINT8 *) (UINTN) BufferPtr,
976 FileHeader,
977 HeaderSize
978 );
979
980 //
981 // update Free Space Entry, now need to substract the file data length
982 //
983 FreeSpaceEntry->StartingAddress += (BufferSize - HeaderSize);
984 FreeSpaceEntry->Length -= (BufferSize - HeaderSize);
985
986 //
987 // Calculate File Checksum
988 //
989 SetFileChecksum (FileHeader, ActualFileSize);
990
991 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
992
993 NumBytesWritten = BufferSize;
994 Status = FvcWrite (
995 FvDevice,
996 Offset,
997 &NumBytesWritten,
998 FfsFileBuffer
999 );
1000 if (EFI_ERROR (Status)) {
1001 return Status;
1002 }
1003 //
1004 // each time write block successfully, write also to cache
1005 //
1006 CopyMem (
1007 (UINT8 *) (UINTN) BufferPtr,
1008 FfsFileBuffer,
1009 NumBytesWritten
1010 );
1011
1012 //
1013 // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
1014 //
1015 SetFileState (EFI_FILE_DATA_VALID, FileHeader);
1016
1017 Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
1018 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
1019
1020 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1021 Status = FvcWrite (
1022 FvDevice,
1023 StateOffset,
1024 &NumBytesWritten,
1025 &FileHeader->State
1026 );
1027 if (EFI_ERROR (Status)) {
1028 return Status;
1029 }
1030 //
1031 // update header 2 cache
1032 //
1033 CopyMem (
1034 (UINT8 *) (UINTN) BufferPtr,
1035 FileHeader,
1036 HeaderSize
1037 );
1038
1039 //
1040 // If successfully, insert an FfsFileEntry at the end of ffs file list
1041 //
1042
1043 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
1044 ASSERT (FfsFileEntry != NULL);
1045 FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) BufferPtr;
1046 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
1047
1048 //
1049 // Set cache file to this file
1050 //
1051 FvDevice->CurrentFfsFile = FfsFileEntry;
1052
1053 return EFI_SUCCESS;
1054 }
1055
1056 /**
1057 Update a File, so after successful update, there are 2 files existing
1058 in FV, one is marked for deleted, and another one is valid.
1059
1060 @param FvDevice Cached Firmware Volume.
1061 @param FfsFileBuffer A buffer that holds an FFS file,(it contains
1062 a File Header which is in init state).
1063 @param BufferSize The size of FfsFileBuffer.
1064 @param ActualFileSize The actual file length, it may not be multiples of 8.
1065 @param FileName The FFS File Name.
1066 @param NewFileType The FFS File Type.
1067 @param NewFileAttributes The Attributes of the FFS File to be created.
1068
1069 @retval EFI_SUCCESS FFS fle is updated into FV.
1070 @retval EFI_INVALID_PARAMETER File type is not valid.
1071 @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
1072 @retval EFI_NOT_FOUND FV has no enough space for the added file.
1073 FFS with same file name is not found in FV.
1074
1075 **/
1076 EFI_STATUS
1077 FvUpdateFile (
1078 IN FV_DEVICE *FvDevice,
1079 IN UINT8 *FfsFileBuffer,
1080 IN UINTN BufferSize,
1081 IN UINTN ActualFileSize,
1082 IN EFI_GUID *FileName,
1083 IN EFI_FV_FILETYPE NewFileType,
1084 IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
1085 )
1086 {
1087 EFI_STATUS Status;
1088 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1089 UINTN NumBytesWritten;
1090 EFI_FV_FILETYPE OldFileType;
1091 EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
1092 UINTN OldFileSize;
1093 EFI_FFS_FILE_HEADER *OldFileHeader;
1094 UINTN OldOffset;
1095 UINTN OldStateOffset;
1096 FFS_FILE_LIST_ENTRY *OldFfsFileEntry;
1097 UINTN Key;
1098 EFI_GUID FileNameGuid;
1099
1100 Fv = &FvDevice->Fv;
1101
1102 //
1103 // Step 1, find old file,
1104 // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
1105 //
1106
1107 //
1108 // Check if the file was read last time.
1109 //
1110 OldFileHeader = NULL;
1111 OldFfsFileEntry = FvDevice->CurrentFfsFile;
1112
1113 if (OldFfsFileEntry != NULL) {
1114 OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
1115 }
1116
1117 if ((OldFfsFileEntry == NULL) || (!CompareGuid (&OldFileHeader->Name, FileName))) {
1118 Key = 0;
1119 do {
1120 OldFileType = 0;
1121 Status = Fv->GetNextFile (
1122 Fv,
1123 &Key,
1124 &OldFileType,
1125 &FileNameGuid,
1126 &OldFileAttributes,
1127 &OldFileSize
1128 );
1129 if (EFI_ERROR (Status)) {
1130 return Status;
1131 }
1132 } while (!CompareGuid (&FileNameGuid, FileName));
1133
1134 //
1135 // Get FfsFileEntry from the search key
1136 //
1137 OldFfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
1138
1139 //
1140 // Double check file state before being ready to be removed
1141 //
1142 OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
1143 } else {
1144 //
1145 // Mark the cache file to invalid
1146 //
1147 FvDevice->CurrentFfsFile = NULL;
1148 }
1149 //
1150 // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
1151 //
1152 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
1153
1154 OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
1155 OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
1156
1157 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1158 Status = FvcWrite (
1159 FvDevice,
1160 OldStateOffset,
1161 &NumBytesWritten,
1162 &OldFileHeader->State
1163 );
1164 if (EFI_ERROR (Status)) {
1165 //
1166 // if failed, write the bit back in the cache, its XOR operation.
1167 //
1168 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
1169
1170 return Status;
1171 }
1172
1173 //
1174 // Step 2, Create New Files
1175 //
1176 Status = FvCreateNewFile (
1177 FvDevice,
1178 FfsFileBuffer,
1179 BufferSize,
1180 ActualFileSize,
1181 FileName,
1182 NewFileType,
1183 NewFileAttributes
1184 );
1185 if (EFI_ERROR (Status)) {
1186 return Status;
1187 }
1188
1189 //
1190 // If successfully, remove this file entry,
1191 // although delete file may fail.
1192 //
1193 (OldFfsFileEntry->Link.BackLink)->ForwardLink = OldFfsFileEntry->Link.ForwardLink;
1194 (OldFfsFileEntry->Link.ForwardLink)->BackLink = OldFfsFileEntry->Link.BackLink;
1195 FreePool (OldFfsFileEntry);
1196
1197 //
1198 // Step 3: Delete old files,
1199 // by marking EFI_FILE_DELETED to TRUE
1200 //
1201 SetFileState (EFI_FILE_DELETED, OldFileHeader);
1202
1203 OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
1204 OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
1205
1206 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1207 Status = FvcWrite (
1208 FvDevice,
1209 OldStateOffset,
1210 &NumBytesWritten,
1211 &OldFileHeader->State
1212 );
1213 if (EFI_ERROR (Status)) {
1214 //
1215 // if failed, write the bit back in the cache, its XOR operation.
1216 //
1217 SetFileState (EFI_FILE_DELETED, OldFileHeader);
1218
1219 return Status;
1220 }
1221
1222 return EFI_SUCCESS;
1223 }
1224
1225 /**
1226 Deleted a given file from FV device.
1227
1228 @param FvDevice Cached Firmware Volume.
1229 @param NameGuid The FFS File Name.
1230
1231 @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
1232 @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
1233
1234 **/
1235 EFI_STATUS
1236 FvDeleteFile (
1237 IN FV_DEVICE *FvDevice,
1238 IN EFI_GUID *NameGuid
1239 )
1240 {
1241 EFI_STATUS Status;
1242 UINTN Key;
1243 EFI_GUID FileNameGuid;
1244 EFI_FV_FILETYPE FileType;
1245 EFI_FV_FILE_ATTRIBUTES FileAttributes;
1246 UINTN FileSize;
1247 EFI_FFS_FILE_HEADER *FileHeader;
1248 FFS_FILE_LIST_ENTRY *FfsFileEntry;
1249 EFI_FFS_FILE_STATE FileState;
1250 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1251 UINTN Offset;
1252 UINTN StateOffset;
1253 UINTN NumBytesWritten;
1254
1255 Fv = &FvDevice->Fv;
1256
1257 //
1258 // Check if the file was read last time.
1259 //
1260 FileHeader = NULL;
1261 FfsFileEntry = FvDevice->CurrentFfsFile;
1262
1263 if (FfsFileEntry != NULL) {
1264 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
1265 }
1266
1267 if ((FfsFileEntry == NULL) || (!CompareGuid (&FileHeader->Name, NameGuid))) {
1268 //
1269 // Next search for the file using GetNextFile
1270 //
1271 Key = 0;
1272 do {
1273 FileType = 0;
1274 Status = Fv->GetNextFile (
1275 Fv,
1276 &Key,
1277 &FileType,
1278 &FileNameGuid,
1279 &FileAttributes,
1280 &FileSize
1281 );
1282 if (EFI_ERROR (Status)) {
1283 return Status;
1284 }
1285 } while (!CompareGuid (&FileNameGuid, NameGuid));
1286
1287 //
1288 // Get FfsFileEntry from the search key
1289 //
1290 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
1291
1292 //
1293 // Double check file state before being ready to be removed
1294 //
1295 FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
1296 } else {
1297 //
1298 // Mark the cache file to NULL
1299 //
1300 FvDevice->CurrentFfsFile = NULL;
1301 }
1302
1303 FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
1304
1305 if (FileState == EFI_FILE_HEADER_INVALID) {
1306 return EFI_NOT_FOUND;
1307 }
1308
1309 if (FileState == EFI_FILE_DELETED) {
1310 return EFI_NOT_FOUND;
1311 }
1312 //
1313 // Delete File: Mark EFI_FILE_DELETED to TRUE
1314 //
1315 SetFileState (EFI_FILE_DELETED, FileHeader);
1316
1317 Offset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader - FvDevice->CachedFv);
1318 StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
1319
1320 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
1321 Status = FvcWrite (
1322 FvDevice,
1323 StateOffset,
1324 &NumBytesWritten,
1325 &FileHeader->State
1326 );
1327 if (EFI_ERROR (Status)) {
1328 //
1329 // if failed, write the bit back in the cache, its XOR operation.
1330 //
1331 SetFileState (EFI_FILE_DELETED, FileHeader);
1332
1333 return Status;
1334 }
1335 //
1336 // If successfully, remove this file entry
1337 //
1338 FvDevice->CurrentFfsFile = NULL;
1339
1340 (FfsFileEntry->Link.BackLink)->ForwardLink = FfsFileEntry->Link.ForwardLink;
1341 (FfsFileEntry->Link.ForwardLink)->BackLink = FfsFileEntry->Link.BackLink;
1342 FreePool (FfsFileEntry);
1343
1344 return EFI_SUCCESS;
1345 }
1346
1347 /**
1348 Writes one or more files to the firmware volume.
1349
1350 @param This Indicates the calling context.
1351 @param NumberOfFiles Number of files.
1352 @param WritePolicy WritePolicy indicates the level of reliability
1353 for the write in the event of a power failure or
1354 other system failure during the write operation.
1355 @param FileData FileData is an pointer to an array of
1356 EFI_FV_WRITE_DATA. Each element of array
1357 FileData represents a file to be written.
1358
1359 @retval EFI_SUCCESS Files successfully written to firmware volume
1360 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
1361 @retval EFI_DEVICE_ERROR Device error.
1362 @retval EFI_WRITE_PROTECTED Write protected.
1363 @retval EFI_NOT_FOUND Not found.
1364 @retval EFI_INVALID_PARAMETER Invalid parameter.
1365 @retval EFI_UNSUPPORTED This function not supported.
1366
1367 **/
1368 EFI_STATUS
1369 EFIAPI
1370 FvWriteFile (
1371 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
1372 IN UINT32 NumberOfFiles,
1373 IN EFI_FV_WRITE_POLICY WritePolicy,
1374 IN EFI_FV_WRITE_FILE_DATA *FileData
1375 )
1376 {
1377 EFI_STATUS Status;
1378 UINTN Index1;
1379 UINTN Index2;
1380 UINT8 *FileBuffer;
1381 UINTN BufferSize;
1382 UINTN ActualSize;
1383 UINT8 ErasePolarity;
1384 FV_DEVICE *FvDevice;
1385 EFI_FV_FILETYPE FileType;
1386 EFI_FV_FILE_ATTRIBUTES FileAttributes;
1387 UINTN Size;
1388 BOOLEAN CreateNewFile[MAX_FILES];
1389 UINTN NumDelete;
1390 EFI_FV_ATTRIBUTES FvAttributes;
1391 UINT32 AuthenticationStatus;
1392 UINTN HeaderSize;
1393
1394 if (NumberOfFiles > MAX_FILES) {
1395 return EFI_UNSUPPORTED;
1396 }
1397
1398 Status = EFI_SUCCESS;
1399
1400 SetMem (CreateNewFile, NumberOfFiles, TRUE);
1401
1402 FvDevice = FV_DEVICE_FROM_THIS (This);
1403
1404 //
1405 // First check the volume attributes.
1406 //
1407 Status = This->GetVolumeAttributes (
1408 This,
1409 &FvAttributes
1410 );
1411 if (EFI_ERROR (Status)) {
1412 return Status;
1413 }
1414 //
1415 // Can we have write right?
1416 //
1417 if ((FvAttributes & EFI_FV2_WRITE_STATUS) == 0) {
1418 return EFI_WRITE_PROTECTED;
1419 }
1420
1421 ErasePolarity = FvDevice->ErasePolarity;
1422
1423 //
1424 // Loop for all files
1425 //
1426 NumDelete = 0;
1427 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1428
1429 if ((FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER) > 0x00FFFFFF) && !FvDevice->IsFfs3Fv) {
1430 //
1431 // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
1432 //
1433 DEBUG ((EFI_D_ERROR, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
1434 return EFI_INVALID_PARAMETER;
1435 }
1436
1437 if (FileData[Index1].BufferSize == 0) {
1438 //
1439 // Here we will delete this file
1440 //
1441 Status = This->ReadFile (
1442 This,
1443 FileData[Index1].NameGuid,
1444 NULL,
1445 &Size,
1446 &FileType,
1447 &FileAttributes,
1448 &AuthenticationStatus
1449 );
1450 if (!EFI_ERROR (Status)) {
1451 NumDelete++;
1452 } else {
1453 return Status;
1454 }
1455 }
1456
1457 if (FileData[Index1].Type == EFI_FV_FILETYPE_FFS_PAD) {
1458 //
1459 // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
1460 // "Standard firmware file system services will not return the handle of any pad files,
1461 // nor will they permit explicit creation of such files."
1462 //
1463 return EFI_INVALID_PARAMETER;
1464 }
1465 }
1466
1467 if ((NumDelete != NumberOfFiles) && (NumDelete != 0)) {
1468 //
1469 // A delete was request with a multiple file write
1470 //
1471 return EFI_INVALID_PARAMETER;
1472 }
1473
1474 if (NumDelete == NumberOfFiles) {
1475 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1476 //
1477 // Delete Files
1478 //
1479 Status = FvDeleteFile (FvDevice, FileData[Index1].NameGuid);
1480 if (EFI_ERROR (Status)) {
1481 return Status;
1482 }
1483 }
1484
1485 return EFI_SUCCESS;
1486 }
1487
1488 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1489 Status = This->ReadFile (
1490 This,
1491 FileData[Index1].NameGuid,
1492 NULL,
1493 &Size,
1494 &FileType,
1495 &FileAttributes,
1496 &AuthenticationStatus
1497 );
1498 if (!EFI_ERROR (Status)) {
1499 CreateNewFile[Index1] = FALSE;
1500 } else if (Status == EFI_NOT_FOUND) {
1501 CreateNewFile[Index1] = TRUE;
1502 } else {
1503 return Status;
1504 }
1505 //
1506 // Checking alignment
1507 //
1508 if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {
1509 UINT8 FFSAlignmentValue;
1510 UINT8 FvAlignmentValue;
1511
1512 FFSAlignmentValue = (UINT8) (FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT);
1513 FvAlignmentValue = (UINT8) (((UINT32) (FvAttributes & EFI_FV2_ALIGNMENT)) >> 16);
1514
1515 if (FFSAlignmentValue > FvAlignmentValue) {
1516 return EFI_INVALID_PARAMETER;
1517 }
1518 }
1519 }
1520
1521 if ((WritePolicy != EFI_FV_RELIABLE_WRITE) && (WritePolicy != EFI_FV_UNRELIABLE_WRITE)) {
1522 return EFI_INVALID_PARAMETER;
1523 }
1524 //
1525 // Checking the reliable write is supported by FV
1526 //
1527
1528 if ((WritePolicy == EFI_FV_RELIABLE_WRITE) && (NumberOfFiles > 1)) {
1529 //
1530 // Only for multiple files, reliable write is meaningful
1531 //
1532 Status = FvCreateMultipleFiles (
1533 FvDevice,
1534 NumberOfFiles,
1535 FileData,
1536 CreateNewFile
1537 );
1538
1539 return Status;
1540 }
1541
1542 for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
1543 //
1544 // Making Buffersize QWORD boundary, and add file tail.
1545 //
1546 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
1547 ActualSize = FileData[Index1].BufferSize + HeaderSize;
1548 if (ActualSize > 0x00FFFFFF) {
1549 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
1550 ActualSize = FileData[Index1].BufferSize + HeaderSize;
1551 }
1552 BufferSize = ActualSize;
1553
1554 while ((BufferSize & 0x07) != 0) {
1555 BufferSize++;
1556 }
1557
1558 FileBuffer = AllocateZeroPool (BufferSize);
1559 if (FileBuffer == NULL) {
1560 return Status;
1561 }
1562 //
1563 // Copy File Data into FileBuffer
1564 //
1565 CopyMem (
1566 FileBuffer + HeaderSize,
1567 FileData[Index1].Buffer,
1568 FileData[Index1].BufferSize
1569 );
1570
1571 if (ErasePolarity == 1) {
1572 //
1573 // Fill the file header and padding byte with Erase Byte
1574 //
1575 for (Index2 = 0; Index2 < HeaderSize; Index2++) {
1576 FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
1577 }
1578
1579 for (Index2 = ActualSize; Index2 < BufferSize; Index2++) {
1580 FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
1581 }
1582 }
1583
1584 if (CreateNewFile[Index1]) {
1585 Status = FvCreateNewFile (
1586 FvDevice,
1587 FileBuffer,
1588 BufferSize,
1589 ActualSize,
1590 FileData[Index1].NameGuid,
1591 FileData[Index1].Type,
1592 FileData[Index1].FileAttributes
1593 );
1594 } else {
1595 Status = FvUpdateFile (
1596 FvDevice,
1597 FileBuffer,
1598 BufferSize,
1599 ActualSize,
1600 FileData[Index1].NameGuid,
1601 FileData[Index1].Type,
1602 FileData[Index1].FileAttributes
1603 );
1604 }
1605
1606 FreePool (FileBuffer);
1607
1608 if (EFI_ERROR (Status)) {
1609 return Status;
1610 }
1611 }
1612
1613 return EFI_SUCCESS;
1614 }