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