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