FwVol.c revision 4888d15e74628fd373605d5d853fa3b172aeadc3
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**/
40EFI_STATUS
41GetFwVolHeader (
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**/
150VOID
151FreeFvDeviceResource (
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**/
203VOID
204FwVolInheritAuthenticationStatus (
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**/
308EFI_STATUS
309FvCheck (
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**/
640EFI_STATUS
641EFIAPI
642FwVolDriverInit (
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
783Done:
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