]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
Fix potential NULL pointer dereference issue in TcgDxe & TreeDxe.
[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 - 2014, 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 LbaOffset;\r
333 UINTN HeaderSize;\r
334 UINTN Index;\r
335 EFI_LBA LbaIndex;\r
336 UINTN Size;\r
337 EFI_FFS_FILE_STATE FileState;\r
338 UINT8 *TopFvAddress;\r
339 UINTN TestLength;\r
340 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
341 BOOLEAN FileCached;\r
342 UINTN WholeFileSize;\r
343 EFI_FFS_FILE_HEADER *CacheFfsHeader;\r
344\r
345 FileCached = FALSE;\r
346 CacheFfsHeader = NULL;\r
347\r
348 Fvb = FvDevice->Fvb;\r
349 FwVolHeader = FvDevice->FwVolHeader;\r
350\r
351 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
352 if (EFI_ERROR (Status)) {\r
353 return Status;\r
354 }\r
355\r
356 //\r
357 // Size is the size of the FV minus the head. We have already allocated\r
358 // the header to check to make sure the volume is valid\r
359 //\r
360 Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);\r
361 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
362 FvDevice->IsMemoryMapped = TRUE;\r
363\r
364 Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);\r
365 if (EFI_ERROR (Status)) {\r
366 return Status;\r
367 }\r
368\r
369 //\r
370 // Don't cache memory mapped FV really.\r
371 //\r
372 FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength);\r
373 } else {\r
374 FvDevice->IsMemoryMapped = FALSE;\r
375 FvDevice->CachedFv = AllocatePool (Size);\r
376\r
377 if (FvDevice->CachedFv == NULL) {\r
378 return EFI_OUT_OF_RESOURCES;\r
379 }\r
380 }\r
381\r
382 //\r
383 // Remember a pointer to the end fo the CachedFv\r
384 //\r
385 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;\r
386\r
387 if (!FvDevice->IsMemoryMapped) {\r
388 //\r
389 // Copy FV minus header into memory using the block map we have all ready\r
390 // read into memory.\r
391 //\r
392 BlockMap = FwVolHeader->BlockMap;\r
393 CacheLocation = FvDevice->CachedFv;\r
394 LbaIndex = 0;\r
395 LbaOffset = 0;\r
396 HeaderSize = FwVolHeader->HeaderLength;\r
397 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
398 Index = 0;\r
399 Size = BlockMap->Length;\r
400 if (HeaderSize > 0) {\r
401 //\r
402 // Skip header size\r
403 //\r
404 for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {\r
405 HeaderSize -= BlockMap->Length;\r
406 LbaIndex ++;\r
407 }\r
408\r
409 //\r
410 // Check whether FvHeader is crossing the multi block range.\r
411 //\r
412 if (Index >= BlockMap->NumBlocks) {\r
413 BlockMap++;\r
414 continue;\r
415 } else if (HeaderSize > 0) {\r
416 LbaOffset = HeaderSize;\r
417 Size = BlockMap->Length - HeaderSize;\r
418 HeaderSize = 0;\r
419 }\r
420 }\r
421 \r
422 //\r
423 // read the FV data \r
424 //\r
425 for (; Index < BlockMap->NumBlocks; Index ++) {\r
426 Status = Fvb->Read (Fvb,\r
427 LbaIndex,\r
428 LbaOffset,\r
429 &Size,\r
430 CacheLocation\r
431 );\r
432\r
433 //\r
434 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
435 //\r
436 if (EFI_ERROR (Status)) {\r
437 goto Done;\r
438 }\r
439\r
440 LbaIndex++;\r
441 CacheLocation += Size;\r
442\r
443 //\r
444 // After we skip Fv Header always read from start of block\r
445 //\r
446 LbaOffset = 0;\r
447 Size = BlockMap->Length;\r
448 }\r
449\r
450 BlockMap++;\r
451 }\r
452 }\r
453\r
454 //\r
455 // Scan to check the free space & File list\r
456 //\r
457 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
458 FvDevice->ErasePolarity = 1;\r
459 } else {\r
460 FvDevice->ErasePolarity = 0;\r
461 }\r
462\r
463\r
464 //\r
465 // go through the whole FV cache, check the consistence of the FV.\r
466 // Make a linked list of all the Ffs file headers\r
467 //\r
468 Status = EFI_SUCCESS;\r
469 InitializeListHead (&FvDevice->FfsFileListHeader);\r
470\r
471 //\r
472 // Build FFS list\r
473 //\r
474 if (FwVolHeader->ExtHeaderOffset != 0) {\r
475 //\r
476 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.\r
477 //\r
478 FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength));\r
479 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);\r
480 FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);\r
481 } else {\r
482 FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv);\r
483 }\r
484 TopFvAddress = FvDevice->EndOfCachedFv;\r
485 while ((UINT8 *) FfsHeader < TopFvAddress) {\r
486\r
487 if (FileCached) {\r
488 CoreFreePool (CacheFfsHeader);\r
489 FileCached = FALSE;\r
490 }\r
491\r
492 TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
493 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
494 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
495 }\r
496\r
497 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {\r
498 //\r
499 // We have found the free space so we are done!\r
500 //\r
501 goto Done;\r
502 }\r
503\r
504 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
505 if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
506 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
507 if (IS_FFS_FILE2 (FfsHeader)) {\r
508 if (!FvDevice->IsFfs3Fv) {\r
509 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));\r
510 }\r
511 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));\r
512 } else {\r
513 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));\r
514 }\r
515 continue;\r
516 } else {\r
517 //\r
518 // File system is corrputed\r
519 //\r
520 Status = EFI_VOLUME_CORRUPTED;\r
521 goto Done;\r
522 }\r
523 }\r
524\r
525 CacheFfsHeader = FfsHeader;\r
526 if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {\r
527 if (FvDevice->IsMemoryMapped) {\r
528 //\r
529 // Memory mapped FV has not been cached.\r
530 // Here is to cache FFS file to memory buffer for following checksum calculating.\r
531 // And then, the cached file buffer can be also used for FvReadFile.\r
532 //\r
533 WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);\r
534 CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);\r
535 if (CacheFfsHeader == NULL) {\r
536 Status = EFI_OUT_OF_RESOURCES;\r
537 goto Done;\r
538 }\r
539 FileCached = TRUE;\r
540 }\r
541 }\r
542\r
543 if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {\r
544 //\r
545 // File system is corrupted\r
546 //\r
547 Status = EFI_VOLUME_CORRUPTED;\r
548 goto Done;\r
549 }\r
550\r
551 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
552 ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);\r
553 if (!FvDevice->IsFfs3Fv) {\r
554 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));\r
555 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
556 //\r
557 // Adjust pointer to the next 8-byte aligned boundry.\r
558 //\r
559 FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);\r
560 continue;\r
561 }\r
562 }\r
563\r
564 FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);\r
565\r
566 //\r
567 // check for non-deleted file\r
568 //\r
569 if (FileState != EFI_FILE_DELETED) {\r
570 //\r
571 // Create a FFS list entry for each non-deleted file\r
572 //\r
573 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
574 if (FfsFileEntry == NULL) {\r
575 Status = EFI_OUT_OF_RESOURCES;\r
576 goto Done;\r
577 }\r
578\r
579 FfsFileEntry->FfsHeader = CacheFfsHeader;\r
580 FfsFileEntry->FileCached = FileCached;\r
581 FileCached = FALSE;\r
582 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
583 }\r
584\r
585 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
586 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
587 } else {\r
588 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));\r
589 }\r
590\r
591 //\r
592 // Adjust pointer to the next 8-byte aligned boundry.\r
593 //\r
594 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
595\r
596 }\r
597\r
598Done:\r
599 if (EFI_ERROR (Status)) {\r
600 if (FileCached) {\r
601 CoreFreePool (CacheFfsHeader);\r
602 FileCached = FALSE;\r
603 }\r
604 FreeFvDeviceResource (FvDevice);\r
605 }\r
606\r
607 return Status;\r
608}\r
609\r
610\r
611\r
612/**\r
613 This notification function is invoked when an instance of the\r
614 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the\r
615 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where\r
616 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.\r
617\r
618 @param Event The event that occured\r
619 @param Context For EFI compatiblity. Not used.\r
620\r
621**/\r
622VOID\r
623EFIAPI\r
624NotifyFwVolBlock (\r
625 IN EFI_EVENT Event,\r
626 IN VOID *Context\r
627 )\r
628{\r
629 EFI_HANDLE Handle;\r
630 EFI_STATUS Status;\r
631 UINTN BufferSize;\r
632 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
633 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
634 FV_DEVICE *FvDevice;\r
635 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
636 //\r
637 // Examine all new handles\r
638 //\r
639 for (;;) {\r
640 //\r
641 // Get the next handle\r
642 //\r
643 BufferSize = sizeof (Handle);\r
644 Status = CoreLocateHandle (\r
645 ByRegisterNotify,\r
646 NULL,\r
647 gEfiFwVolBlockNotifyReg,\r
648 &BufferSize,\r
649 &Handle\r
650 );\r
651\r
652 //\r
653 // If not found, we're done\r
654 //\r
655 if (EFI_NOT_FOUND == Status) {\r
656 break;\r
657 }\r
658\r
659 if (EFI_ERROR (Status)) {\r
660 continue;\r
661 }\r
662\r
663 //\r
664 // Get the FirmwareVolumeBlock protocol on that handle\r
665 //\r
666 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
667 ASSERT_EFI_ERROR (Status);\r
668 ASSERT (Fvb != NULL);\r
669\r
670 //\r
671 // Make sure the Fv Header is O.K.\r
672 //\r
673 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
674 if (EFI_ERROR (Status)) {\r
675 return;\r
676 }\r
677 ASSERT (FwVolHeader != NULL);\r
678\r
679 if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
680 CoreFreePool (FwVolHeader);\r
681 continue;\r
682 }\r
683\r
684 //\r
685 // Check if there is an FV protocol already installed in that handle\r
686 //\r
687 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
688 if (!EFI_ERROR (Status)) {\r
689 //\r
690 // Update Fv to use a new Fvb\r
691 //\r
692 FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);\r
693 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {\r
694 //\r
695 // Only write into our device structure if it's our device structure\r
696 //\r
697 FvDevice->Fvb = Fvb;\r
698 }\r
699\r
700 } else {\r
701 //\r
702 // No FwVol protocol on the handle so create a new one\r
703 //\r
704 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
705 if (FvDevice == NULL) {\r
706 return;\r
707 }\r
708\r
709 FvDevice->Fvb = Fvb;\r
710 FvDevice->Handle = Handle;\r
711 FvDevice->FwVolHeader = FwVolHeader;\r
712 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
713 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
714\r
715 if (Fvb->ParentHandle != NULL) {\r
716 //\r
717 // Inherit the authentication status from FVB.\r
718 //\r
719 FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);\r
720 }\r
721 \r
722 if (!EFI_ERROR (FvCheck (FvDevice))) {\r
723 //\r
724 // Install an New FV protocol on the existing handle\r
725 //\r
726 Status = CoreInstallProtocolInterface (\r
727 &Handle,\r
728 &gEfiFirmwareVolume2ProtocolGuid,\r
729 EFI_NATIVE_INTERFACE,\r
730 &FvDevice->Fv\r
731 );\r
732 ASSERT_EFI_ERROR (Status);\r
733 } else {\r
734 //\r
735 // Free FvDevice Buffer for the corrupt FV image.\r
736 //\r
737 CoreFreePool (FvDevice);\r
738 }\r
739 }\r
740 }\r
741\r
742 return;\r
743}\r
744\r
745\r
746\r
747/**\r
748 This routine is the driver initialization entry point. It registers\r
749 a notification function. This notification function are responsible\r
750 for building the FV stack dynamically.\r
751\r
752 @param ImageHandle The image handle.\r
753 @param SystemTable The system table.\r
754\r
755 @retval EFI_SUCCESS Function successfully returned.\r
756\r
757**/\r
758EFI_STATUS\r
759EFIAPI\r
760FwVolDriverInit (\r
761 IN EFI_HANDLE ImageHandle,\r
762 IN EFI_SYSTEM_TABLE *SystemTable\r
763 )\r
764{\r
765 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (\r
766 &gEfiFirmwareVolumeBlockProtocolGuid,\r
767 TPL_CALLBACK,\r
768 NotifyFwVolBlock,\r
769 NULL,\r
770 &gEfiFwVolBlockNotifyReg\r
771 );\r
772 return EFI_SUCCESS;\r
773}\r
774\r
775\r