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