1 /** @file
2   Firmware File System driver that produce Firmware Volume protocol.
3   Layers on top of Firmware Block protocol to produce a file abstraction
4   of FV based files.
5 
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "DxeMain.h"
18 #include "FwVolDriver.h"
19 
20 
21 //
22 // Protocol notify related globals
23 //
24 VOID          *gEfiFwVolBlockNotifyReg;
25 EFI_EVENT     gEfiFwVolBlockEvent;
26 
27 FV_DEVICE mFvDevice = {
28   FV2_DEVICE_SIGNATURE,
29   NULL,
30   NULL,
31   {
32     FvGetVolumeAttributes,
33     FvSetVolumeAttributes,
34     FvReadFile,
35     FvReadFileSection,
36     FvWriteFile,
37     FvGetNextFile,
38 	sizeof (UINTN),
39     NULL,
40     FvGetVolumeInfo,
41     FvSetVolumeInfo
42   },
43   NULL,
44   NULL,
45   NULL,
46   NULL,
47   { NULL, NULL },
48   0,
49   0,
50   FALSE,
51   FALSE
52 };
53 
54 
55 //
56 // FFS helper functions
57 //
58 /**
59   Read data from Firmware Block by FVB protocol Read.
60   The data may cross the multi block ranges.
61 
62   @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
63   @param  StartLba              Pointer to StartLba.
64                                 On input, the start logical block index from which to read.
65                                 On output,the end logical block index after reading.
66   @param  Offset                Pointer to Offset
67                                 On input, offset into the block at which to begin reading.
68                                 On output, offset into the end block after reading.
69   @param  DataSize              Size of data to be read.
70   @param  Data                  Pointer to Buffer that the data will be read into.
71 
72   @retval EFI_SUCCESS           Successfully read data from firmware block.
73   @retval others
74 **/
75 EFI_STATUS
ReadFvbData(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb,IN OUT EFI_LBA * StartLba,IN OUT UINTN * Offset,IN UINTN DataSize,OUT UINT8 * Data)76 ReadFvbData (
77   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *Fvb,
78   IN OUT EFI_LBA                                *StartLba,
79   IN OUT UINTN                                  *Offset,
80   IN     UINTN                                  DataSize,
81   OUT    UINT8                                  *Data
82   )
83 {
84   UINTN                       BlockSize;
85   UINTN                       NumberOfBlocks;
86   UINTN                       BlockIndex;
87   UINTN                       ReadDataSize;
88   EFI_STATUS                  Status;
89 
90   //
91   // Try read data in current block
92   //
93   BlockIndex   = 0;
94   ReadDataSize = DataSize;
95   Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
96   if (Status == EFI_SUCCESS) {
97     *Offset  += DataSize;
98     return EFI_SUCCESS;
99   } else if (Status != EFI_BAD_BUFFER_SIZE) {
100     //
101     // other error will direct return
102     //
103     return Status;
104   }
105 
106   //
107   // Data crosses the blocks, read data from next block
108   //
109   DataSize -= ReadDataSize;
110   Data     += ReadDataSize;
111   *StartLba = *StartLba + 1;
112   while (DataSize > 0) {
113     Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
114     if (EFI_ERROR (Status)) {
115       return Status;
116     }
117 
118     //
119     // Read data from the crossing blocks
120     //
121     BlockIndex = 0;
122     while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
123       Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
124       if (EFI_ERROR (Status)) {
125         return Status;
126       }
127       Data += BlockSize;
128       DataSize -= BlockSize;
129       BlockIndex ++;
130     }
131 
132     //
133     // Data doesn't exceed the current block range.
134     //
135     if (DataSize < BlockSize) {
136       break;
137     }
138 
139     //
140     // Data must be got from the next block range.
141     //
142     *StartLba += NumberOfBlocks;
143   }
144 
145   //
146   // read the remaining data
147   //
148   if (DataSize > 0) {
149     Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
150     if (EFI_ERROR (Status)) {
151       return Status;
152     }
153   }
154 
155   //
156   // Update Lba and Offset used by the following read.
157   //
158   *StartLba += BlockIndex;
159   *Offset   = DataSize;
160 
161   return EFI_SUCCESS;
162 }
163 
164 /**
165   Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
166   copy the real length volume header into it.
167 
168   @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to
169                                 read the volume header
170   @param  FwVolHeader           Pointer to pointer to allocated buffer in which
171                                 the volume header is returned.
172 
173   @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
174   @retval EFI_SUCCESS           Successfully read volume header to the allocated
175                                 buffer.
176   @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
177                                 the file system could not be understood.
178 
179 **/
180 EFI_STATUS
GetFwVolHeader(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb,OUT EFI_FIRMWARE_VOLUME_HEADER ** FwVolHeader)181 GetFwVolHeader (
182   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *Fvb,
183   OUT    EFI_FIRMWARE_VOLUME_HEADER             **FwVolHeader
184   )
185 {
186   EFI_STATUS                  Status;
187   EFI_FIRMWARE_VOLUME_HEADER  TempFvh;
188   UINTN                       FvhLength;
189   EFI_LBA                     StartLba;
190   UINTN                       Offset;
191   UINT8                       *Buffer;
192 
193   //
194   // Read the standard FV header
195   //
196   StartLba = 0;
197   Offset   = 0;
198   FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
199   Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
200   if (EFI_ERROR (Status)) {
201     return Status;
202   }
203 
204   //
205   // Validate FV Header signature, if not as expected, continue.
206   //
207   if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
208     return EFI_INVALID_PARAMETER;
209   }
210 
211   //
212   // Check to see that the file system is indeed formatted in a way we can
213   // understand it...
214   //
215   if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
216       (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
217     return EFI_INVALID_PARAMETER;
218   }
219 
220   //
221   // Allocate a buffer for the caller
222   //
223   *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
224   if (*FwVolHeader == NULL) {
225     return EFI_OUT_OF_RESOURCES;
226   }
227 
228   //
229   // Copy the standard header into the buffer
230   //
231   CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
232 
233   //
234   // Read the rest of the header
235   //
236   FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
237   Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
238   Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
239   if (EFI_ERROR (Status)) {
240     //
241     // Read failed so free buffer
242     //
243     CoreFreePool (*FwVolHeader);
244   }
245 
246   return Status;
247 }
248 
249 
250 
251 /**
252   Free FvDevice resource when error happens
253 
254   @param  FvDevice              pointer to the FvDevice to be freed.
255 
256 **/
257 VOID
FreeFvDeviceResource(IN FV_DEVICE * FvDevice)258 FreeFvDeviceResource (
259   IN FV_DEVICE  *FvDevice
260   )
261 {
262   FFS_FILE_LIST_ENTRY         *FfsFileEntry;
263   LIST_ENTRY                  *NextEntry;
264 
265   //
266   // Free File List Entry
267   //
268   FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
269   while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
270     NextEntry = (&FfsFileEntry->Link)->ForwardLink;
271 
272     if (FfsFileEntry->StreamHandle != 0) {
273       //
274       // Close stream and free resources from SEP
275       //
276       CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
277     }
278 
279     if (FfsFileEntry->FileCached) {
280       //
281       // Free the cached file buffer.
282       //
283       CoreFreePool (FfsFileEntry->FfsHeader);
284     }
285 
286     CoreFreePool (FfsFileEntry);
287 
288     FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
289   }
290 
291   if (!FvDevice->IsMemoryMapped) {
292     //
293     // Free the cached FV buffer.
294     //
295     CoreFreePool (FvDevice->CachedFv);
296   }
297 
298   //
299   // Free Volume Header
300   //
301   CoreFreePool (FvDevice->FwVolHeader);
302 
303   return;
304 }
305 
306 
307 
308 /**
309   Check if an FV is consistent and allocate cache for it.
310 
311   @param  FvDevice              A pointer to the FvDevice to be checked.
312 
313   @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
314   @retval EFI_SUCCESS           FV is consistent and cache is allocated.
315   @retval EFI_VOLUME_CORRUPTED  File system is corrupted.
316 
317 **/
318 EFI_STATUS
FvCheck(IN OUT FV_DEVICE * FvDevice)319 FvCheck (
320   IN OUT FV_DEVICE  *FvDevice
321   )
322 {
323   EFI_STATUS                            Status;
324   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
325   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
326   EFI_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExtHeader;
327   EFI_FVB_ATTRIBUTES_2                  FvbAttributes;
328   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
329   FFS_FILE_LIST_ENTRY                   *FfsFileEntry;
330   EFI_FFS_FILE_HEADER                   *FfsHeader;
331   UINT8                                 *CacheLocation;
332   UINTN                                 LbaOffset;
333   UINTN                                 HeaderSize;
334   UINTN                                 Index;
335   EFI_LBA                               LbaIndex;
336   UINTN                                 Size;
337   EFI_FFS_FILE_STATE                    FileState;
338   UINT8                                 *TopFvAddress;
339   UINTN                                 TestLength;
340   EFI_PHYSICAL_ADDRESS                  PhysicalAddress;
341   BOOLEAN                               FileCached;
342   UINTN                                 WholeFileSize;
343   EFI_FFS_FILE_HEADER                   *CacheFfsHeader;
344 
345   FileCached = FALSE;
346   CacheFfsHeader = NULL;
347 
348   Fvb = FvDevice->Fvb;
349   FwVolHeader = FvDevice->FwVolHeader;
350 
351   Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
352   if (EFI_ERROR (Status)) {
353     return Status;
354   }
355 
356   //
357   // Size is the size of the FV minus the head. We have already allocated
358   // the header to check to make sure the volume is valid
359   //
360   Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);
361   if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
362     FvDevice->IsMemoryMapped = TRUE;
363 
364     Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
365     if (EFI_ERROR (Status)) {
366       return Status;
367     }
368 
369     //
370     // Don't cache memory mapped FV really.
371     //
372     FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength);
373   } else {
374     FvDevice->IsMemoryMapped = FALSE;
375     FvDevice->CachedFv = AllocatePool (Size);
376 
377     if (FvDevice->CachedFv == NULL) {
378       return EFI_OUT_OF_RESOURCES;
379     }
380   }
381 
382   //
383   // Remember a pointer to the end fo the CachedFv
384   //
385   FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
386 
387   if (!FvDevice->IsMemoryMapped) {
388     //
389     // Copy FV minus header into memory using the block map we have all ready
390     // read into memory.
391     //
392     BlockMap = FwVolHeader->BlockMap;
393     CacheLocation = FvDevice->CachedFv;
394     LbaIndex = 0;
395     LbaOffset = 0;
396     HeaderSize = FwVolHeader->HeaderLength;
397     while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
398       Index = 0;
399       Size  = BlockMap->Length;
400       if (HeaderSize > 0) {
401         //
402         // Skip header size
403         //
404         for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {
405           HeaderSize -= BlockMap->Length;
406           LbaIndex ++;
407         }
408 
409         //
410         // Check whether FvHeader is crossing the multi block range.
411         //
412         if (Index >= BlockMap->NumBlocks) {
413           BlockMap++;
414           continue;
415         } else if (HeaderSize > 0) {
416           LbaOffset = HeaderSize;
417           Size = BlockMap->Length - HeaderSize;
418           HeaderSize = 0;
419         }
420       }
421 
422       //
423       // read the FV data
424       //
425       for (; Index < BlockMap->NumBlocks; Index ++) {
426         Status = Fvb->Read (Fvb,
427                         LbaIndex,
428                         LbaOffset,
429                         &Size,
430                         CacheLocation
431                         );
432 
433         //
434         // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
435         //
436         if (EFI_ERROR (Status)) {
437           goto Done;
438         }
439 
440         LbaIndex++;
441         CacheLocation += Size;
442 
443         //
444         // After we skip Fv Header always read from start of block
445         //
446         LbaOffset = 0;
447         Size  = BlockMap->Length;
448       }
449 
450       BlockMap++;
451     }
452   }
453 
454   //
455   // Scan to check the free space & File list
456   //
457   if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
458     FvDevice->ErasePolarity = 1;
459   } else {
460     FvDevice->ErasePolarity = 0;
461   }
462 
463 
464   //
465   // go through the whole FV cache, check the consistence of the FV.
466   // Make a linked list of all the Ffs file headers
467   //
468   Status = EFI_SUCCESS;
469   InitializeListHead (&FvDevice->FfsFileListHeader);
470 
471   //
472   // Build FFS list
473   //
474   if (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 *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength));
479     FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
480     FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);
481   } else {
482     FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv);
483   }
484   TopFvAddress = FvDevice->EndOfCachedFv;
485   while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
486 
487     if (FileCached) {
488       CoreFreePool (CacheFfsHeader);
489       FileCached = FALSE;
490     }
491 
492     TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
493     if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
494       TestLength = sizeof (EFI_FFS_FILE_HEADER);
495     }
496 
497     if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
498       //
499       // We have found the free space so we are done!
500       //
501       goto Done;
502     }
503 
504     if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
505       if ((FileState == EFI_FILE_HEADER_INVALID) ||
506           (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
507         if (IS_FFS_FILE2 (FfsHeader)) {
508           if (!FvDevice->IsFfs3Fv) {
509             DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
510           }
511           FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
512         } else {
513           FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
514         }
515         continue;
516       } else {
517         //
518         // File system is corrputed
519         //
520         Status = EFI_VOLUME_CORRUPTED;
521         goto Done;
522       }
523     }
524 
525     CacheFfsHeader = FfsHeader;
526     if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
527       if (FvDevice->IsMemoryMapped) {
528         //
529         // Memory mapped FV has not been cached.
530         // Here is to cache FFS file to memory buffer for following checksum calculating.
531         // And then, the cached file buffer can be also used for FvReadFile.
532         //
533         WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);
534         CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
535         if (CacheFfsHeader == NULL) {
536           Status = EFI_OUT_OF_RESOURCES;
537           goto Done;
538         }
539         FileCached = TRUE;
540       }
541     }
542 
543     if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
544       //
545       // File system is corrupted
546       //
547       Status = EFI_VOLUME_CORRUPTED;
548       goto Done;
549     }
550 
551     if (IS_FFS_FILE2 (CacheFfsHeader)) {
552       ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
553       if (!FvDevice->IsFfs3Fv) {
554         DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
555         FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
556         //
557         // Adjust pointer to the next 8-byte aligned boundry.
558         //
559         FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);
560         continue;
561       }
562     }
563 
564     FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
565 
566     //
567     // check for non-deleted file
568     //
569     if (FileState != EFI_FILE_DELETED) {
570       //
571       // Create a FFS list entry for each non-deleted file
572       //
573       FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
574       if (FfsFileEntry == NULL) {
575         Status = EFI_OUT_OF_RESOURCES;
576         goto Done;
577       }
578 
579       FfsFileEntry->FfsHeader = CacheFfsHeader;
580       FfsFileEntry->FileCached = FileCached;
581       FileCached = FALSE;
582       InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
583     }
584 
585     if (IS_FFS_FILE2 (CacheFfsHeader)) {
586       FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
587     } else {
588       FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
589     }
590 
591     //
592     // Adjust pointer to the next 8-byte aligned boundry.
593     //
594     FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
595 
596   }
597 
598 Done:
599   if (EFI_ERROR (Status)) {
600     if (FileCached) {
601       CoreFreePool (CacheFfsHeader);
602       FileCached = FALSE;
603     }
604     FreeFvDeviceResource (FvDevice);
605   }
606 
607   return Status;
608 }
609 
610 
611 
612 /**
613   This notification function is invoked when an instance of the
614   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced.  It layers an instance of the
615   EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle.  This is the function where
616   the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
617 
618   @param  Event                 The event that occured
619   @param  Context               For EFI compatiblity.  Not used.
620 
621 **/
622 VOID
623 EFIAPI
NotifyFwVolBlock(IN EFI_EVENT Event,IN VOID * Context)624 NotifyFwVolBlock (
625   IN  EFI_EVENT Event,
626   IN  VOID      *Context
627   )
628 {
629   EFI_HANDLE                            Handle;
630   EFI_STATUS                            Status;
631   UINTN                                 BufferSize;
632   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
633   EFI_FIRMWARE_VOLUME2_PROTOCOL         *Fv;
634   FV_DEVICE                             *FvDevice;
635   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
636   //
637   // Examine all new handles
638   //
639   for (;;) {
640     //
641     // Get the next handle
642     //
643     BufferSize = sizeof (Handle);
644     Status = CoreLocateHandle (
645               ByRegisterNotify,
646               NULL,
647               gEfiFwVolBlockNotifyReg,
648               &BufferSize,
649               &Handle
650               );
651 
652     //
653     // If not found, we're done
654     //
655     if (EFI_NOT_FOUND == Status) {
656       break;
657     }
658 
659     if (EFI_ERROR (Status)) {
660       continue;
661     }
662 
663     //
664     // Get the FirmwareVolumeBlock protocol on that handle
665     //
666     Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
667     ASSERT_EFI_ERROR (Status);
668     ASSERT (Fvb != NULL);
669 
670     //
671     // Make sure the Fv Header is O.K.
672     //
673     Status = GetFwVolHeader (Fvb, &FwVolHeader);
674     if (EFI_ERROR (Status)) {
675       continue;
676     }
677     ASSERT (FwVolHeader != NULL);
678 
679     if (!VerifyFvHeaderChecksum (FwVolHeader)) {
680       CoreFreePool (FwVolHeader);
681       continue;
682     }
683 
684     //
685     // Check if there is an FV protocol already installed in that handle
686     //
687     Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
688     if (!EFI_ERROR (Status)) {
689       //
690       // Update Fv to use a new Fvb
691       //
692       FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
693       if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
694         //
695         // Only write into our device structure if it's our device structure
696         //
697         FvDevice->Fvb = Fvb;
698       }
699 
700     } else {
701       //
702       // No FwVol protocol on the handle so create a new one
703       //
704       FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
705       if (FvDevice == NULL) {
706         return;
707       }
708 
709       FvDevice->Fvb             = Fvb;
710       FvDevice->Handle          = Handle;
711       FvDevice->FwVolHeader     = FwVolHeader;
712       FvDevice->IsFfs3Fv        = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
713       FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
714 
715       if (Fvb->ParentHandle != NULL) {
716         //
717         // Inherit the authentication status from FVB.
718         //
719         FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
720       }
721 
722       if (!EFI_ERROR (FvCheck (FvDevice))) {
723         //
724         // Install an New FV protocol on the existing handle
725         //
726         Status = CoreInstallProtocolInterface (
727                     &Handle,
728                     &gEfiFirmwareVolume2ProtocolGuid,
729                     EFI_NATIVE_INTERFACE,
730                     &FvDevice->Fv
731                     );
732         ASSERT_EFI_ERROR (Status);
733       } else {
734         //
735         // Free FvDevice Buffer for the corrupt FV image.
736         //
737         CoreFreePool (FvDevice);
738       }
739     }
740   }
741 
742   return;
743 }
744 
745 
746 
747 /**
748   This routine is the driver initialization entry point.  It registers
749   a notification function.  This notification function are responsible
750   for building the FV stack dynamically.
751 
752   @param  ImageHandle           The image handle.
753   @param  SystemTable           The system table.
754 
755   @retval EFI_SUCCESS           Function successfully returned.
756 
757 **/
758 EFI_STATUS
759 EFIAPI
FwVolDriverInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)760 FwVolDriverInit (
761   IN EFI_HANDLE                   ImageHandle,
762   IN EFI_SYSTEM_TABLE             *SystemTable
763   )
764 {
765   gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
766                           &gEfiFirmwareVolumeBlockProtocolGuid,
767                           TPL_CALLBACK,
768                           NotifyFwVolBlock,
769                           NULL,
770                           &gEfiFwVolBlockNotifyReg
771                           );
772   return EFI_SUCCESS;
773 }
774 
775 
776