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