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