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