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