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