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