]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
MdeModulePkg DxeCore: Handle FFS file with FFS_ATTRIB_CHECKSUM set for not cache...
[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
eb1cace2 6Copyright (c) 2006 - 2014, 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
0c3a1db4 48 0,\r
eb1cace2 49 0,\r
0c3a1db4 50 FALSE,\r
eb1cace2 51 FALSE\r
28a00297 52};\r
53\r
54\r
55//\r
56// FFS helper functions\r
57//\r
162ed594 58/**\r
657abcff
LG
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
28a00297 167\r
022c6d45 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
28a00297 172\r
022c6d45 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
162ed594 175 buffer.\r
28a00297 176\r
162ed594 177**/\r
178EFI_STATUS\r
179GetFwVolHeader (\r
180 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
181 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
182 )\r
28a00297 183{\r
184 EFI_STATUS Status;\r
185 EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
186 UINTN FvhLength;\r
657abcff
LG
187 EFI_LBA StartLba;\r
188 UINTN Offset;\r
28a00297 189 UINT8 *Buffer;\r
657abcff 190 \r
28a00297 191 //\r
657abcff 192 // Read the standard FV header\r
28a00297 193 //\r
657abcff
LG
194 StartLba = 0;\r
195 Offset = 0;\r
28a00297 196 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
657abcff 197 Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);\r
13492369 198 if (EFI_ERROR (Status)) {\r
199 return Status;\r
200 }\r
28a00297 201\r
202 //\r
203 // Allocate a buffer for the caller\r
204 //\r
9c4ac31c 205 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
28a00297 206 if (*FwVolHeader == NULL) {\r
207 return EFI_OUT_OF_RESOURCES;\r
208 }\r
209\r
210 //\r
211 // Copy the standard header into the buffer\r
212 //\r
213 CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
214\r
215 //\r
216 // Read the rest of the header\r
217 //\r
218 FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
219 Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
657abcff 220 Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);\r
28a00297 221 if (EFI_ERROR (Status)) {\r
222 //\r
223 // Read failed so free buffer\r
224 //\r
225 CoreFreePool (*FwVolHeader);\r
226 }\r
022c6d45 227\r
28a00297 228 return Status;\r
229}\r
230\r
231\r
28a00297 232\r
162ed594 233/**\r
28a00297 234 Free FvDevice resource when error happens\r
235\r
022c6d45 236 @param FvDevice pointer to the FvDevice to be freed.\r
28a00297 237\r
162ed594 238**/\r
162ed594 239VOID\r
240FreeFvDeviceResource (\r
241 IN FV_DEVICE *FvDevice\r
242 )\r
28a00297 243{\r
244 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
245 LIST_ENTRY *NextEntry;\r
246\r
247 //\r
248 // Free File List Entry\r
249 //\r
250 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;\r
251 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
252 NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
022c6d45 253\r
28a00297 254 if (FfsFileEntry->StreamHandle != 0) {\r
255 //\r
256 // Close stream and free resources from SEP\r
257 //\r
eb1cace2
SZ
258 CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);\r
259 }\r
260\r
261 if (FfsFileEntry->FileCached) {\r
262 //\r
263 // Free the cached file buffer.\r
264 //\r
265 CoreFreePool (FfsFileEntry->FfsHeader);\r
28a00297 266 }\r
267\r
268 CoreFreePool (FfsFileEntry);\r
269\r
e94a9ff7 270 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
28a00297 271 }\r
272\r
eb1cace2
SZ
273 if (!FvDevice->IsMemoryMapped) {\r
274 //\r
275 // Free the cached FV buffer.\r
276 //\r
277 CoreFreePool (FvDevice->CachedFv);\r
278 }\r
28a00297 279\r
280 //\r
281 // Free Volume Header\r
282 //\r
283 CoreFreePool (FvDevice->FwVolHeader);\r
284\r
285 return;\r
286}\r
287\r
288\r
28a00297 289\r
162ed594 290/**\r
e94a9ff7 291 Check if an FV is consistent and allocate cache for it.\r
28a00297 292\r
022c6d45 293 @param FvDevice A pointer to the FvDevice to be checked.\r
28a00297 294\r
022c6d45 295 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
296 @retval EFI_SUCCESS FV is consistent and cache is allocated.\r
162ed594 297 @retval EFI_VOLUME_CORRUPTED File system is corrupted.\r
28a00297 298\r
162ed594 299**/\r
300EFI_STATUS\r
301FvCheck (\r
302 IN OUT FV_DEVICE *FvDevice\r
303 )\r
28a00297 304{\r
305 EFI_STATUS Status;\r
306 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
307 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
f95f107c 308 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;\r
8ee3a199 309 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
28a00297 310 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
311 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
312 EFI_FFS_FILE_HEADER *FfsHeader;\r
313 UINT8 *CacheLocation;\r
314 UINTN LbaOffset;\r
657abcff 315 UINTN HeaderSize;\r
28a00297 316 UINTN Index;\r
317 EFI_LBA LbaIndex;\r
318 UINTN Size;\r
28a00297 319 EFI_FFS_FILE_STATE FileState;\r
320 UINT8 *TopFvAddress;\r
321 UINTN TestLength;\r
eb1cace2 322 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
bc012551
SZ
323 BOOLEAN FileCached;\r
324 UINTN WholeFileSize;\r
325 EFI_FFS_FILE_HEADER *CacheFfsHeader;\r
326\r
327 FileCached = FALSE;\r
328 CacheFfsHeader = NULL;\r
28a00297 329\r
330 Fvb = FvDevice->Fvb;\r
331 FwVolHeader = FvDevice->FwVolHeader;\r
022c6d45 332\r
28a00297 333 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
334 if (EFI_ERROR (Status)) {\r
335 return Status;\r
336 }\r
337\r
338 //\r
339 // Size is the size of the FV minus the head. We have already allocated\r
340 // the header to check to make sure the volume is valid\r
341 //\r
342 Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);\r
eb1cace2
SZ
343 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
344 FvDevice->IsMemoryMapped = TRUE;\r
28a00297 345\r
eb1cace2
SZ
346 Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);\r
347 if (EFI_ERROR (Status)) {\r
348 return Status;\r
349 }\r
350\r
351 //\r
352 // Don't cache memory mapped FV really.\r
353 //\r
354 FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength);\r
355 } else {\r
356 FvDevice->IsMemoryMapped = FALSE;\r
357 FvDevice->CachedFv = AllocatePool (Size);\r
358\r
359 if (FvDevice->CachedFv == NULL) {\r
360 return EFI_OUT_OF_RESOURCES;\r
361 }\r
28a00297 362 }\r
363\r
364 //\r
365 // Remember a pointer to the end fo the CachedFv\r
366 //\r
367 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;\r
368\r
eb1cace2 369 if (!FvDevice->IsMemoryMapped) {\r
657abcff 370 //\r
eb1cace2
SZ
371 // Copy FV minus header into memory using the block map we have all ready\r
372 // read into memory.\r
657abcff 373 //\r
eb1cace2
SZ
374 BlockMap = FwVolHeader->BlockMap;\r
375 CacheLocation = FvDevice->CachedFv;\r
376 LbaIndex = 0;\r
377 LbaOffset = 0;\r
378 HeaderSize = FwVolHeader->HeaderLength;\r
379 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
380 Index = 0;\r
381 Size = BlockMap->Length;\r
382 if (HeaderSize > 0) {\r
383 //\r
384 // Skip header size\r
385 //\r
386 for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {\r
387 HeaderSize -= BlockMap->Length;\r
388 LbaIndex ++;\r
389 }\r
390\r
391 //\r
392 // Check whether FvHeader is crossing the multi block range.\r
393 //\r
394 if (Index >= BlockMap->NumBlocks) {\r
395 BlockMap++;\r
396 continue;\r
397 } else if (HeaderSize > 0) {\r
398 LbaOffset = HeaderSize;\r
399 Size = BlockMap->Length - HeaderSize;\r
400 HeaderSize = 0;\r
401 }\r
402 }\r
403 \r
28a00297 404 //\r
eb1cace2 405 // read the FV data \r
28a00297 406 //\r
eb1cace2
SZ
407 for (; Index < BlockMap->NumBlocks; Index ++) {\r
408 Status = Fvb->Read (Fvb,\r
409 LbaIndex,\r
410 LbaOffset,\r
411 &Size,\r
412 CacheLocation\r
413 );\r
414\r
415 //\r
416 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
417 //\r
418 if (EFI_ERROR (Status)) {\r
419 goto Done;\r
420 }\r
421\r
422 LbaIndex++;\r
423 CacheLocation += Size;\r
424\r
425 //\r
426 // After we skip Fv Header always read from start of block\r
427 //\r
428 LbaOffset = 0;\r
429 Size = BlockMap->Length;\r
28a00297 430 }\r
022c6d45 431\r
eb1cace2 432 BlockMap++;\r
28a00297 433 }\r
28a00297 434 }\r
435\r
436 //\r
437 // Scan to check the free space & File list\r
438 //\r
71f68914 439 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
28a00297 440 FvDevice->ErasePolarity = 1;\r
441 } else {\r
442 FvDevice->ErasePolarity = 0;\r
022c6d45 443 }\r
28a00297 444\r
445\r
446 //\r
447 // go through the whole FV cache, check the consistence of the FV.\r
f95f107c 448 // Make a linked list of all the Ffs file headers\r
28a00297 449 //\r
450 Status = EFI_SUCCESS;\r
451 InitializeListHead (&FvDevice->FfsFileListHeader);\r
452\r
453 //\r
454 // Build FFS list\r
455 //\r
f95f107c
SZ
456 if (FwVolHeader->ExtHeaderOffset != 0) {\r
457 //\r
458 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.\r
459 //\r
460 FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength));\r
461 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);\r
462 FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);\r
463 } else {\r
464 FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv);\r
465 }\r
28a00297 466 TopFvAddress = FvDevice->EndOfCachedFv;\r
e94a9ff7 467 while ((UINT8 *) FfsHeader < TopFvAddress) {\r
28a00297 468\r
bc012551
SZ
469 if (FileCached) {\r
470 CoreFreePool (CacheFfsHeader);\r
471 FileCached = FALSE;\r
472 }\r
473\r
e94a9ff7 474 TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
28a00297 475 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
476 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
477 }\r
478\r
479 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {\r
480 //\r
481 // We have found the free space so we are done!\r
482 //\r
483 goto Done;\r
484 }\r
485\r
486 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
022c6d45 487 if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
28a00297 488 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
6c85d162
SZ
489 if (IS_FFS_FILE2 (FfsHeader)) {\r
490 if (!FvDevice->IsFfs3Fv) {\r
491 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));\r
492 }\r
493 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));\r
494 } else {\r
495 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));\r
496 }\r
28a00297 497 continue;\r
28a00297 498 } else {\r
499 //\r
500 // File system is corrputed\r
501 //\r
502 Status = EFI_VOLUME_CORRUPTED;\r
503 goto Done;\r
504 }\r
505 }\r
506\r
bc012551
SZ
507 CacheFfsHeader = FfsHeader;\r
508 if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {\r
509 if (FvDevice->IsMemoryMapped) {\r
510 //\r
511 // Memory mapped FV has not been cached.\r
512 // Here is to cache FFS file to memory buffer for following checksum calculating.\r
513 // And then, the cached file buffer can be also used for FvReadFile.\r
514 //\r
515 WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);\r
516 CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);\r
517 if (CacheFfsHeader == NULL) {\r
518 Status = EFI_OUT_OF_RESOURCES;\r
519 goto Done;\r
520 }\r
521 FileCached = TRUE;\r
522 }\r
523 }\r
524\r
525 if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {\r
28a00297 526 //\r
527 // File system is corrupted\r
528 //\r
529 Status = EFI_VOLUME_CORRUPTED;\r
530 goto Done;\r
531 }\r
532\r
bc012551
SZ
533 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
534 ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);\r
6c85d162 535 if (!FvDevice->IsFfs3Fv) {\r
bc012551
SZ
536 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));\r
537 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
6c85d162
SZ
538 //\r
539 // Adjust pointer to the next 8-byte aligned boundry.\r
540 //\r
541 FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);\r
542 continue;\r
543 }\r
544 }\r
28a00297 545\r
bc012551 546 FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);\r
022c6d45 547\r
28a00297 548 //\r
549 // check for non-deleted file\r
550 //\r
551 if (FileState != EFI_FILE_DELETED) {\r
552 //\r
553 // Create a FFS list entry for each non-deleted file\r
554 //\r
9c4ac31c 555 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
28a00297 556 if (FfsFileEntry == NULL) {\r
557 Status = EFI_OUT_OF_RESOURCES;\r
558 goto Done;\r
559 }\r
022c6d45 560\r
bc012551
SZ
561 FfsFileEntry->FfsHeader = CacheFfsHeader;\r
562 FfsFileEntry->FileCached = FileCached;\r
563 FileCached = FALSE;\r
28a00297 564 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
565 }\r
566\r
bc012551
SZ
567 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
568 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
6c85d162 569 } else {\r
bc012551 570 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));\r
6c85d162 571 }\r
022c6d45 572\r
28a00297 573 //\r
574 // Adjust pointer to the next 8-byte aligned boundry.\r
575 //\r
576 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
022c6d45 577\r
28a00297 578 }\r
579\r
580Done:\r
581 if (EFI_ERROR (Status)) {\r
bc012551
SZ
582 if (FileCached) {\r
583 CoreFreePool (CacheFfsHeader);\r
584 FileCached = FALSE;\r
585 }\r
28a00297 586 FreeFvDeviceResource (FvDevice);\r
587 }\r
588\r
589 return Status;\r
590}\r
591\r
592\r
162ed594 593\r
594/**\r
595 This notification function is invoked when an instance of the\r
6c85d162 596 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the\r
162ed594 597 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where\r
598 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.\r
599\r
022c6d45 600 @param Event The event that occured\r
162ed594 601 @param Context For EFI compatiblity. Not used.\r
602\r
603**/\r
28a00297 604VOID\r
605EFIAPI\r
606NotifyFwVolBlock (\r
607 IN EFI_EVENT Event,\r
608 IN VOID *Context\r
609 )\r
28a00297 610{\r
611 EFI_HANDLE Handle;\r
612 EFI_STATUS Status;\r
613 UINTN BufferSize;\r
614 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
0c2b5da8 615 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 616 FV_DEVICE *FvDevice;\r
617 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
618 //\r
619 // Examine all new handles\r
620 //\r
621 for (;;) {\r
622 //\r
623 // Get the next handle\r
624 //\r
625 BufferSize = sizeof (Handle);\r
626 Status = CoreLocateHandle (\r
627 ByRegisterNotify,\r
628 NULL,\r
629 gEfiFwVolBlockNotifyReg,\r
630 &BufferSize,\r
631 &Handle\r
632 );\r
633\r
634 //\r
635 // If not found, we're done\r
636 //\r
637 if (EFI_NOT_FOUND == Status) {\r
638 break;\r
639 }\r
640\r
641 if (EFI_ERROR (Status)) {\r
642 continue;\r
643 }\r
022c6d45 644\r
28a00297 645 //\r
646 // Get the FirmwareVolumeBlock protocol on that handle\r
647 //\r
022c6d45 648 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
28a00297 649 ASSERT_EFI_ERROR (Status);\r
20bcdbcb 650 ASSERT (Fvb != NULL);\r
28a00297 651\r
652 //\r
653 // Make sure the Fv Header is O.K.\r
654 //\r
655 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
656 if (EFI_ERROR (Status)) {\r
657 return;\r
658 }\r
d2fbaaab 659 ASSERT (FwVolHeader != NULL);\r
28a00297 660\r
661 if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
662 CoreFreePool (FwVolHeader);\r
663 continue;\r
664 }\r
665\r
666\r
667 //\r
668 // Check to see that the file system is indeed formatted in a way we can\r
669 // understand it...\r
670 //\r
6c85d162
SZ
671 if ((!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&\r
672 (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {\r
28a00297 673 continue;\r
674 }\r
675\r
676 //\r
677 // Check if there is an FV protocol already installed in that handle\r
678 //\r
0c2b5da8 679 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
28a00297 680 if (!EFI_ERROR (Status)) {\r
681 //\r
682 // Update Fv to use a new Fvb\r
683 //\r
50d7ebad 684 FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);\r
0c2b5da8 685 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {\r
28a00297 686 //\r
687 // Only write into our device structure if it's our device structure\r
688 //\r
689 FvDevice->Fvb = Fvb;\r
690 }\r
691\r
692 } else {\r
693 //\r
694 // No FwVol protocol on the handle so create a new one\r
695 //\r
9c4ac31c 696 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
28a00297 697 if (FvDevice == NULL) {\r
698 return;\r
699 }\r
022c6d45 700\r
e94a9ff7 701 FvDevice->Fvb = Fvb;\r
702 FvDevice->Handle = Handle;\r
703 FvDevice->FwVolHeader = FwVolHeader;\r
6c85d162 704 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
0c3a1db4
SZ
705 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
706\r
707 if (Fvb->ParentHandle != NULL) {\r
708 //\r
709 // Inherit the authentication status from FVB.\r
710 //\r
711 FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);\r
712 }\r
1f33d186
LG
713 \r
714 if (!EFI_ERROR (FvCheck (FvDevice))) {\r
715 //\r
716 // Install an New FV protocol on the existing handle\r
717 //\r
718 Status = CoreInstallProtocolInterface (\r
719 &Handle,\r
720 &gEfiFirmwareVolume2ProtocolGuid,\r
721 EFI_NATIVE_INTERFACE,\r
722 &FvDevice->Fv\r
723 );\r
724 ASSERT_EFI_ERROR (Status);\r
725 } else {\r
726 //\r
727 // Free FvDevice Buffer for the corrupt FV image.\r
728 //\r
729 CoreFreePool (FvDevice);\r
730 }\r
28a00297 731 }\r
732 }\r
022c6d45 733\r
28a00297 734 return;\r
735}\r
736\r
737\r
162ed594 738\r
739/**\r
13492369 740 This routine is the driver initialization entry point. It registers\r
741 a notification function. This notification function are responsible\r
742 for building the FV stack dynamically.\r
162ed594 743\r
022c6d45 744 @param ImageHandle The image handle.\r
745 @param SystemTable The system table.\r
162ed594 746\r
747 @retval EFI_SUCCESS Function successfully returned.\r
748\r
749**/\r
28a00297 750EFI_STATUS\r
751EFIAPI\r
752FwVolDriverInit (\r
753 IN EFI_HANDLE ImageHandle,\r
754 IN EFI_SYSTEM_TABLE *SystemTable\r
755 )\r
28a00297 756{\r
7899b797 757 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (\r
28a00297 758 &gEfiFirmwareVolumeBlockProtocolGuid,\r
759 TPL_CALLBACK,\r
760 NotifyFwVolBlock,\r
761 NULL,\r
7899b797 762 &gEfiFwVolBlockNotifyReg\r
28a00297 763 );\r
764 return EFI_SUCCESS;\r
765}\r
766\r
162ed594 767\r