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