]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
IntelFrameworkModulePkg: Add FwVolDxe driver
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwPadFile.c
1 /** @file
2 Implements functions to pad 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 Calculate the checksum for a PAD file.
21
22 @param PadFileHeader The Pad File to be caculeted the checksum.
23
24 **/
25 VOID
26 SetPadFileChecksum (
27 IN EFI_FFS_FILE_HEADER *PadFileHeader
28 )
29 {
30 UINT32 PadFileLength;
31
32 if ((PadFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
33
34 PadFileLength = *(UINT32 *) PadFileHeader->Size & 0x00FFFFFF;
35
36 //
37 // Calculate checksum of Pad File Data
38 //
39 PadFileHeader->IntegrityCheck.Checksum.File =
40 CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER), PadFileLength - sizeof (EFI_FFS_FILE_HEADER));
41
42 } else {
43
44 PadFileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
45
46 }
47
48 return ;
49 }
50
51 /**
52 Create a PAD File in the Free Space.
53
54 @param FvDevice Firmware Volume Device.
55 @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.
56 @param Size Pad file Size, not include the header.
57 @param PadFileEntry The Ffs File Entry that points to this Pad File.
58
59 @retval EFI_SUCCESS Successfully create a PAD file.
60 @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.
61 @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.
62 @retval EFI_DEVICE_ERROR Free space is not erased.
63 **/
64 EFI_STATUS
65 FvCreatePadFileInFreeSpace (
66 IN FV_DEVICE *FvDevice,
67 IN FREE_SPACE_ENTRY *FreeSpaceEntry,
68 IN UINTN Size,
69 OUT FFS_FILE_LIST_ENTRY **PadFileEntry
70 )
71 {
72 EFI_STATUS Status;
73 EFI_FFS_FILE_HEADER *PadFileHeader;
74 UINTN Offset;
75 UINTN NumBytesWritten;
76 UINTN StateOffset;
77 UINT8 *StartPos;
78 FFS_FILE_LIST_ENTRY *FfsFileEntry;
79
80 if (FreeSpaceEntry->Length < Size + sizeof (EFI_FFS_FILE_HEADER)) {
81 return EFI_OUT_OF_RESOURCES;
82 }
83
84 if ((Size & 0x07) != 0) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 StartPos = FreeSpaceEntry->StartingAddress;
89
90 //
91 // First double check the space
92 //
93 if (!IsBufferErased (
94 FvDevice->ErasePolarity,
95 StartPos,
96 Size + sizeof (EFI_FFS_FILE_HEADER)
97 )) {
98 return EFI_DEVICE_ERROR;
99 }
100
101 PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;
102
103 //
104 // Create File Step 1
105 //
106 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
107
108 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
109 StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
110
111 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
112 Status = FvcWrite (
113 FvDevice,
114 StateOffset,
115 &NumBytesWritten,
116 &PadFileHeader->State
117 );
118 if (EFI_ERROR (Status)) {
119 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
120 return Status;
121 }
122 //
123 // Update Free Space Entry, since header is allocated
124 //
125 FreeSpaceEntry->Length -= sizeof (EFI_FFS_FILE_HEADER);
126 FreeSpaceEntry->StartingAddress += sizeof (EFI_FFS_FILE_HEADER);
127
128 //
129 // Fill File Name Guid, here we assign a NULL-GUID to Pad files
130 //
131 ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
132
133 //
134 // Fill File Type, checksum(0), Attributes(0), Size
135 //
136 PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
137 PadFileHeader->Attributes = 0;
138 *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
139 *(UINT32 *) PadFileHeader->Size |= (Size + sizeof (EFI_FFS_FILE_HEADER));
140
141 SetHeaderChecksum (PadFileHeader);
142 SetPadFileChecksum (PadFileHeader);
143
144 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
145
146 NumBytesWritten = sizeof (EFI_FFS_FILE_HEADER);
147 Status = FvcWrite (
148 FvDevice,
149 Offset,
150 &NumBytesWritten,
151 (UINT8 *) PadFileHeader
152 );
153 if (EFI_ERROR (Status)) {
154 return Status;
155 }
156
157 //
158 // Step 2, then Mark header valid, since no data write,
159 // mark the data valid at the same time.
160 //
161 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
162 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
163
164 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
165 StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
166
167 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
168 Status = FvcWrite (
169 FvDevice,
170 StateOffset,
171 &NumBytesWritten,
172 &PadFileHeader->State
173 );
174 if (EFI_ERROR (Status)) {
175 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
176 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
177 return Status;
178 }
179 //
180 // Update Free Space Entry, since header is allocated
181 //
182 FreeSpaceEntry->Length -= Size;
183 FreeSpaceEntry->StartingAddress += Size;
184
185 //
186 // If successfully, insert an FfsFileEntry at the end of ffs file list
187 //
188 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
189 ASSERT (FfsFileEntry != NULL);
190
191 FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos;
192 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
193
194 *PadFileEntry = FfsFileEntry;
195 FvDevice->CurrentFfsFile = FfsFileEntry;
196
197 return EFI_SUCCESS;
198 }
199
200 /**
201 Fill pad file header within firmware cache.
202
203 @param PadFileHeader The start of the Pad File Buffer.
204 @param PadFileLength The length of the pad file including the header.
205
206 **/
207 VOID
208 FvFillPadFile (
209 IN EFI_FFS_FILE_HEADER *PadFileHeader,
210 IN UINTN PadFileLength
211 )
212 {
213 //
214 // Fill File Name Guid, here we assign a NULL-GUID to Pad files
215 //
216 ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
217
218 //
219 // Fill File Type, checksum(0), Attributes(0), Size
220 //
221 PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
222 PadFileHeader->Attributes = 0;
223 *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
224 *(UINT32 *) PadFileHeader->Size |= PadFileLength;
225
226 SetHeaderChecksum (PadFileHeader);
227 SetPadFileChecksum (PadFileHeader);
228
229 //
230 // Set File State to 0x00000111
231 //
232 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
233 SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
234 SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
235
236 return ;
237 }
238
239 /**
240 Create entire FFS file.
241
242 @param FileHeader Starting Address of a Buffer that hold the FFS File image.
243 @param FfsFileBuffer The source buffer that contains the File Data.
244 @param BufferSize The length of FfsFileBuffer.
245 @param ActualFileSize Size of FFS file.
246 @param FileName The Guid of Ffs File.
247 @param FileType The type of the written Ffs File.
248 @param FileAttributes The attributes of the written Ffs File.
249
250 @retval EFI_INVALID_PARAMETER File type is not valid.
251 @retval EFI_SUCCESS FFS file is successfully created.
252
253 **/
254 EFI_STATUS
255 FvFillFfsFile (
256 OUT EFI_FFS_FILE_HEADER *FileHeader,
257 IN UINT8 *FfsFileBuffer,
258 IN UINTN BufferSize,
259 IN UINTN ActualFileSize,
260 IN EFI_GUID *FileName,
261 IN EFI_FV_FILETYPE FileType,
262 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
263 )
264 {
265 EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
266 EFI_FFS_FILE_HEADER *TmpFileHeader;
267
268 //
269 // File Type value 0x0E~0xE0 are reserved
270 //
271 if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
272 return EFI_INVALID_PARAMETER;
273 }
274
275 TmpFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
276 //
277 // First fill all fields ready in FfsFileBuffer
278 //
279 CopyGuid (&TmpFileHeader->Name, FileName);
280 TmpFileHeader->Type = FileType;
281
282 //
283 // Convert the FileAttributes to FFSFileAttributes
284 //
285 FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
286
287 TmpFileHeader->Attributes = TmpFileAttribute;
288
289 *(UINT32 *) TmpFileHeader->Size &= 0xFF000000;
290 *(UINT32 *) TmpFileHeader->Size |= ActualFileSize;
291
292 SetHeaderChecksum (TmpFileHeader);
293 SetFileChecksum (TmpFileHeader, ActualFileSize);
294
295 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, TmpFileHeader);
296 SetFileState (EFI_FILE_HEADER_VALID, TmpFileHeader);
297 SetFileState (EFI_FILE_DATA_VALID, TmpFileHeader);
298
299 //
300 // Copy data from FfsFileBuffer to FileHeader(cache)
301 //
302 CopyMem (FileHeader, FfsFileBuffer, BufferSize);
303
304 return EFI_SUCCESS;
305 }
306
307 /**
308 Fill some other extra space using 0xFF(Erase Value).
309
310 @param ErasePolarity Fv erase value.
311 @param FileHeader Point to the start of FFS File.
312 @param ExtraLength The pading length.
313
314 **/
315 VOID
316 FvAdjustFfsFile (
317 IN UINT8 ErasePolarity,
318 IN EFI_FFS_FILE_HEADER *FileHeader,
319 IN UINTN ExtraLength
320 )
321 {
322 UINTN FileLength;
323 UINT8 *Ptr;
324 UINT8 PadingByte;
325
326 FileLength = *(UINT32 *) FileHeader->Size & 0x00FFFFFF;
327 Ptr = (UINT8 *) FileHeader + FileLength;
328
329 if (ErasePolarity == 0) {
330 PadingByte = 0;
331 } else {
332 PadingByte = 0xFF;
333 }
334 //
335 // Fill the non-used space with Padding Byte
336 //
337 SetMem (Ptr, ExtraLength, PadingByte);
338
339 return ;
340 }
341
342 /**
343 Free File List entry pointed by FileListHead.
344
345 @param FileListHeader FileListEntry Header.
346
347 **/
348 VOID
349 FreeFileList (
350 IN LIST_ENTRY *FileListHead
351 )
352 {
353 FFS_FILE_LIST_ENTRY *FfsFileEntry;
354 LIST_ENTRY *NextEntry;
355
356 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) (FileListHead->ForwardLink);
357
358 //
359 // Loop the whole list entry to free resources
360 //
361 while (&FfsFileEntry->Link != FileListHead) {
362 NextEntry = (&FfsFileEntry->Link)->ForwardLink;
363 FreePool (FfsFileEntry);
364 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
365 }
366
367 return ;
368 }
369
370 /**
371 Create a new file within a PAD file area.
372
373 @param FvDevice Firmware Volume Device.
374 @param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state).
375 @param BufferSize The size of FfsFileBuffer.
376 @param ActualFileSize The actual file length, it may not be multiples of 8.
377 @param FileName The FFS File Name.
378 @param FileType The FFS File Type.
379 @param FileAttributes The Attributes of the FFS File to be created.
380
381 @retval EFI_SUCCESS Successfully create a new file within the found PAD file area.
382 @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.
383 @retval other errors New file is created failed.
384
385 **/
386 EFI_STATUS
387 FvCreateNewFileInsidePadFile (
388 IN FV_DEVICE *FvDevice,
389 IN UINT8 *FfsFileBuffer,
390 IN UINTN BufferSize,
391 IN UINTN ActualFileSize,
392 IN EFI_GUID *FileName,
393 IN EFI_FV_FILETYPE FileType,
394 IN EFI_FV_FILE_ATTRIBUTES FileAttributes
395 )
396 {
397 UINTN RequiredAlignment;
398 FFS_FILE_LIST_ENTRY *PadFileEntry;
399 EFI_STATUS Status;
400 UINTN PadAreaLength;
401 UINTN PadSize;
402 EFI_FFS_FILE_HEADER *FileHeader;
403 EFI_FFS_FILE_HEADER *OldPadFileHeader;
404 EFI_FFS_FILE_HEADER *PadFileHeader;
405 EFI_FFS_FILE_HEADER *TailPadFileHeader;
406 UINTN StateOffset;
407 UINTN Offset;
408 UINTN NumBytesWritten;
409 UINT8 *StartPos;
410 LIST_ENTRY NewFileList;
411 FFS_FILE_LIST_ENTRY *NewFileListEntry;
412 FFS_FILE_LIST_ENTRY *FfsEntry;
413 FFS_FILE_LIST_ENTRY *NextFfsEntry;
414
415 //
416 // First get the required alignment from the File Attributes
417 //
418 RequiredAlignment = GetRequiredAlignment (FileAttributes);
419
420 //
421 // Find a suitable PAD File
422 //
423 Status = FvLocatePadFile (
424 FvDevice,
425 BufferSize,
426 RequiredAlignment,
427 &PadSize,
428 &PadFileEntry
429 );
430
431 if (EFI_ERROR (Status)) {
432 return EFI_OUT_OF_RESOURCES;
433 }
434
435 OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
436
437 //
438 // Step 1: Update Pad File Header
439 //
440 SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldPadFileHeader);
441
442 StartPos = PadFileEntry->FfsHeader;
443
444 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
445 StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
446
447 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
448 Status = FvcWrite (
449 FvDevice,
450 StateOffset,
451 &NumBytesWritten,
452 &OldPadFileHeader->State
453 );
454 if (EFI_ERROR (Status)) {
455 SetFileState (EFI_FILE_HEADER_CONSTRUCTION, OldPadFileHeader);
456 return Status;
457 }
458
459 //
460 // Step 2: Update Pad area
461 //
462 InitializeListHead (&NewFileList);
463
464 PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
465
466 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
467
468 if (RequiredAlignment != 8) {
469 //
470 // Insert a PAD file before to achieve required alignment
471 //
472 FvFillPadFile (PadFileHeader, PadSize);
473 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
474 ASSERT (NewFileListEntry != NULL);
475 NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
476 InsertTailList (&NewFileList, &NewFileListEntry->Link);
477 }
478
479 FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize);
480
481 Status = FvFillFfsFile (
482 FileHeader,
483 FfsFileBuffer,
484 BufferSize,
485 ActualFileSize,
486 FileName,
487 FileType,
488 FileAttributes
489 );
490 if (EFI_ERROR (Status)) {
491 return Status;
492 }
493
494 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
495 ASSERT (NewFileListEntry != NULL);
496
497 NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
498 InsertTailList (&NewFileList, &NewFileListEntry->Link);
499
500 FvDevice->CurrentFfsFile = NewFileListEntry;
501
502 if (PadAreaLength > (BufferSize + PadSize)) {
503 if ((PadAreaLength - BufferSize - PadSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
504 //
505 // we can insert another PAD file
506 //
507 TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize);
508 FvFillPadFile (TailPadFileHeader, PadAreaLength - BufferSize - PadSize);
509
510 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
511 ASSERT (NewFileListEntry != NULL);
512
513 NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
514 InsertTailList (&NewFileList, &NewFileListEntry->Link);
515 } else {
516 //
517 // because left size cannot hold another PAD file header,
518 // adjust the writing file size (just in cache)
519 //
520 FvAdjustFfsFile (
521 FvDevice->ErasePolarity,
522 FileHeader,
523 PadAreaLength - BufferSize - PadSize
524 );
525 }
526 }
527 //
528 // Start writing to FV
529 //
530 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
531
532 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
533
534 NumBytesWritten = PadAreaLength;
535 Status = FvcWrite (
536 FvDevice,
537 Offset,
538 &NumBytesWritten,
539 StartPos
540 );
541 if (EFI_ERROR (Status)) {
542 FreeFileList (&NewFileList);
543 return Status;
544 }
545
546 //
547 // Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID
548 //
549 SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
550
551 StartPos = PadFileEntry->FfsHeader;
552
553 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
554 StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
555
556 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
557 Status = FvcWrite (
558 FvDevice,
559 StateOffset,
560 &NumBytesWritten,
561 &OldPadFileHeader->State
562 );
563 if (EFI_ERROR (Status)) {
564 SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
565 return Status;
566 }
567
568 //
569 // If all successfully, update FFS_FILE_LIST
570 //
571
572 //
573 // Delete old pad file entry
574 //
575 FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
576 NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
577
578 FreePool (PadFileEntry);
579
580 FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
581 (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
582 NextFfsEntry->Link.BackLink = NewFileList.BackLink;
583 (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
584
585 return EFI_SUCCESS;
586 }
587
588 /**
589 Free all FfsBuffer.
590
591 @param NumOfFiles Number of FfsBuffer.
592 @param FfsBuffer An array of pointer to an FFS File Buffer
593
594 **/
595 VOID
596 FreeFfsBuffer (
597 IN UINTN NumOfFiles,
598 IN UINT8 **FfsBuffer
599 )
600 {
601 UINTN Index;
602 for (Index = 0; Index < NumOfFiles; Index++) {
603 if (FfsBuffer[Index] != NULL) {
604 FreePool (FfsBuffer[Index]);
605 }
606 }
607 }
608
609 /**
610 Create multiple files within a PAD File area.
611
612 @param FvDevice Firmware Volume Device.
613 @param PadFileEntry The pad file entry to be written in.
614 @param NumOfFiles Total File number to be written.
615 @param BufferSize The array of buffer size of each FfsBuffer.
616 @param ActualFileSize The array of actual file size.
617 @param PadSize The array of leading pad file size for each FFS File
618 @param FfsBuffer The array of Ffs Buffer pointer.
619 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
620 used to get name, attributes, type, etc.
621
622 @retval EFI_SUCCESS Add the input multiple files into PAD file area.
623 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
624 @retval other error Files can't be added into PAD file area.
625
626 **/
627 EFI_STATUS
628 FvCreateMultipleFilesInsidePadFile (
629 IN FV_DEVICE *FvDevice,
630 IN FFS_FILE_LIST_ENTRY *PadFileEntry,
631 IN UINTN NumOfFiles,
632 IN UINTN *BufferSize,
633 IN UINTN *ActualFileSize,
634 IN UINTN *PadSize,
635 IN UINT8 **FfsBuffer,
636 IN EFI_FV_WRITE_FILE_DATA *FileData
637 )
638 {
639 EFI_STATUS Status;
640 EFI_FFS_FILE_HEADER *OldPadFileHeader;
641 UINTN Index;
642 EFI_FFS_FILE_HEADER *PadFileHeader;
643 EFI_FFS_FILE_HEADER *FileHeader;
644 EFI_FFS_FILE_HEADER *TailPadFileHeader;
645 UINTN TotalSize;
646 UINTN PadAreaLength;
647 LIST_ENTRY NewFileList;
648 FFS_FILE_LIST_ENTRY *NewFileListEntry;
649 UINTN Offset;
650 UINTN NumBytesWritten;
651 UINT8 *StartPos;
652 FFS_FILE_LIST_ENTRY *FfsEntry;
653 FFS_FILE_LIST_ENTRY *NextFfsEntry;
654
655 InitializeListHead (&NewFileList);
656
657 NewFileListEntry = NULL;
658
659 OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
660 PadAreaLength = (*(UINT32 *) OldPadFileHeader->Size & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
661
662 Status = UpdateHeaderBit (
663 FvDevice,
664 OldPadFileHeader,
665 EFI_FILE_MARKED_FOR_UPDATE
666 );
667 if (EFI_ERROR (Status)) {
668 return Status;
669 }
670 //
671 // Update PAD area
672 //
673 TotalSize = 0;
674 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
675 FileHeader = PadFileHeader;
676
677 for (Index = 0; Index < NumOfFiles; Index++) {
678 if (PadSize[Index] != 0) {
679 FvFillPadFile (PadFileHeader, PadSize[Index]);
680 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
681 if (NewFileListEntry == NULL) {
682 return EFI_OUT_OF_RESOURCES;
683 }
684
685 NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
686 InsertTailList (&NewFileList, &NewFileListEntry->Link);
687 }
688
689 FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]);
690 Status = FvFillFfsFile (
691 FileHeader,
692 FfsBuffer[Index],
693 BufferSize[Index],
694 ActualFileSize[Index],
695 FileData[Index].NameGuid,
696 FileData[Index].Type,
697 FileData[Index].FileAttributes
698 );
699 if (EFI_ERROR (Status)) {
700 return Status;
701 }
702
703 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
704 if (NewFileListEntry == NULL) {
705 FreeFileList (&NewFileList);
706 return EFI_OUT_OF_RESOURCES;
707 }
708
709 NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
710 InsertTailList (&NewFileList, &NewFileListEntry->Link);
711
712 PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]);
713 TotalSize += PadSize[Index];
714 TotalSize += BufferSize[Index];
715 }
716
717 FvDevice->CurrentFfsFile = NewFileListEntry;
718 //
719 // Maybe we need a tail pad file
720 //
721 if (PadAreaLength > TotalSize) {
722 if ((PadAreaLength - TotalSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
723 //
724 // we can insert another PAD file
725 //
726 TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[NumOfFiles - 1]);
727 FvFillPadFile (TailPadFileHeader, PadAreaLength - TotalSize);
728
729 NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
730 if (NewFileListEntry == NULL) {
731 FreeFileList (&NewFileList);
732 return EFI_OUT_OF_RESOURCES;
733 }
734
735 NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
736 InsertTailList (&NewFileList, &NewFileListEntry->Link);
737 } else {
738 //
739 // because left size cannot hold another PAD file header,
740 // adjust the writing file size (just in cache)
741 //
742 FvAdjustFfsFile (
743 FvDevice->ErasePolarity,
744 FileHeader,
745 PadAreaLength - TotalSize
746 );
747 }
748 }
749 //
750 // Start writing to FV
751 //
752 StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
753
754 Offset = (UINTN) (StartPos - FvDevice->CachedFv);
755
756 NumBytesWritten = PadAreaLength;
757 Status = FvcWrite (
758 FvDevice,
759 Offset,
760 &NumBytesWritten,
761 StartPos
762 );
763 if (EFI_ERROR (Status)) {
764 FreeFileList (&NewFileList);
765 return Status;
766 }
767
768 Status = UpdateHeaderBit (
769 FvDevice,
770 OldPadFileHeader,
771 EFI_FILE_HEADER_INVALID
772 );
773 if (EFI_ERROR (Status)) {
774 FreeFileList (&NewFileList);
775 return Status;
776 }
777
778 //
779 // Update File List Link
780 //
781
782 //
783 // First delete old pad file entry
784 //
785 FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
786 NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
787
788 FreePool (PadFileEntry);
789
790 FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
791 (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
792 NextFfsEntry->Link.BackLink = NewFileList.BackLink;
793 (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
794
795 return EFI_SUCCESS;
796 }
797
798 /**
799 Write multiple files into FV in reliable method.
800
801 @param FvDevice Firmware Volume Device.
802 @param NumOfFiles Total File number to be written.
803 @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
804 used to get name, attributes, type, etc
805 @param FileOperation The array of operation for each file.
806
807 @retval EFI_SUCCESS Files are added into FV.
808 @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.
809 @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.
810 @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.
811
812 **/
813 EFI_STATUS
814 FvCreateMultipleFiles (
815 IN FV_DEVICE *FvDevice,
816 IN UINTN NumOfFiles,
817 IN EFI_FV_WRITE_FILE_DATA *FileData,
818 IN BOOLEAN *FileOperation
819 )
820 {
821 EFI_STATUS Status;
822 UINT8 *FfsBuffer[MAX_FILES];
823 UINTN Index1;
824 UINTN Index2;
825 UINTN BufferSize[MAX_FILES];
826 UINTN ActualFileSize[MAX_FILES];
827 UINTN RequiredAlignment[MAX_FILES];
828 UINTN PadSize[MAX_FILES];
829 FFS_FILE_LIST_ENTRY *PadFileEntry;
830 UINTN TotalSizeNeeded;
831 FREE_SPACE_ENTRY *FreeSpaceEntry;
832 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
833 UINTN Key;
834 EFI_GUID FileNameGuid;
835 EFI_FV_FILETYPE OldFileType;
836 EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
837 UINTN OldFileSize;
838 FFS_FILE_LIST_ENTRY *OldFfsFileEntry[MAX_FILES];
839 EFI_FFS_FILE_HEADER *OldFileHeader[MAX_FILES];
840 BOOLEAN IsCreateFile;
841
842 //
843 // To use this function, we must ensure that the NumOfFiles is great
844 // than 1
845 //
846 if (NumOfFiles <= 1) {
847 return EFI_INVALID_PARAMETER;
848 }
849
850 if (NumOfFiles > MAX_FILES) {
851 return EFI_UNSUPPORTED;
852 }
853
854 Fv = &FvDevice->Fv;
855
856 SetMem (FfsBuffer, NumOfFiles, 0);
857 SetMem (RequiredAlignment, NumOfFiles, 8);
858 SetMem (PadSize, NumOfFiles, 0);
859 ZeroMem (OldFfsFileEntry, sizeof (OldFfsFileEntry));
860 ZeroMem (OldFileHeader, sizeof (OldFileHeader));
861
862 //
863 // Adjust file size
864 //
865 for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
866 ActualFileSize[Index1] = FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER);
867 BufferSize[Index1] = ActualFileSize[Index1];
868
869 if (BufferSize[Index1] == sizeof (EFI_FFS_FILE_HEADER)) {
870 //
871 // clear file attributes, zero-length file does not have any attributes
872 //
873 FileData[Index1].FileAttributes = 0;
874 }
875
876 while ((BufferSize[Index1] & 0x07) != 0) {
877 BufferSize[Index1]++;
878 }
879
880 FfsBuffer[Index1] = AllocateZeroPool (BufferSize[Index1]);
881
882 //
883 // Copy File Data into FileBuffer
884 //
885 CopyMem (
886 FfsBuffer[Index1] + sizeof (EFI_FFS_FILE_HEADER),
887 FileData[Index1].Buffer,
888 FileData[Index1].BufferSize
889 );
890
891 if (FvDevice->ErasePolarity == 1) {
892 for (Index2 = 0; Index2 < sizeof (EFI_FFS_FILE_HEADER); Index2++) {
893 FfsBuffer[Index1][Index2] = (UINT8)~FfsBuffer[Index1][Index2];
894 }
895 }
896
897 if ((FileData[Index1].FileAttributes & FFS_ATTRIB_DATA_ALIGNMENT) != 0) {
898 RequiredAlignment[Index1] = GetRequiredAlignment (FileData[Index1].FileAttributes);
899 }
900 //
901 // If update file, mark the original file header to
902 // EFI_FILE_MARKED_FOR_UPDATE
903 //
904 IsCreateFile = FileOperation[Index1];
905 if (!IsCreateFile) {
906
907 Key = 0;
908 do {
909 OldFileType = 0;
910 Status = Fv->GetNextFile (
911 Fv,
912 &Key,
913 &OldFileType,
914 &FileNameGuid,
915 &OldFileAttributes,
916 &OldFileSize
917 );
918 if (EFI_ERROR (Status)) {
919 FreeFfsBuffer (NumOfFiles, FfsBuffer);
920 return Status;
921 }
922 } while (!CompareGuid (&FileNameGuid, FileData[Index1].NameGuid));
923
924 //
925 // Get FfsFileEntry from the search key
926 //
927 OldFfsFileEntry[Index1] = (FFS_FILE_LIST_ENTRY *) Key;
928 OldFileHeader[Index1] = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry[Index1]->FfsHeader;
929 Status = UpdateHeaderBit (
930 FvDevice,
931 OldFileHeader[Index1],
932 EFI_FILE_MARKED_FOR_UPDATE
933 );
934 if (EFI_ERROR (Status)) {
935 FreeFfsBuffer (NumOfFiles, FfsBuffer);
936 return Status;
937 }
938 }
939 }
940 //
941 // First to search a suitable pad file that can hold so
942 // many files
943 //
944 Status = FvSearchSuitablePadFile (
945 FvDevice,
946 NumOfFiles,
947 BufferSize,
948 RequiredAlignment,
949 PadSize,
950 &TotalSizeNeeded,
951 &PadFileEntry
952 );
953
954 if (Status == EFI_NOT_FOUND) {
955 //
956 // Try to find a free space that can hold these files
957 // and create a suitable PAD file in this free space
958 //
959 Status = FvSearchSuitableFreeSpace (
960 FvDevice,
961 NumOfFiles,
962 BufferSize,
963 RequiredAlignment,
964 PadSize,
965 &TotalSizeNeeded,
966 &FreeSpaceEntry
967 );
968 if (EFI_ERROR (Status)) {
969 FreeFfsBuffer (NumOfFiles, FfsBuffer);
970 return EFI_OUT_OF_RESOURCES;
971 }
972 //
973 // Create a PAD file in that space
974 //
975 Status = FvCreatePadFileInFreeSpace (
976 FvDevice,
977 FreeSpaceEntry,
978 TotalSizeNeeded,
979 &PadFileEntry
980 );
981
982 if (EFI_ERROR (Status)) {
983 FreeFfsBuffer (NumOfFiles, FfsBuffer);
984 return Status;
985 }
986 }
987 //
988 // Create multiple files inside such a pad file
989 // to achieve lock-step update
990 //
991 Status = FvCreateMultipleFilesInsidePadFile (
992 FvDevice,
993 PadFileEntry,
994 NumOfFiles,
995 BufferSize,
996 ActualFileSize,
997 PadSize,
998 FfsBuffer,
999 FileData
1000 );
1001
1002 FreeFfsBuffer (NumOfFiles, FfsBuffer);
1003
1004 if (EFI_ERROR (Status)) {
1005 return Status;
1006 }
1007 //
1008 // Delete those updated files
1009 //
1010 for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
1011 IsCreateFile = FileOperation[Index1];
1012 if (!IsCreateFile && OldFfsFileEntry[Index1] != NULL) {
1013 (OldFfsFileEntry[Index1]->Link.BackLink)->ForwardLink = OldFfsFileEntry[Index1]->Link.ForwardLink;
1014 (OldFfsFileEntry[Index1]->Link.ForwardLink)->BackLink = OldFfsFileEntry[Index1]->Link.BackLink;
1015 FreePool (OldFfsFileEntry[Index1]);
1016 }
1017 }
1018 //
1019 // Set those files' state to EFI_FILE_DELETED
1020 //
1021 for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
1022 IsCreateFile = FileOperation[Index1];
1023 if (!IsCreateFile && OldFileHeader[Index1] != NULL) {
1024 Status = UpdateHeaderBit (FvDevice, OldFileHeader[Index1], EFI_FILE_DELETED);
1025 if (EFI_ERROR (Status)) {
1026 return Status;
1027 }
1028 }
1029 }
1030
1031 return EFI_SUCCESS;
1032 }