]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwVol.c
CommitLineData
c2df8e13 1/** @file\r
2\r
3 Firmware File System driver that produce full Firmware Volume2 protocol.\r
4 Layers on top of Firmware Block protocol to produce a file abstraction\r
5 of FV based files.\r
6\r
ece4c1de 7 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
c2df8e13 8\r
c0a00b14 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
c2df8e13 10\r
11**/\r
12\r
13#include "FwVolDriver.h"\r
14\r
15#define KEYSIZE sizeof (UINTN)\r
16\r
17/**\r
18 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
19 copy the real length volume header into it.\r
20\r
21 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to\r
22 read the volume header\r
23 @param FwVolHeader Pointer to pointer to allocated buffer in which\r
24 the volume header is returned.\r
25\r
26 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
27 @retval EFI_SUCCESS Successfully read volume header to the allocated\r
28 buffer.\r
29 @retval EFI_ACCESS_DENIED Read status of FV is not enabled.\r
4888d15e
SZ
30 @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or\r
31 the file system could not be understood.\r
c2df8e13 32**/\r
33EFI_STATUS\r
34GetFwVolHeader (\r
35 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
36 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
37 )\r
38{\r
39 EFI_STATUS Status;\r
40 EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
41 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
42 UINTN FvhLength;\r
43 EFI_PHYSICAL_ADDRESS BaseAddress;\r
44\r
45 //\r
46 // Determine the real length of FV header\r
47 //\r
48 Status = Fvb->GetAttributes (\r
49 Fvb,\r
50 &FvbAttributes\r
51 );\r
52 if (EFI_ERROR (Status)) {\r
53 return Status;\r
54 }\r
55\r
56 if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {\r
57 return EFI_ACCESS_DENIED;\r
58 }\r
59\r
60 //\r
61 // Just avoid compiling warning\r
62 //\r
63 BaseAddress = 0;\r
64 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
65\r
66 //\r
67 // memory-mapped FV and non memory-mapped has different ways to read\r
68 //\r
69 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
70 Status = Fvb->GetPhysicalAddress (\r
71 Fvb,\r
72 &BaseAddress\r
73 );\r
74 if (EFI_ERROR (Status)) {\r
75 return Status;\r
76 }\r
77 CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);\r
78 } else {\r
79 Status = Fvb->Read (\r
80 Fvb,\r
81 0,\r
82 0,\r
83 &FvhLength,\r
84 (UINT8 *) &TempFvh\r
85 );\r
86 }\r
87\r
4888d15e
SZ
88 //\r
89 // Validate FV Header signature, if not as expected, continue.\r
90 //\r
91 if (TempFvh.Signature != EFI_FVH_SIGNATURE) {\r
92 return EFI_INVALID_PARAMETER;\r
93 }\r
94\r
95 //\r
96 // Check to see that the file system is indeed formatted in a way we can\r
97 // understand it...\r
98 //\r
99 if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&\r
100 (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {\r
101 return EFI_INVALID_PARAMETER;\r
102 }\r
103\r
c2df8e13 104 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
105 if (*FwVolHeader == NULL) {\r
106 return EFI_OUT_OF_RESOURCES;\r
107 }\r
108 //\r
109 // Read the whole header\r
110 //\r
111 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
112 CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);\r
113 } else {\r
114 //\r
115 // Assumed the first block is bigger than the length of Fv headder\r
116 //\r
117 FvhLength = TempFvh.HeaderLength;\r
118 Status = Fvb->Read (\r
119 Fvb,\r
120 0,\r
121 0,\r
122 &FvhLength,\r
123 (UINT8 *) *FwVolHeader\r
124 );\r
125 //\r
126 // Check whether Read successes.\r
127 //\r
128 if (EFI_ERROR (Status)) {\r
129 FreePool (*FwVolHeader);\r
130 *FwVolHeader = NULL;\r
131 return Status;\r
132 }\r
133 }\r
134\r
135 return EFI_SUCCESS;\r
136}\r
137\r
138/**\r
139 Free FvDevice resource when error happens.\r
140\r
141 @param FvDevice Pointer to the FvDevice to be freed.\r
142**/\r
143VOID\r
144FreeFvDeviceResource (\r
145 IN FV_DEVICE *FvDevice\r
146 )\r
147{\r
148 LBA_ENTRY *LbaEntry;\r
149 FREE_SPACE_ENTRY *FreeSpaceEntry;\r
150 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
151 LIST_ENTRY *NextEntry;\r
152\r
153 //\r
154 // Free LAB Entry\r
155 //\r
156 LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;\r
157 while (&LbaEntry->Link != &FvDevice->LbaHeader) {\r
158 NextEntry = (&LbaEntry->Link)->ForwardLink;\r
159 FreePool (LbaEntry);\r
160 LbaEntry = (LBA_ENTRY *) NextEntry;\r
161 }\r
162 //\r
163 // Free File List Entry\r
164 //\r
165 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;\r
166 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
167 NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
168 FreePool (FfsFileEntry);\r
169 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
170 }\r
171 //\r
172 // Free Space Entry\r
173 //\r
174 FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;\r
175 while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {\r
176 NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;\r
177 FreePool (FreeSpaceEntry);\r
178 FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;\r
179 }\r
180 //\r
181 // Free the cache\r
182 //\r
183 FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);\r
184\r
185 return ;\r
186}\r
187\r
0c3a1db4
SZ
188/**\r
189\r
190 Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)\r
2331cab7 191 where it came from or propagated from PEI-phase.\r
0c3a1db4
SZ
192\r
193 @param FvDevice A pointer to the FvDevice.\r
194\r
195**/\r
196VOID\r
197FwVolInheritAuthenticationStatus (\r
198 IN FV_DEVICE *FvDevice\r
199 )\r
200{\r
2331cab7
SZ
201 EFI_STATUS Status;\r
202 EFI_FIRMWARE_VOLUME_HEADER *CachedFvHeader;\r
203 EFI_FIRMWARE_VOLUME_EXT_HEADER *CachedFvExtHeader;\r
204 EFI_FIRMWARE_VOLUME2_PROTOCOL *ParentFvProtocol;\r
205 UINTN Key;\r
206 EFI_GUID FileNameGuid;\r
207 EFI_FV_FILETYPE FileType;\r
208 EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
209 UINTN FileSize;\r
210 EFI_SECTION_TYPE SectionType;\r
211 UINT32 AuthenticationStatus;\r
212 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
213 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;\r
214 UINTN BufferSize;\r
215 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
216 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
217 EFI_PHYSICAL_ADDRESS BaseAddress;\r
218 EFI_PEI_HOB_POINTERS Fv3Hob;\r
0c3a1db4
SZ
219\r
220 if (FvDevice->Fv.ParentHandle != NULL) {\r
2331cab7
SZ
221 CachedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvDevice->CachedFv;\r
222\r
0c3a1db4 223 //\r
2331cab7 224 // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from\r
0c3a1db4
SZ
225 //\r
226 Status = gBS->HandleProtocol (FvDevice->Fv.ParentHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &ParentFvProtocol);\r
227 if (!EFI_ERROR (Status) && (ParentFvProtocol != NULL)) {\r
228 Key = 0;\r
229 do {\r
230 FileType = EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;\r
231 Status = ParentFvProtocol->GetNextFile (\r
232 ParentFvProtocol,\r
233 &Key,\r
234 &FileType,\r
235 &FileNameGuid,\r
236 &FileAttributes,\r
237 &FileSize\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
240 return;\r
241 }\r
242\r
243 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
244 FvHeader = NULL;\r
245 BufferSize = 0;\r
246 Status = ParentFvProtocol->ReadSection (\r
247 ParentFvProtocol,\r
248 &FileNameGuid,\r
249 SectionType,\r
250 0,\r
251 (VOID **) &FvHeader,\r
252 &BufferSize,\r
253 &AuthenticationStatus\r
254 );\r
255 if (!EFI_ERROR (Status)) {\r
256 if ((FvHeader->FvLength == CachedFvHeader->FvLength) &&\r
257 (FvHeader->ExtHeaderOffset == CachedFvHeader->ExtHeaderOffset)) {\r
2331cab7 258 if (FvHeader->ExtHeaderOffset != 0) {\r
0c3a1db4
SZ
259 //\r
260 // Both FVs contain extension header, then compare their FV Name GUID\r
261 //\r
262 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) FvHeader + FvHeader->ExtHeaderOffset);\r
263 CachedFvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) CachedFvHeader + CachedFvHeader->ExtHeaderOffset);\r
264 if (CompareGuid (&FvExtHeader->FvName, &CachedFvExtHeader->FvName)) {\r
265 //\r
266 // Found the FV image section where the firmware volume came from,\r
267 // and then inherit authentication status from it.\r
268 //\r
269 FvDevice->AuthenticationStatus = AuthenticationStatus;\r
270 FreePool ((VOID *) FvHeader);\r
271 return;\r
272 }\r
273 } else {\r
274 //\r
275 // Both FVs don't contain extension header, then compare their whole FV Image.\r
276 //\r
25fbcc0a 277 if (CompareMem ((VOID *) FvHeader, (VOID *) CachedFvHeader, (UINTN) FvHeader->FvLength) == 0) {\r
0c3a1db4
SZ
278 //\r
279 // Found the FV image section where the firmware volume came from\r
280 // and then inherit authentication status from it.\r
281 //\r
282 FvDevice->AuthenticationStatus = AuthenticationStatus;\r
283 FreePool ((VOID *) FvHeader);\r
284 return;\r
285 }\r
286 }\r
287 }\r
288 FreePool ((VOID *) FvHeader);\r
289 }\r
290 } while (TRUE);\r
291 }\r
2331cab7
SZ
292 } else {\r
293 Fvb = FvDevice->Fvb;\r
294\r
295 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
296 if (EFI_ERROR (Status)) {\r
297 return;\r
298 }\r
299\r
300 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
301 //\r
302 // Get volume base address\r
303 //\r
304 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);\r
305 if (EFI_ERROR (Status)) {\r
306 return;\r
307 }\r
308\r
309 //\r
310 // Get the authentication status propagated from PEI-phase to DXE.\r
311 //\r
312 Fv3Hob.Raw = GetHobList ();\r
313 while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {\r
314 if (Fv3Hob.FirmwareVolume3->BaseAddress == BaseAddress) {\r
315 FvDevice->AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;\r
316 return;\r
317 }\r
318 Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);\r
319 }\r
320 }\r
0c3a1db4
SZ
321 }\r
322}\r
323\r
c2df8e13 324/**\r
325 Check if an FV is consistent and allocate cache for it.\r
326\r
327 @param FvDevice A pointer to the FvDevice to be checked.\r
328\r
329 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
330 @retval EFI_VOLUME_CORRUPTED File system is corrupted.\r
331 @retval EFI_SUCCESS FV is consistent and cache is allocated.\r
332\r
333**/\r
334EFI_STATUS\r
335FvCheck (\r
336 IN FV_DEVICE *FvDevice\r
337 )\r
338{\r
339 EFI_STATUS Status;\r
340 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
341 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
342 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
343 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
f95f107c 344 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;\r
c2df8e13 345 UINT8 *FwCache;\r
346 LBA_ENTRY *LbaEntry;\r
347 FREE_SPACE_ENTRY *FreeSpaceEntry;\r
348 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
349 UINT8 *LbaStart;\r
350 UINTN Index;\r
351 EFI_LBA LbaIndex;\r
352 UINT8 *Ptr;\r
353 UINTN Size;\r
354 UINT8 *FreeStart;\r
355 UINTN FreeSize;\r
356 UINT8 ErasePolarity;\r
c2df8e13 357 EFI_FFS_FILE_STATE FileState;\r
358 UINT8 *TopFvAddress;\r
359 UINTN TestLength;\r
360 EFI_PHYSICAL_ADDRESS BaseAddress;\r
361\r
362 Fvb = FvDevice->Fvb;\r
363\r
364 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
365 if (EFI_ERROR (Status)) {\r
366 return Status;\r
367 }\r
368\r
369 InitializeListHead (&FvDevice->LbaHeader);\r
370 InitializeListHead (&FvDevice->FreeSpaceHeader);\r
371 InitializeListHead (&FvDevice->FfsFileListHeader);\r
372\r
373 FwVolHeader = NULL;\r
374 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
375 if (EFI_ERROR (Status)) {\r
376 return Status;\r
377 }\r
378 ASSERT (FwVolHeader != NULL);\r
379\r
23491d5c
SZ
380 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
381\r
c2df8e13 382 //\r
383 // Double Check firmware volume header here\r
384 //\r
385 if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
386 FreePool (FwVolHeader);\r
387 return EFI_VOLUME_CORRUPTED;\r
388 }\r
389\r
390 BlockMap = FwVolHeader->BlockMap;\r
391\r
392 //\r
393 // FwVolHeader->FvLength is the whole FV length including FV header\r
394 //\r
395 FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);\r
396 if (FwCache == NULL) {\r
397 FreePool (FwVolHeader);\r
398 return EFI_OUT_OF_RESOURCES;\r
399 }\r
400\r
401 FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;\r
402\r
403 //\r
404 // Copy to memory\r
405 //\r
406 LbaStart = FwCache;\r
407 LbaIndex = 0;\r
408 Ptr = NULL;\r
409\r
410 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
411 //\r
412 // Get volume base address\r
413 //\r
414 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);\r
415 if (EFI_ERROR (Status)) {\r
416 FreePool (FwVolHeader);\r
417 return Status;\r
418 }\r
419\r
420 Ptr = (UINT8 *) ((UINTN) BaseAddress);\r
421\r
422 DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));\r
423 }\r
424 //\r
425 // Copy whole FV into the memory\r
426 //\r
427 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
428\r
429 for (Index = 0; Index < BlockMap->NumBlocks; Index++) {\r
430 LbaEntry = AllocatePool (sizeof (LBA_ENTRY));\r
431 if (LbaEntry == NULL) {\r
432 FreePool (FwVolHeader);\r
433 FreeFvDeviceResource (FvDevice);\r
434 return EFI_OUT_OF_RESOURCES;\r
435 }\r
436\r
437 LbaEntry->LbaIndex = LbaIndex;\r
438 LbaEntry->StartingAddress = LbaStart;\r
439 LbaEntry->BlockLength = BlockMap->Length;\r
440\r
441 //\r
442 // Copy each LBA into memory\r
443 //\r
444 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
445\r
446 CopyMem (LbaStart, Ptr, BlockMap->Length);\r
447 Ptr += BlockMap->Length;\r
448\r
449 } else {\r
450\r
451 Size = BlockMap->Length;\r
452 Status = Fvb->Read (\r
453 Fvb,\r
454 LbaIndex,\r
455 0,\r
456 &Size,\r
457 LbaStart\r
458 );\r
459 //\r
460 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
461 //\r
462 if (EFI_ERROR (Status)) {\r
463 FreePool (FwVolHeader);\r
464 FreeFvDeviceResource (FvDevice);\r
465 return Status;\r
466 }\r
467\r
468 }\r
469\r
470 LbaIndex++;\r
471 LbaStart += BlockMap->Length;\r
472\r
473 InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);\r
474 }\r
475\r
476 BlockMap++;\r
477 }\r
478\r
479 FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;\r
480\r
481 //\r
482 // it is not used any more, so free FwVolHeader\r
483 //\r
484 FreePool (FwVolHeader);\r
485\r
486 //\r
487 // Scan to check the free space & File list\r
488 //\r
489 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
490 ErasePolarity = 1;\r
491 } else {\r
492 ErasePolarity = 0;\r
493 }\r
494\r
495 FvDevice->ErasePolarity = ErasePolarity;\r
496\r
497 //\r
498 // go through the whole FV cache, check the consistence of the FV\r
499 //\r
f95f107c
SZ
500 if (FvDevice->FwVolHeader->ExtHeaderOffset != 0) {\r
501 //\r
502 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.\r
503 //\r
504 FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->ExtHeaderOffset);\r
505 Ptr = (UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize;\r
f95f107c
SZ
506 } else {\r
507 Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);\r
508 }\r
ece4c1de 509 Ptr = (UINT8 *) ALIGN_POINTER (Ptr, 8);\r
f95f107c 510 TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength);\r
c2df8e13 511\r
512 //\r
513 // Build FFS list & Free Space List here\r
514 //\r
f95f107c
SZ
515 while (Ptr < TopFvAddress) {\r
516 TestLength = TopFvAddress - Ptr;\r
c2df8e13 517\r
518 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
519 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
520 }\r
521\r
522 if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {\r
523 //\r
524 // We found free space\r
525 //\r
526 FreeStart = Ptr;\r
527 FreeSize = 0;\r
528\r
529 do {\r
f95f107c 530 TestLength = TopFvAddress - Ptr;\r
c2df8e13 531\r
532 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
533 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
534 }\r
535\r
536 if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {\r
537 break;\r
538 }\r
539\r
540 FreeSize += TestLength;\r
541 Ptr += TestLength;\r
f95f107c 542 } while (Ptr < TopFvAddress);\r
c2df8e13 543\r
544 FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));\r
545 if (FreeSpaceEntry == NULL) {\r
546 FreeFvDeviceResource (FvDevice);\r
547 return EFI_OUT_OF_RESOURCES;\r
548 }\r
549 //\r
550 // Create a Free space entry\r
551 //\r
552 FreeSpaceEntry->StartingAddress = FreeStart;\r
553 FreeSpaceEntry->Length = FreeSize;\r
554 InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);\r
555 continue;\r
556 }\r
557 //\r
70d3fe9d 558 // double check boundary\r
c2df8e13 559 //\r
560 if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {\r
561 break;\r
562 }\r
563\r
564 if (!IsValidFFSHeader (\r
565 FvDevice->ErasePolarity,\r
566 (EFI_FFS_FILE_HEADER *) Ptr\r
567 )) {\r
568 FileState = GetFileState (\r
569 FvDevice->ErasePolarity,\r
570 (EFI_FFS_FILE_HEADER *) Ptr\r
571 );\r
572 if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
23491d5c
SZ
573 if (IS_FFS_FILE2 (Ptr)) {\r
574 if (!FvDevice->IsFfs3Fv) {\r
575 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));\r
576 }\r
577 Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2);\r
578 } else {\r
579 Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER);\r
580 }\r
c2df8e13 581\r
582 continue;\r
583\r
584 } else {\r
585 //\r
586 // File system is corrputed, return\r
587 //\r
588 FreeFvDeviceResource (FvDevice);\r
589 return EFI_VOLUME_CORRUPTED;\r
590 }\r
591 }\r
592\r
23491d5c
SZ
593 if (IS_FFS_FILE2 (Ptr)) {\r
594 ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF);\r
595 if (!FvDevice->IsFfs3Fv) {\r
596 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));\r
597 Ptr = Ptr + FFS_FILE2_SIZE (Ptr);\r
598 //\r
70d3fe9d 599 // Adjust Ptr to the next 8-byte aligned boundary.\r
23491d5c
SZ
600 //\r
601 while (((UINTN) Ptr & 0x07) != 0) {\r
602 Ptr++;\r
603 }\r
604 continue;\r
605 }\r
606 }\r
607\r
c2df8e13 608 if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {\r
c2df8e13 609 FileState = GetFileState (\r
610 FvDevice->ErasePolarity,\r
611 (EFI_FFS_FILE_HEADER *) Ptr\r
612 );\r
613\r
614 //\r
615 // check for non-deleted file\r
616 //\r
617 if (FileState != EFI_FILE_DELETED) {\r
618 //\r
619 // Create a FFS list entry for each non-deleted file\r
620 //\r
621 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
622 if (FfsFileEntry == NULL) {\r
623 FreeFvDeviceResource (FvDevice);\r
624 return EFI_OUT_OF_RESOURCES;\r
625 }\r
626\r
627 FfsFileEntry->FfsHeader = Ptr;\r
628 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
629 }\r
630\r
23491d5c
SZ
631 if (IS_FFS_FILE2 (Ptr)) {\r
632 Ptr = Ptr + FFS_FILE2_SIZE (Ptr);\r
633 } else {\r
634 Ptr = Ptr + FFS_FILE_SIZE (Ptr);\r
635 }\r
c2df8e13 636\r
637 //\r
70d3fe9d 638 // Adjust Ptr to the next 8-byte aligned boundary.\r
c2df8e13 639 //\r
640 while (((UINTN) Ptr & 0x07) != 0) {\r
641 Ptr++;\r
642 }\r
643 } else {\r
644 //\r
645 // File system is corrupted, return\r
646 //\r
647 FreeFvDeviceResource (FvDevice);\r
648 return EFI_VOLUME_CORRUPTED;\r
649 }\r
650 }\r
651\r
652 FvDevice->CurrentFfsFile = NULL;\r
653\r
654 return EFI_SUCCESS;\r
655}\r
656\r
657/**\r
658 Entry point function does install/reinstall FV2 protocol with full functionality.\r
659\r
660 @param ImageHandle A handle for the image that is initializing this driver\r
661 @param SystemTable A pointer to the EFI system table\r
662\r
663 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.\r
664 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.\r
665**/\r
666EFI_STATUS\r
667EFIAPI\r
668FwVolDriverInit (\r
669 IN EFI_HANDLE ImageHandle,\r
670 IN EFI_SYSTEM_TABLE *SystemTable\r
671 )\r
672{\r
673 EFI_STATUS Status;\r
674 EFI_HANDLE *HandleBuffer;\r
675 UINTN HandleCount;\r
676 UINTN Index;\r
677 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
678 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
679 FV_DEVICE *FvDevice;\r
680 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
681 BOOLEAN Reinstall;\r
682 BOOLEAN InstallFlag;\r
683\r
684 DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));\r
685 InstallFlag = FALSE;\r
686 //\r
687 // Locate all handles of Fvb protocol\r
688 //\r
689 Status = gBS->LocateHandleBuffer (\r
690 ByProtocol,\r
691 &gEfiFirmwareVolumeBlockProtocolGuid,\r
692 NULL,\r
693 &HandleCount,\r
694 &HandleBuffer\r
695 );\r
696 if (EFI_ERROR (Status)) {\r
697 return EFI_NOT_FOUND;\r
698 }\r
23491d5c 699\r
c2df8e13 700 for (Index = 0; Index < HandleCount; Index += 1) {\r
701 Status = gBS->HandleProtocol (\r
702 HandleBuffer[Index],\r
703 &gEfiFirmwareVolumeBlockProtocolGuid,\r
704 (VOID **) &Fvb\r
705 );\r
706 if (EFI_ERROR (Status)) {\r
707 continue;\r
708 }\r
709\r
710 FwVolHeader = NULL;\r
711 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
712 if (EFI_ERROR (Status)) {\r
713 continue;\r
714 }\r
715 ASSERT (FwVolHeader != NULL);\r
c2df8e13 716 FreePool (FwVolHeader);\r
717\r
718 Reinstall = FALSE;\r
719 //\r
720 // Check if there is an FV protocol already installed in that handle\r
721 //\r
722 Status = gBS->HandleProtocol (\r
723 HandleBuffer[Index],\r
724 &gEfiFirmwareVolume2ProtocolGuid,\r
725 (VOID **) &Fv\r
726 );\r
727 if (!EFI_ERROR (Status)) {\r
728 Reinstall = TRUE;\r
729 }\r
730 //\r
731 // FwVol protocol on the handle so create a new one\r
732 //\r
733 FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));\r
734 if (FvDevice == NULL) {\r
735 goto Done;\r
736 }\r
737\r
738 FvDevice->Signature = FV_DEVICE_SIGNATURE;\r
739 FvDevice->Fvb = Fvb;\r
740\r
741 //\r
742 // Firmware Volume Protocol interface\r
743 //\r
744 FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;\r
745 FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;\r
746 FvDevice->Fv.ReadFile = FvReadFile;\r
747 FvDevice->Fv.ReadSection = FvReadFileSection;\r
748 FvDevice->Fv.WriteFile = FvWriteFile;\r
749 FvDevice->Fv.GetNextFile = FvGetNextFile;\r
750 FvDevice->Fv.KeySize = KEYSIZE;\r
751 FvDevice->Fv.GetInfo = FvGetVolumeInfo;\r
752 FvDevice->Fv.SetInfo = FvSetVolumeInfo;\r
0c3a1db4 753 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
c2df8e13 754\r
755 Status = FvCheck (FvDevice);\r
756 if (EFI_ERROR (Status)) {\r
757 //\r
758 // The file system is not consistence\r
759 //\r
760 FreePool (FvDevice);\r
761 continue;\r
762 }\r
763\r
0c3a1db4
SZ
764 FwVolInheritAuthenticationStatus (FvDevice);\r
765\r
c2df8e13 766 if (Reinstall) {\r
767 //\r
768 // Reinstall an New FV protocol\r
769 //\r
770 // FvDevice = FV_DEVICE_FROM_THIS (Fv);\r
771 // FvDevice->Fvb = Fvb;\r
772 // FreeFvDeviceResource (FvDevice);\r
773 //\r
774 Status = gBS->ReinstallProtocolInterface (\r
775 HandleBuffer[Index],\r
776 &gEfiFirmwareVolume2ProtocolGuid,\r
777 Fv,\r
778 &FvDevice->Fv\r
779 );\r
780 if (!EFI_ERROR (Status)) {\r
781 InstallFlag = TRUE;\r
782 } else {\r
783 FreePool (FvDevice);\r
784 }\r
0a6f4824 785\r
c2df8e13 786 DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));\r
787 ASSERT_EFI_ERROR (Status);\r
788 } else {\r
789 //\r
790 // Install an New FV protocol\r
791 //\r
792 Status = gBS->InstallProtocolInterface (\r
793 &FvDevice->Handle,\r
794 &gEfiFirmwareVolume2ProtocolGuid,\r
795 EFI_NATIVE_INTERFACE,\r
796 &FvDevice->Fv\r
797 );\r
798 if (!EFI_ERROR (Status)) {\r
799 InstallFlag = TRUE;\r
800 } else {\r
801 FreePool (FvDevice);\r
802 }\r
0a6f4824 803\r
c2df8e13 804 DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));\r
805 ASSERT_EFI_ERROR (Status);\r
806 }\r
807 }\r
808\r
809Done:\r
810 //\r
811 // As long as one Fv protocol install/reinstall successfully,\r
812 // success should return to ensure this image will be not unloaded.\r
813 // Otherwise, new Fv protocols are corrupted by other loaded driver.\r
814 //\r
815 if (InstallFlag) {\r
816 return EFI_SUCCESS;\r
817 }\r
0a6f4824 818\r
c2df8e13 819 //\r
820 // No FV protocol install/reinstall successfully.\r
821 // EFI_NOT_FOUND should return to ensure this image will be unloaded.\r
822 //\r
823 return EFI_NOT_FOUND;\r
824}\r