]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
MdeModulePkg DxeCore: Fix issue to print GUID value %g without pointer
[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
4888d15e
SZ
176 @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or\r
177 the file system could not be understood.\r
28a00297 178\r
162ed594 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
28a00297 185{\r
186 EFI_STATUS Status;\r
187 EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
188 UINTN FvhLength;\r
657abcff
LG
189 EFI_LBA StartLba;\r
190 UINTN Offset;\r
28a00297 191 UINT8 *Buffer;\r
657abcff 192 \r
28a00297 193 //\r
657abcff 194 // Read the standard FV header\r
28a00297 195 //\r
657abcff
LG
196 StartLba = 0;\r
197 Offset = 0;\r
28a00297 198 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
657abcff 199 Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);\r
13492369 200 if (EFI_ERROR (Status)) {\r
201 return Status;\r
202 }\r
28a00297 203\r
4888d15e
SZ
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
28a00297 220 //\r
221 // Allocate a buffer for the caller\r
222 //\r
9c4ac31c 223 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
28a00297 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
657abcff 238 Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);\r
28a00297 239 if (EFI_ERROR (Status)) {\r
240 //\r
241 // Read failed so free buffer\r
242 //\r
243 CoreFreePool (*FwVolHeader);\r
244 }\r
022c6d45 245\r
28a00297 246 return Status;\r
247}\r
248\r
249\r
28a00297 250\r
162ed594 251/**\r
28a00297 252 Free FvDevice resource when error happens\r
253\r
022c6d45 254 @param FvDevice pointer to the FvDevice to be freed.\r
28a00297 255\r
162ed594 256**/\r
162ed594 257VOID\r
258FreeFvDeviceResource (\r
259 IN FV_DEVICE *FvDevice\r
260 )\r
28a00297 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
022c6d45 271\r
28a00297 272 if (FfsFileEntry->StreamHandle != 0) {\r
273 //\r
274 // Close stream and free resources from SEP\r
275 //\r
eb1cace2
SZ
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
28a00297 284 }\r
285\r
286 CoreFreePool (FfsFileEntry);\r
287\r
e94a9ff7 288 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
28a00297 289 }\r
290\r
eb1cace2
SZ
291 if (!FvDevice->IsMemoryMapped) {\r
292 //\r
293 // Free the cached FV buffer.\r
294 //\r
295 CoreFreePool (FvDevice->CachedFv);\r
296 }\r
28a00297 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
28a00297 307\r
162ed594 308/**\r
e94a9ff7 309 Check if an FV is consistent and allocate cache for it.\r
28a00297 310\r
022c6d45 311 @param FvDevice A pointer to the FvDevice to be checked.\r
28a00297 312\r
022c6d45 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
162ed594 315 @retval EFI_VOLUME_CORRUPTED File system is corrupted.\r
28a00297 316\r
162ed594 317**/\r
318EFI_STATUS\r
319FvCheck (\r
320 IN OUT FV_DEVICE *FvDevice\r
321 )\r
28a00297 322{\r
323 EFI_STATUS Status;\r
324 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
325 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
f95f107c 326 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;\r
8ee3a199 327 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
28a00297 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
657abcff 333 UINTN HeaderSize;\r
28a00297 334 UINTN Index;\r
335 EFI_LBA LbaIndex;\r
336 UINTN Size;\r
28a00297 337 EFI_FFS_FILE_STATE FileState;\r
338 UINT8 *TopFvAddress;\r
339 UINTN TestLength;\r
eb1cace2 340 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
bc012551
SZ
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
28a00297 347\r
348 Fvb = FvDevice->Fvb;\r
349 FwVolHeader = FvDevice->FwVolHeader;\r
022c6d45 350\r
28a00297 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
eb1cace2
SZ
361 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
362 FvDevice->IsMemoryMapped = TRUE;\r
28a00297 363\r
eb1cace2
SZ
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
28a00297 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
eb1cace2 387 if (!FvDevice->IsMemoryMapped) {\r
657abcff 388 //\r
eb1cace2
SZ
389 // Copy FV minus header into memory using the block map we have all ready\r
390 // read into memory.\r
657abcff 391 //\r
eb1cace2
SZ
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
28a00297 422 //\r
eb1cace2 423 // read the FV data \r
28a00297 424 //\r
eb1cace2
SZ
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
28a00297 448 }\r
022c6d45 449\r
eb1cace2 450 BlockMap++;\r
28a00297 451 }\r
28a00297 452 }\r
453\r
454 //\r
455 // Scan to check the free space & File list\r
456 //\r
71f68914 457 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
28a00297 458 FvDevice->ErasePolarity = 1;\r
459 } else {\r
460 FvDevice->ErasePolarity = 0;\r
022c6d45 461 }\r
28a00297 462\r
463\r
464 //\r
465 // go through the whole FV cache, check the consistence of the FV.\r
f95f107c 466 // Make a linked list of all the Ffs file headers\r
28a00297 467 //\r
468 Status = EFI_SUCCESS;\r
469 InitializeListHead (&FvDevice->FfsFileListHeader);\r
470\r
471 //\r
472 // Build FFS list\r
473 //\r
f95f107c
SZ
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
28a00297 484 TopFvAddress = FvDevice->EndOfCachedFv;\r
fd8a2eb0 485 while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {\r
28a00297 486\r
bc012551
SZ
487 if (FileCached) {\r
488 CoreFreePool (CacheFfsHeader);\r
489 FileCached = FALSE;\r
490 }\r
491\r
e94a9ff7 492 TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
28a00297 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
022c6d45 505 if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
28a00297 506 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
6c85d162
SZ
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
28a00297 515 continue;\r
28a00297 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
bc012551
SZ
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
28a00297 544 //\r
545 // File system is corrupted\r
546 //\r
547 Status = EFI_VOLUME_CORRUPTED;\r
548 goto Done;\r
549 }\r
550\r
bc012551
SZ
551 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
552 ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);\r
6c85d162 553 if (!FvDevice->IsFfs3Fv) {\r
bc012551
SZ
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
6c85d162 556 //\r
6393d9c8 557 // Adjust pointer to the next 8-byte aligned boundary.\r
6c85d162
SZ
558 //\r
559 FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);\r
560 continue;\r
561 }\r
562 }\r
28a00297 563\r
bc012551 564 FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);\r
022c6d45 565\r
28a00297 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
9c4ac31c 573 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
28a00297 574 if (FfsFileEntry == NULL) {\r
575 Status = EFI_OUT_OF_RESOURCES;\r
576 goto Done;\r
577 }\r
022c6d45 578\r
bc012551
SZ
579 FfsFileEntry->FfsHeader = CacheFfsHeader;\r
580 FfsFileEntry->FileCached = FileCached;\r
581 FileCached = FALSE;\r
28a00297 582 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
583 }\r
584\r
bc012551
SZ
585 if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
586 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
6c85d162 587 } else {\r
bc012551 588 FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));\r
6c85d162 589 }\r
022c6d45 590\r
28a00297 591 //\r
6393d9c8 592 // Adjust pointer to the next 8-byte aligned boundary.\r
28a00297 593 //\r
594 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
022c6d45 595\r
28a00297 596 }\r
597\r
598Done:\r
599 if (EFI_ERROR (Status)) {\r
bc012551
SZ
600 if (FileCached) {\r
601 CoreFreePool (CacheFfsHeader);\r
602 FileCached = FALSE;\r
603 }\r
28a00297 604 FreeFvDeviceResource (FvDevice);\r
605 }\r
606\r
607 return Status;\r
608}\r
609\r
610\r
162ed594 611\r
612/**\r
613 This notification function is invoked when an instance of the\r
6c85d162 614 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the\r
162ed594 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
022c6d45 618 @param Event The event that occured\r
162ed594 619 @param Context For EFI compatiblity. Not used.\r
620\r
621**/\r
28a00297 622VOID\r
623EFIAPI\r
624NotifyFwVolBlock (\r
625 IN EFI_EVENT Event,\r
626 IN VOID *Context\r
627 )\r
28a00297 628{\r
629 EFI_HANDLE Handle;\r
630 EFI_STATUS Status;\r
631 UINTN BufferSize;\r
632 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
0c2b5da8 633 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 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
022c6d45 662\r
28a00297 663 //\r
664 // Get the FirmwareVolumeBlock protocol on that handle\r
665 //\r
022c6d45 666 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
28a00297 667 ASSERT_EFI_ERROR (Status);\r
20bcdbcb 668 ASSERT (Fvb != NULL);\r
28a00297 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
684a565a 675 continue;\r
28a00297 676 }\r
d2fbaaab 677 ASSERT (FwVolHeader != NULL);\r
28a00297 678\r
679 if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
680 CoreFreePool (FwVolHeader);\r
681 continue;\r
682 }\r
683\r
28a00297 684 //\r
685 // Check if there is an FV protocol already installed in that handle\r
686 //\r
0c2b5da8 687 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
28a00297 688 if (!EFI_ERROR (Status)) {\r
689 //\r
690 // Update Fv to use a new Fvb\r
691 //\r
50d7ebad 692 FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);\r
0c2b5da8 693 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {\r
28a00297 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
9c4ac31c 704 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
28a00297 705 if (FvDevice == NULL) {\r
706 return;\r
707 }\r
022c6d45 708\r
e94a9ff7 709 FvDevice->Fvb = Fvb;\r
710 FvDevice->Handle = Handle;\r
711 FvDevice->FwVolHeader = FwVolHeader;\r
6c85d162 712 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
0c3a1db4
SZ
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
1f33d186
LG
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
28a00297 739 }\r
740 }\r
022c6d45 741\r
28a00297 742 return;\r
743}\r
744\r
745\r
162ed594 746\r
747/**\r
13492369 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
162ed594 751\r
022c6d45 752 @param ImageHandle The image handle.\r
753 @param SystemTable The system table.\r
162ed594 754\r
755 @retval EFI_SUCCESS Function successfully returned.\r
756\r
757**/\r
28a00297 758EFI_STATUS\r
759EFIAPI\r
760FwVolDriverInit (\r
761 IN EFI_HANDLE ImageHandle,\r
762 IN EFI_SYSTEM_TABLE *SystemTable\r
763 )\r
28a00297 764{\r
7899b797 765 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (\r
28a00297 766 &gEfiFirmwareVolumeBlockProtocolGuid,\r
767 TPL_CALLBACK,\r
768 NotifyFwVolBlock,\r
769 NULL,\r
7899b797 770 &gEfiFwVolBlockNotifyReg\r
28a00297 771 );\r
772 return EFI_SUCCESS;\r
773}\r
774\r
162ed594 775\r