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