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