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