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