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