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