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