]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
Add core FFS3 support, FwVolDxe and SectionExtraction.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / Ffs.c
CommitLineData
c2df8e13 1/** @file\r
2 FFS file access utilities.\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#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))\r
20\r
21/**\r
22 Set File State in the FfsHeader.\r
23\r
24 @param State File state to be set into FFS header.\r
25 @param FfsHeader Points to the FFS file header\r
26\r
27**/\r
28VOID\r
29SetFileState (\r
30 IN UINT8 State,\r
31 IN EFI_FFS_FILE_HEADER *FfsHeader\r
32 )\r
33{\r
34 //\r
35 // Set File State in the FfsHeader\r
36 //\r
37 FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);\r
38 return ;\r
39}\r
40\r
41/**\r
42 Get the FFS file state by checking the highest bit set in the header's state field.\r
43\r
44 @param ErasePolarity Erase polarity attribute of the firmware volume\r
45 @param FfsHeader Points to the FFS file header\r
46\r
47 @return FFS File state\r
48\r
49**/\r
50EFI_FFS_FILE_STATE\r
51GetFileState (\r
52 IN UINT8 ErasePolarity,\r
53 IN EFI_FFS_FILE_HEADER *FfsHeader\r
54 )\r
55{\r
56 EFI_FFS_FILE_STATE FileState;\r
57 UINT8 HighestBit;\r
58\r
59 FileState = FfsHeader->State;\r
60\r
61 if (ErasePolarity != 0) {\r
62 FileState = (EFI_FFS_FILE_STATE)~FileState;\r
63 }\r
64\r
65 HighestBit = 0x80;\r
66 while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {\r
67 HighestBit >>= 1;\r
68 }\r
69\r
70 return (EFI_FFS_FILE_STATE) HighestBit;\r
71}\r
72\r
73/**\r
74 Convert the Buffer Address to LBA Entry Address.\r
75\r
76 @param FvDevice Cached FvDevice\r
77 @param BufferAddress Address of Buffer\r
78 @param LbaListEntry Pointer to the got LBA entry that contains the address.\r
79\r
80 @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
81 @retval EFI_SUCCESS LBA entry is found for Buffer address.\r
82\r
83**/\r
84EFI_STATUS\r
85Buffer2LbaEntry (\r
86 IN FV_DEVICE *FvDevice,\r
87 IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
88 OUT LBA_ENTRY **LbaListEntry\r
89 )\r
90{\r
91 LBA_ENTRY *LbaEntry;\r
92 LIST_ENTRY *Link;\r
93\r
94 Link = FvDevice->LbaHeader.ForwardLink;\r
95 LbaEntry = (LBA_ENTRY *) Link;\r
96\r
97 //\r
98 // Locate LBA which contains the address\r
99 //\r
100 while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
101 if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {\r
102 break;\r
103 }\r
104\r
105 Link = LbaEntry->Link.ForwardLink;\r
106 LbaEntry = (LBA_ENTRY *) Link;\r
107 }\r
108\r
109 if (&LbaEntry->Link == &FvDevice->LbaHeader) {\r
110 return EFI_NOT_FOUND;\r
111 }\r
112\r
113 Link = LbaEntry->Link.BackLink;\r
114 LbaEntry = (LBA_ENTRY *) Link;\r
115\r
116 if (&LbaEntry->Link == &FvDevice->LbaHeader) {\r
117 return EFI_NOT_FOUND;\r
118 }\r
119\r
120 *LbaListEntry = LbaEntry;\r
121\r
122 return EFI_SUCCESS;\r
123}\r
124\r
125/**\r
126 Convert the Buffer Address to LBA Address & Offset.\r
127\r
128 @param FvDevice Cached FvDevice\r
129 @param BufferAddress Address of Buffer\r
130 @param Lba Pointer to the gob Lba value\r
131 @param Offset Pointer to the got Offset\r
132\r
133 @retval EFI_NOT_FOUND Buffer address is out of FvDevice.\r
134 @retval EFI_SUCCESS LBA and Offset is found for Buffer address.\r
135\r
136**/\r
137EFI_STATUS\r
138Buffer2Lba (\r
139 IN FV_DEVICE *FvDevice,\r
140 IN EFI_PHYSICAL_ADDRESS BufferAddress,\r
141 OUT EFI_LBA *Lba,\r
142 OUT UINTN *Offset\r
143 )\r
144{\r
145 LBA_ENTRY *LbaEntry;\r
146 EFI_STATUS Status;\r
147\r
148 LbaEntry = NULL;\r
149\r
150 Status = Buffer2LbaEntry (\r
151 FvDevice,\r
152 BufferAddress,\r
153 &LbaEntry\r
154 );\r
155 if (EFI_ERROR (Status)) {\r
156 return Status;\r
157 }\r
158\r
159 *Lba = LbaEntry->LbaIndex;\r
160 *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;\r
161\r
162 return EFI_SUCCESS;\r
163}\r
164\r
165/**\r
166 Check if a block of buffer is erased.\r
167\r
168 @param ErasePolarity Erase polarity attribute of the firmware volume\r
169 @param Buffer The buffer to be checked\r
170 @param BufferSize Size of the buffer in bytes\r
171\r
172 @retval TRUE The block of buffer is erased\r
173 @retval FALSE The block of buffer is not erased\r
174\r
175**/\r
176BOOLEAN\r
177IsBufferErased (\r
178 IN UINT8 ErasePolarity,\r
179 IN UINT8 *Buffer,\r
180 IN UINTN BufferSize\r
181 )\r
182{\r
183 UINTN Count;\r
184 UINT8 EraseByte;\r
185\r
186 if (ErasePolarity == 1) {\r
187 EraseByte = 0xFF;\r
188 } else {\r
189 EraseByte = 0;\r
190 }\r
191\r
192 for (Count = 0; Count < BufferSize; Count++) {\r
193 if (Buffer[Count] != EraseByte) {\r
194 return FALSE;\r
195 }\r
196 }\r
197\r
198 return TRUE;\r
199}\r
200\r
201/**\r
202 Verify checksum of the firmware volume header.\r
203\r
204 @param FvHeader Points to the firmware volume header to be checked\r
205\r
206 @retval TRUE Checksum verification passed\r
207 @retval FALSE Checksum verification failed\r
208\r
209**/\r
210BOOLEAN\r
211VerifyFvHeaderChecksum (\r
212 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader\r
213 )\r
214{\r
215 UINT16 Checksum;\r
216\r
217 Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);\r
218\r
219 if (Checksum == 0) {\r
220 return TRUE;\r
221 } else {\r
222 return FALSE;\r
223 }\r
224}\r
225\r
226/**\r
227 Verify checksum of the FFS file header.\r
228\r
229 @param FfsHeader Points to the FFS file header to be checked\r
230\r
231 @retval TRUE Checksum verification passed\r
232 @retval FALSE Checksum verification failed\r
233\r
234**/\r
235BOOLEAN\r
236VerifyHeaderChecksum (\r
237 IN EFI_FFS_FILE_HEADER *FfsHeader\r
238 )\r
239{\r
240 UINT8 HeaderChecksum;\r
241\r
23491d5c
SZ
242 if (IS_FFS_FILE2 (FfsHeader)) {\r
243 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));\r
244 } else {\r
245 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));\r
246 }\r
c2df8e13 247 HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);\r
248\r
249 if (HeaderChecksum == 0) {\r
250 return TRUE;\r
251 } else {\r
252 return FALSE;\r
253 }\r
254}\r
255\r
256/**\r
257 Verify checksum of the FFS file data.\r
258\r
259 @param FfsHeader Points to the FFS file header to be checked\r
260\r
261 @retval TRUE Checksum verification passed\r
262 @retval FALSE Checksum verification failed\r
263\r
264**/\r
265BOOLEAN\r
266VerifyFileChecksum (\r
267 IN EFI_FFS_FILE_HEADER *FfsHeader\r
268 )\r
269{\r
270 UINT8 FileChecksum;\r
271 EFI_FV_FILE_ATTRIBUTES Attributes;\r
c2df8e13 272\r
273 Attributes = FfsHeader->Attributes;\r
274\r
275 if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {\r
276\r
c2df8e13 277 //\r
278 // Check checksum of FFS data\r
279 //\r
23491d5c
SZ
280 if (IS_FFS_FILE2 (FfsHeader)) {\r
281 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));\r
282 } else {\r
283 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));\r
284 }\r
c2df8e13 285 FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);\r
286\r
287 if (FileChecksum == 0) {\r
288 return TRUE;\r
289 } else {\r
290 return FALSE;\r
291 }\r
292\r
293 } else {\r
294\r
295 if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {\r
296 return FALSE;\r
297 } else {\r
298 return TRUE;\r
299 }\r
300 }\r
301\r
302}\r
303\r
304/**\r
305 Check if it's a valid FFS file header.\r
306\r
307 @param ErasePolarity Erase polarity attribute of the firmware volume\r
308 @param FfsHeader Points to the FFS file header to be checked\r
309\r
310 @retval TRUE Valid FFS file header\r
311 @retval FALSE Invalid FFS file header\r
312\r
313**/\r
314BOOLEAN\r
315IsValidFFSHeader (\r
316 IN UINT8 ErasePolarity,\r
317 IN EFI_FFS_FILE_HEADER *FfsHeader\r
318 )\r
319{\r
320 EFI_FFS_FILE_STATE FileState;\r
321\r
322 //\r
323 // Check if it is a free space\r
324 //\r
325 if (IsBufferErased (\r
326 ErasePolarity,\r
327 (UINT8 *) FfsHeader,\r
328 sizeof (EFI_FFS_FILE_HEADER)\r
329 )) {\r
330 return FALSE;\r
331 }\r
332\r
333 FileState = GetFileState (ErasePolarity, FfsHeader);\r
334\r
335 switch (FileState) {\r
336 case EFI_FILE_HEADER_CONSTRUCTION:\r
337 //\r
338 // fall through\r
339 //\r
340 case EFI_FILE_HEADER_INVALID:\r
341 return FALSE;\r
342\r
343 case EFI_FILE_HEADER_VALID:\r
344 //\r
345 // fall through\r
346 //\r
347 case EFI_FILE_DATA_VALID:\r
348 //\r
349 // fall through\r
350 //\r
351 case EFI_FILE_MARKED_FOR_UPDATE:\r
352 //\r
353 // fall through\r
354 //\r
355 case EFI_FILE_DELETED:\r
356 //\r
357 // Here we need to verify header checksum\r
358 //\r
359 if (!VerifyHeaderChecksum (FfsHeader)) {\r
360 return FALSE;\r
361 }\r
362 break;\r
363\r
364 default:\r
365 //\r
366 // return\r
367 //\r
368 return FALSE;\r
369 }\r
370\r
371 return TRUE;\r
372}\r
373\r
374/**\r
375 Get next possible of Firmware File System Header.\r
376\r
377 @param ErasePolarity Erase polarity attribute of the firmware volume\r
378 @param FfsHeader Points to the FFS file header to be skipped.\r
379\r
380 @return Pointer to next FFS header.\r
381\r
382**/\r
383EFI_PHYSICAL_ADDRESS\r
384GetNextPossibleFileHeader (\r
385 IN UINT8 ErasePolarity,\r
386 IN EFI_FFS_FILE_HEADER *FfsHeader\r
387 )\r
388{\r
389 UINT32 FileLength;\r
390 UINT32 SkipLength;\r
391\r
392 if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {\r
393 //\r
394 // Skip this header\r
395 //\r
23491d5c
SZ
396 if (IS_FFS_FILE2 (FfsHeader)) {\r
397 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2);\r
398 } else {\r
399 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);\r
400 }\r
c2df8e13 401 }\r
402\r
23491d5c
SZ
403 if (IS_FFS_FILE2 (FfsHeader)) {\r
404 FileLength = FFS_FILE2_SIZE (FfsHeader);\r
405 } else {\r
406 FileLength = FFS_FILE_SIZE (FfsHeader);\r
407 }\r
c2df8e13 408\r
409 //\r
410 // Since FileLength is not multiple of 8, we need skip some bytes\r
411 // to get next possible header\r
412 //\r
413 SkipLength = FileLength;\r
414 while ((SkipLength & 0x07) != 0) {\r
415 SkipLength++;\r
416 }\r
417\r
418 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;\r
419}\r
420\r
421/**\r
422 Search FFS file with the same FFS name in FV Cache.\r
423\r
424 @param FvDevice Cached FV image.\r
425 @param FfsHeader Points to the FFS file header to be skipped.\r
426 @param StateBit FFS file state bit to be checked.\r
427\r
428 @return Pointer to next found FFS header. NULL will return if no found.\r
429\r
430**/\r
431EFI_FFS_FILE_HEADER *\r
432DuplicateFileExist (\r
433 IN FV_DEVICE *FvDevice,\r
434 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
435 IN EFI_FFS_FILE_STATE StateBit\r
436 )\r
437{\r
438 UINT8 *Ptr;\r
439 EFI_FFS_FILE_HEADER *NextFfsFile;\r
440\r
441 //\r
442 // Search duplicate file, not from the beginning of FV,\r
443 // just search the next ocurrence of this file\r
444 //\r
445 NextFfsFile = FfsHeader;\r
446\r
447 do {\r
448 Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (\r
449 GetNextPossibleFileHeader (FvDevice->ErasePolarity,\r
450 NextFfsFile)\r
451 );\r
452 NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;\r
453\r
454 if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <\r
455 sizeof (EFI_FFS_FILE_HEADER)\r
456 ) {\r
457 break;\r
458 }\r
459\r
460 if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {\r
461 continue;\r
462 }\r
463\r
464 if (!VerifyFileChecksum (NextFfsFile)) {\r
465 continue;\r
466 }\r
467\r
468 if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {\r
469 if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {\r
470 return NextFfsFile;\r
471 }\r
472 }\r
473 } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);\r
474\r
475 return NULL;\r
476}\r
477\r
478/**\r
479 Change FFS file header state and write to FV.\r
480\r
481 @param FvDevice Cached FV image.\r
482 @param FfsHeader Points to the FFS file header to be updated.\r
483 @param State FFS file state to be set.\r
484\r
485 @retval EFI_SUCCESS File state is writen into FV.\r
486 @retval others File state can't be writen into FV.\r
487\r
488**/\r
489EFI_STATUS\r
490UpdateHeaderBit (\r
491 IN FV_DEVICE *FvDevice,\r
492 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
493 IN EFI_FFS_FILE_STATE State\r
494 )\r
495{\r
496 EFI_STATUS Status;\r
497 EFI_LBA Lba;\r
498 UINTN Offset;\r
499 UINTN NumBytesWritten;\r
500\r
501 Lba = 0;\r
502 Offset = 0;\r
503\r
504 SetFileState (State, FfsHeader);\r
505\r
506 Buffer2Lba (\r
507 FvDevice,\r
508 (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),\r
509 &Lba,\r
510 &Offset\r
511 );\r
512 //\r
513 // Write the state byte into FV\r
514 //\r
515 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);\r
516 Status = FvDevice->Fvb->Write (\r
517 FvDevice->Fvb,\r
518 Lba,\r
519 Offset,\r
520 &NumBytesWritten,\r
521 &FfsHeader->State\r
522 );\r
523 return Status;\r
524}\r
525\r
526/**\r
527 Check if it's a valid FFS file.\r
528 Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.\r
529\r
530 @param FvDevice Cached FV image.\r
531 @param FfsHeader Points to the FFS file to be checked\r
532\r
533 @retval TRUE Valid FFS file\r
534 @retval FALSE Invalid FFS file\r
535\r
536**/\r
537BOOLEAN\r
538IsValidFFSFile (\r
539 IN FV_DEVICE *FvDevice,\r
540 IN EFI_FFS_FILE_HEADER *FfsHeader\r
541 )\r
542{\r
543 EFI_FFS_FILE_STATE FileState;\r
544 UINT8 ErasePolarity;\r
545\r
546 ErasePolarity = FvDevice->ErasePolarity;\r
547\r
548 FileState = GetFileState (ErasePolarity, FfsHeader);\r
549\r
550 switch (FileState) {\r
551 case EFI_FILE_DATA_VALID:\r
552 if (!VerifyFileChecksum (FfsHeader)) {\r
553 return FALSE;\r
554 }\r
555\r
556 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
557 break;\r
558 }\r
559 //\r
560 // Check if there is another duplicated file with the EFI_FILE_DATA_VALID\r
561 //\r
562 if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {\r
563 return FALSE;\r
564 }\r
565\r
566 break;\r
567\r
568 case EFI_FILE_MARKED_FOR_UPDATE:\r
569 if (!VerifyFileChecksum (FfsHeader)) {\r
570 return FALSE;\r
571 }\r
572\r
573 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
574 //\r
575 // since its data area is not unperturbed, it cannot be reclaimed,\r
576 // marked it as deleted\r
577 //\r
578 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);\r
579 return TRUE;\r
580\r
581 } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {\r
582 //\r
583 // Here the found file is more recent than this file,\r
584 // mark it as deleted\r
585 //\r
586 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);\r
587 return TRUE;\r
588\r
589 } else {\r
590 return TRUE;\r
591 }\r
592\r
593 break;\r
594\r
595 case EFI_FILE_DELETED:\r
596 if (!VerifyFileChecksum (FfsHeader)) {\r
597 return FALSE;\r
598 }\r
599\r
600 break;\r
601\r
602 default:\r
603 return FALSE;\r
604 }\r
605\r
606 return TRUE;\r
607}\r
608\r