]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 // Protocol notify related globals
16 //
17 VOID *gEfiFwVolBlockNotifyReg;
18 EFI_EVENT gEfiFwVolBlockEvent;
19
20 FV_DEVICE mFvDevice = {
21 FV2_DEVICE_SIGNATURE,
22 NULL,
23 NULL,
24 {
25 FvGetVolumeAttributes,
26 FvSetVolumeAttributes,
27 FvReadFile,
28 FvReadFileSection,
29 FvWriteFile,
30 FvGetNextFile,
31 sizeof (UINTN),
32 NULL,
33 FvGetVolumeInfo,
34 FvSetVolumeInfo
35 },
36 NULL,
37 NULL,
38 NULL,
39 NULL,
40 { NULL, NULL},
41 0,
42 0,
43 FALSE,
44 FALSE
45 };
46
47 //
48 // FFS helper functions
49 //
50
51 /**
52 Read data from Firmware Block by FVB protocol Read.
53 The data may cross the multi block ranges.
54
55 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
56 @param StartLba Pointer to StartLba.
57 On input, the start logical block index from which to read.
58 On output,the end logical block index after reading.
59 @param Offset Pointer to Offset
60 On input, offset into the block at which to begin reading.
61 On output, offset into the end block after reading.
62 @param DataSize Size of data to be read.
63 @param Data Pointer to Buffer that the data will be read into.
64
65 @retval EFI_SUCCESS Successfully read data from firmware block.
66 @retval others
67 **/
68 EFI_STATUS
69 ReadFvbData (
70 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
71 IN OUT EFI_LBA *StartLba,
72 IN OUT UINTN *Offset,
73 IN UINTN DataSize,
74 OUT UINT8 *Data
75 )
76 {
77 UINTN BlockSize;
78 UINTN NumberOfBlocks;
79 UINTN BlockIndex;
80 UINTN ReadDataSize;
81 EFI_STATUS Status;
82
83 //
84 // Try read data in current block
85 //
86 BlockIndex = 0;
87 ReadDataSize = DataSize;
88 Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
89 if (Status == EFI_SUCCESS) {
90 *Offset += DataSize;
91 return EFI_SUCCESS;
92 } else if (Status != EFI_BAD_BUFFER_SIZE) {
93 //
94 // other error will direct return
95 //
96 return Status;
97 }
98
99 //
100 // Data crosses the blocks, read data from next block
101 //
102 DataSize -= ReadDataSize;
103 Data += ReadDataSize;
104 *StartLba = *StartLba + 1;
105 while (DataSize > 0) {
106 Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
107 if (EFI_ERROR (Status)) {
108 return Status;
109 }
110
111 //
112 // Read data from the crossing blocks
113 //
114 BlockIndex = 0;
115 while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
116 Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
117 if (EFI_ERROR (Status)) {
118 return Status;
119 }
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 {
212 return EFI_INVALID_PARAMETER;
213 }
214
215 //
216 // Allocate a buffer for the caller
217 //
218 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
219 if (*FwVolHeader == NULL) {
220 return EFI_OUT_OF_RESOURCES;
221 }
222
223 //
224 // Copy the standard header into the buffer
225 //
226 CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
227
228 //
229 // Read the rest of the header
230 //
231 FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
232 Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
233 Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
234 if (EFI_ERROR (Status)) {
235 //
236 // Read failed so free buffer
237 //
238 CoreFreePool (*FwVolHeader);
239 }
240
241 return Status;
242 }
243
244 /**
245 Free FvDevice resource when error happens
246
247 @param FvDevice pointer to the FvDevice to be freed.
248
249 **/
250 VOID
251 FreeFvDeviceResource (
252 IN FV_DEVICE *FvDevice
253 )
254 {
255 FFS_FILE_LIST_ENTRY *FfsFileEntry;
256 LIST_ENTRY *NextEntry;
257
258 //
259 // Free File List Entry
260 //
261 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
262 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
263 NextEntry = (&FfsFileEntry->Link)->ForwardLink;
264
265 if (FfsFileEntry->StreamHandle != 0) {
266 //
267 // Close stream and free resources from SEP
268 //
269 CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
270 }
271
272 if (FfsFileEntry->FileCached) {
273 //
274 // Free the cached file buffer.
275 //
276 CoreFreePool (FfsFileEntry->FfsHeader);
277 }
278
279 CoreFreePool (FfsFileEntry);
280
281 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;
282 }
283
284 if (!FvDevice->IsMemoryMapped) {
285 //
286 // Free the cached FV buffer.
287 //
288 CoreFreePool (FvDevice->CachedFv);
289 }
290
291 //
292 // Free Volume Header
293 //
294 CoreFreePool (FvDevice->FwVolHeader);
295
296 return;
297 }
298
299 /**
300 Check if an FV is consistent and allocate cache for it.
301
302 @param FvDevice A pointer to the FvDevice to be checked.
303
304 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
305 @retval EFI_SUCCESS FV is consistent and cache is allocated.
306 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
307
308 **/
309 EFI_STATUS
310 FvCheck (
311 IN OUT FV_DEVICE *FvDevice
312 )
313 {
314 EFI_STATUS Status;
315 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
316 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
317 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
318 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
319 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
320 FFS_FILE_LIST_ENTRY *FfsFileEntry;
321 EFI_FFS_FILE_HEADER *FfsHeader;
322 UINT8 *CacheLocation;
323 UINTN Index;
324 EFI_LBA LbaIndex;
325 UINTN Size;
326 EFI_FFS_FILE_STATE FileState;
327 UINT8 *TopFvAddress;
328 UINTN TestLength;
329 EFI_PHYSICAL_ADDRESS PhysicalAddress;
330 BOOLEAN FileCached;
331 UINTN WholeFileSize;
332 EFI_FFS_FILE_HEADER *CacheFfsHeader;
333
334 FileCached = FALSE;
335 CacheFfsHeader = NULL;
336
337 Fvb = FvDevice->Fvb;
338 FwVolHeader = FvDevice->FwVolHeader;
339
340 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
341 if (EFI_ERROR (Status)) {
342 return Status;
343 }
344
345 Size = (UINTN)FwVolHeader->FvLength;
346 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
347 FvDevice->IsMemoryMapped = TRUE;
348
349 Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
350 if (EFI_ERROR (Status)) {
351 return Status;
352 }
353
354 //
355 // Don't cache memory mapped FV really.
356 //
357 FvDevice->CachedFv = (UINT8 *)(UINTN)PhysicalAddress;
358 } else {
359 FvDevice->IsMemoryMapped = FALSE;
360 FvDevice->CachedFv = AllocatePool (Size);
361
362 if (FvDevice->CachedFv == NULL) {
363 return EFI_OUT_OF_RESOURCES;
364 }
365 }
366
367 //
368 // Remember a pointer to the end of the CachedFv
369 //
370 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
371
372 if (!FvDevice->IsMemoryMapped) {
373 //
374 // Copy FV into memory using the block map.
375 //
376 BlockMap = FwVolHeader->BlockMap;
377 CacheLocation = FvDevice->CachedFv;
378 LbaIndex = 0;
379 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
380 //
381 // read the FV data
382 //
383 Size = BlockMap->Length;
384 for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
385 Status = Fvb->Read (
386 Fvb,
387 LbaIndex,
388 0,
389 &Size,
390 CacheLocation
391 );
392
393 //
394 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
395 //
396 if (EFI_ERROR (Status)) {
397 goto Done;
398 }
399
400 LbaIndex++;
401 CacheLocation += BlockMap->Length;
402 }
403
404 BlockMap++;
405 }
406 }
407
408 //
409 // Scan to check the free space & File list
410 //
411 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
412 FvDevice->ErasePolarity = 1;
413 } else {
414 FvDevice->ErasePolarity = 0;
415 }
416
417 //
418 // go through the whole FV cache, check the consistence of the FV.
419 // Make a linked list of all the Ffs file headers
420 //
421 Status = EFI_SUCCESS;
422 InitializeListHead (&FvDevice->FfsFileListHeader);
423
424 //
425 // Build FFS list
426 //
427 if (FwVolHeader->ExtHeaderOffset != 0) {
428 //
429 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
430 //
431 FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);
432 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
433 } else {
434 FfsHeader = (EFI_FFS_FILE_HEADER *)(FvDevice->CachedFv + FwVolHeader->HeaderLength);
435 }
436
437 FfsHeader = (EFI_FFS_FILE_HEADER *)ALIGN_POINTER (FfsHeader, 8);
438 TopFvAddress = FvDevice->EndOfCachedFv;
439 while (((UINTN)FfsHeader >= (UINTN)FvDevice->CachedFv) && ((UINTN)FfsHeader <= (UINTN)((UINTN)TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
440 if (FileCached) {
441 CoreFreePool (CacheFfsHeader);
442 FileCached = FALSE;
443 }
444
445 TestLength = TopFvAddress - ((UINT8 *)FfsHeader);
446 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
447 TestLength = sizeof (EFI_FFS_FILE_HEADER);
448 }
449
450 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
451 //
452 // We have found the free space so we are done!
453 //
454 goto Done;
455 }
456
457 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
458 if ((FileState == EFI_FILE_HEADER_INVALID) ||
459 (FileState == EFI_FILE_HEADER_CONSTRUCTION))
460 {
461 if (IS_FFS_FILE2 (FfsHeader)) {
462 if (!FvDevice->IsFfs3Fv) {
463 DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
464 }
465
466 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
467 } else {
468 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
469 }
470
471 continue;
472 } else {
473 //
474 // File system is corrputed
475 //
476 Status = EFI_VOLUME_CORRUPTED;
477 goto Done;
478 }
479 }
480
481 CacheFfsHeader = FfsHeader;
482 if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
483 if (FvDevice->IsMemoryMapped) {
484 //
485 // Memory mapped FV has not been cached.
486 // Here is to cache FFS file to memory buffer for following checksum calculating.
487 // And then, the cached file buffer can be also used for FvReadFile.
488 //
489 WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader) : FFS_FILE_SIZE (CacheFfsHeader);
490 CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
491 if (CacheFfsHeader == NULL) {
492 Status = EFI_OUT_OF_RESOURCES;
493 goto Done;
494 }
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 ((DEBUG_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 Done:
555 if (EFI_ERROR (Status)) {
556 if (FileCached) {
557 CoreFreePool (CacheFfsHeader);
558 FileCached = FALSE;
559 }
560
561 FreeFvDeviceResource (FvDevice);
562 }
563
564 return Status;
565 }
566
567 /**
568 This notification function is invoked when an instance of the
569 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
570 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
571 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
572
573 @param Event The event that occurred
574 @param Context For EFI compatiblity. Not used.
575
576 **/
577 VOID
578 EFIAPI
579 NotifyFwVolBlock (
580 IN EFI_EVENT Event,
581 IN VOID *Context
582 )
583 {
584 EFI_HANDLE Handle;
585 EFI_STATUS Status;
586 UINTN BufferSize;
587 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
588 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
589 FV_DEVICE *FvDevice;
590 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
591
592 //
593 // Examine all new handles
594 //
595 for ( ; ;) {
596 //
597 // Get the next handle
598 //
599 BufferSize = sizeof (Handle);
600 Status = CoreLocateHandle (
601 ByRegisterNotify,
602 NULL,
603 gEfiFwVolBlockNotifyReg,
604 &BufferSize,
605 &Handle
606 );
607
608 //
609 // If not found, we're done
610 //
611 if (EFI_NOT_FOUND == Status) {
612 break;
613 }
614
615 if (EFI_ERROR (Status)) {
616 continue;
617 }
618
619 //
620 // Get the FirmwareVolumeBlock protocol on that handle
621 //
622 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
623 ASSERT_EFI_ERROR (Status);
624 ASSERT (Fvb != NULL);
625
626 //
627 // Make sure the Fv Header is O.K.
628 //
629 Status = GetFwVolHeader (Fvb, &FwVolHeader);
630 if (EFI_ERROR (Status)) {
631 continue;
632 }
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 } else {
657 //
658 // No FwVol protocol on the handle so create a new one
659 //
660 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
661 if (FvDevice == NULL) {
662 return;
663 }
664
665 FvDevice->Fvb = Fvb;
666 FvDevice->Handle = Handle;
667 FvDevice->FwVolHeader = FwVolHeader;
668 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
669 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
670 //
671 // Inherit the authentication status from FVB.
672 //
673 FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
674
675 if (!EFI_ERROR (FvCheck (FvDevice))) {
676 //
677 // Install an New FV protocol on the existing handle
678 //
679 Status = CoreInstallProtocolInterface (
680 &Handle,
681 &gEfiFirmwareVolume2ProtocolGuid,
682 EFI_NATIVE_INTERFACE,
683 &FvDevice->Fv
684 );
685 ASSERT_EFI_ERROR (Status);
686 } else {
687 //
688 // Free FvDevice Buffer for the corrupt FV image.
689 //
690 CoreFreePool (FvDevice);
691 }
692 }
693 }
694
695 return;
696 }
697
698 /**
699 This routine is the driver initialization entry point. It registers
700 a notification function. This notification function are responsible
701 for building the FV stack dynamically.
702
703 @param ImageHandle The image handle.
704 @param SystemTable The system table.
705
706 @retval EFI_SUCCESS Function successfully returned.
707
708 **/
709 EFI_STATUS
710 EFIAPI
711 FwVolDriverInit (
712 IN EFI_HANDLE ImageHandle,
713 IN EFI_SYSTEM_TABLE *SystemTable
714 )
715 {
716 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
717 &gEfiFirmwareVolumeBlockProtocolGuid,
718 TPL_CALLBACK,
719 NotifyFwVolBlock,
720 NULL,
721 &gEfiFwVolBlockNotifyReg
722 );
723 return EFI_SUCCESS;
724 }