]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
move header files in MdeModulePkg\Core\Dxe except DxeMain.h into their corresponding...
[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
6Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
7All rights reserved. This program and the accompanying materials\r
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
28a00297 56 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
57 copy the volume header into it.\r
58\r
022c6d45 59 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to\r
60 read the volume header\r
61 @param FwVolHeader Pointer to pointer to allocated buffer in which\r
62 the volume header is returned.\r
28a00297 63\r
022c6d45 64 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
65 @retval EFI_SUCCESS Successfully read volume header to the allocated\r
162ed594 66 buffer.\r
28a00297 67\r
162ed594 68**/\r
69EFI_STATUS\r
70GetFwVolHeader (\r
71 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
72 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
73 )\r
28a00297 74{\r
75 EFI_STATUS Status;\r
76 EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
77 UINTN FvhLength;\r
78 UINT8 *Buffer;\r
79\r
80\r
81 //\r
82 //Determine the real length of FV header\r
83 //\r
84 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
85 Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);\r
13492369 86 if (EFI_ERROR (Status)) {\r
87 return Status;\r
88 }\r
28a00297 89\r
90 //\r
91 // Allocate a buffer for the caller\r
92 //\r
9c4ac31c 93 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
28a00297 94 if (*FwVolHeader == NULL) {\r
95 return EFI_OUT_OF_RESOURCES;\r
96 }\r
97\r
98 //\r
99 // Copy the standard header into the buffer\r
100 //\r
101 CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
102\r
103 //\r
104 // Read the rest of the header\r
105 //\r
106 FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
107 Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
108 Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);\r
109 if (EFI_ERROR (Status)) {\r
110 //\r
111 // Read failed so free buffer\r
112 //\r
113 CoreFreePool (*FwVolHeader);\r
114 }\r
022c6d45 115\r
28a00297 116 return Status;\r
117}\r
118\r
119\r
28a00297 120\r
162ed594 121/**\r
28a00297 122 Free FvDevice resource when error happens\r
123\r
022c6d45 124 @param FvDevice pointer to the FvDevice to be freed.\r
28a00297 125\r
162ed594 126**/\r
162ed594 127VOID\r
128FreeFvDeviceResource (\r
129 IN FV_DEVICE *FvDevice\r
130 )\r
28a00297 131{\r
132 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
133 LIST_ENTRY *NextEntry;\r
134\r
135 //\r
136 // Free File List Entry\r
137 //\r
138 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;\r
139 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
140 NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
022c6d45 141\r
28a00297 142 if (FfsFileEntry->StreamHandle != 0) {\r
143 //\r
144 // Close stream and free resources from SEP\r
145 //\r
797a9d67 146 CloseSectionStream (FfsFileEntry->StreamHandle);\r
28a00297 147 }\r
148\r
149 CoreFreePool (FfsFileEntry);\r
150\r
e94a9ff7 151 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
28a00297 152 }\r
153\r
154\r
155 //\r
156 // Free the cache\r
157 //\r
158 CoreFreePool (FvDevice->CachedFv);\r
159\r
160 //\r
161 // Free Volume Header\r
162 //\r
163 CoreFreePool (FvDevice->FwVolHeader);\r
164\r
165 return;\r
166}\r
167\r
168\r
28a00297 169\r
162ed594 170/**\r
e94a9ff7 171 Check if an FV is consistent and allocate cache for it.\r
28a00297 172\r
022c6d45 173 @param FvDevice A pointer to the FvDevice to be checked.\r
28a00297 174\r
022c6d45 175 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.\r
176 @retval EFI_SUCCESS FV is consistent and cache is allocated.\r
162ed594 177 @retval EFI_VOLUME_CORRUPTED File system is corrupted.\r
28a00297 178\r
162ed594 179**/\r
180EFI_STATUS\r
181FvCheck (\r
182 IN OUT FV_DEVICE *FvDevice\r
183 )\r
28a00297 184{\r
185 EFI_STATUS Status;\r
186 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
187 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
8ee3a199 188 EFI_FVB_ATTRIBUTES_2 FvbAttributes;\r
28a00297 189 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
190 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
191 EFI_FFS_FILE_HEADER *FfsHeader;\r
192 UINT8 *CacheLocation;\r
193 UINTN LbaOffset;\r
194 UINTN Index;\r
195 EFI_LBA LbaIndex;\r
196 UINTN Size;\r
197 UINTN FileLength;\r
198 EFI_FFS_FILE_STATE FileState;\r
199 UINT8 *TopFvAddress;\r
200 UINTN TestLength;\r
201\r
202\r
203 Fvb = FvDevice->Fvb;\r
204 FwVolHeader = FvDevice->FwVolHeader;\r
022c6d45 205\r
28a00297 206 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);\r
207 if (EFI_ERROR (Status)) {\r
208 return Status;\r
209 }\r
210\r
211 //\r
212 // Size is the size of the FV minus the head. We have already allocated\r
213 // the header to check to make sure the volume is valid\r
214 //\r
215 Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);\r
9c4ac31c 216 FvDevice->CachedFv = AllocatePool (Size);\r
28a00297 217\r
218 if (FvDevice->CachedFv == NULL) {\r
219 return EFI_OUT_OF_RESOURCES;\r
220 }\r
221\r
222 //\r
223 // Remember a pointer to the end fo the CachedFv\r
224 //\r
225 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;\r
226\r
227 //\r
228 // Copy FV minus header into memory using the block map we have all ready\r
229 // read into memory.\r
230 //\r
231 BlockMap = FwVolHeader->BlockMap;\r
232 CacheLocation = FvDevice->CachedFv;\r
233 LbaIndex = 0;\r
234 LbaOffset = FwVolHeader->HeaderLength;\r
235 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
022c6d45 236\r
28a00297 237 for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {\r
238\r
239 Size = BlockMap->Length;\r
240 if (Index == 0) {\r
241 //\r
242 // Cache does not include FV Header\r
243 //\r
244 Size -= LbaOffset;\r
245 }\r
246 Status = Fvb->Read (Fvb,\r
e94a9ff7 247 LbaIndex,\r
248 LbaOffset,\r
249 &Size,\r
250 CacheLocation\r
251 );\r
28a00297 252 //\r
253 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
254 //\r
255 if (EFI_ERROR (Status)) {\r
256 goto Done;\r
257 }\r
022c6d45 258\r
28a00297 259 //\r
260 // After we skip Fv Header always read from start of block\r
261 //\r
262 LbaOffset = 0;\r
263\r
264 LbaIndex++;\r
265 CacheLocation += Size;\r
266 }\r
267 BlockMap++;\r
268 }\r
269\r
270 //\r
271 // Scan to check the free space & File list\r
272 //\r
71f68914 273 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
28a00297 274 FvDevice->ErasePolarity = 1;\r
275 } else {\r
276 FvDevice->ErasePolarity = 0;\r
022c6d45 277 }\r
28a00297 278\r
279\r
280 //\r
281 // go through the whole FV cache, check the consistence of the FV.\r
282 // Make a linked list off all the Ffs file headers\r
283 //\r
284 Status = EFI_SUCCESS;\r
285 InitializeListHead (&FvDevice->FfsFileListHeader);\r
286\r
287 //\r
288 // Build FFS list\r
289 //\r
e94a9ff7 290 FfsHeader = (EFI_FFS_FILE_HEADER *) FvDevice->CachedFv;\r
28a00297 291 TopFvAddress = FvDevice->EndOfCachedFv;\r
e94a9ff7 292 while ((UINT8 *) FfsHeader < TopFvAddress) {\r
28a00297 293\r
e94a9ff7 294 TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
28a00297 295 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
296 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
297 }\r
298\r
299 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {\r
300 //\r
301 // We have found the free space so we are done!\r
302 //\r
303 goto Done;\r
304 }\r
305\r
306 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
022c6d45 307 if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
28a00297 308 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
309 FfsHeader++;\r
28a00297 310 continue;\r
28a00297 311 } else {\r
312 //\r
313 // File system is corrputed\r
314 //\r
315 Status = EFI_VOLUME_CORRUPTED;\r
316 goto Done;\r
317 }\r
318 }\r
319\r
320 if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) {\r
321 //\r
322 // File system is corrupted\r
323 //\r
324 Status = EFI_VOLUME_CORRUPTED;\r
325 goto Done;\r
326 }\r
327\r
328 //\r
329 // Size[3] is a three byte array, read 4 bytes and throw one away\r
330 //\r
331 FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF;\r
332\r
333 FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader);\r
022c6d45 334\r
28a00297 335 //\r
336 // check for non-deleted file\r
337 //\r
338 if (FileState != EFI_FILE_DELETED) {\r
339 //\r
340 // Create a FFS list entry for each non-deleted file\r
341 //\r
9c4ac31c 342 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));\r
28a00297 343 if (FfsFileEntry == NULL) {\r
344 Status = EFI_OUT_OF_RESOURCES;\r
345 goto Done;\r
346 }\r
022c6d45 347\r
28a00297 348 FfsFileEntry->FfsHeader = FfsHeader;\r
349 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
350 }\r
351\r
352 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength);\r
022c6d45 353\r
28a00297 354 //\r
355 // Adjust pointer to the next 8-byte aligned boundry.\r
356 //\r
357 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
022c6d45 358\r
28a00297 359 }\r
360\r
361Done:\r
362 if (EFI_ERROR (Status)) {\r
363 FreeFvDeviceResource (FvDevice);\r
364 }\r
365\r
366 return Status;\r
367}\r
368\r
369\r
162ed594 370\r
371/**\r
372 This notification function is invoked when an instance of the\r
373 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the\r
374 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where\r
375 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.\r
376\r
022c6d45 377 @param Event The event that occured\r
162ed594 378 @param Context For EFI compatiblity. Not used.\r
379\r
380**/\r
28a00297 381VOID\r
382EFIAPI\r
383NotifyFwVolBlock (\r
384 IN EFI_EVENT Event,\r
385 IN VOID *Context\r
386 )\r
28a00297 387{\r
388 EFI_HANDLE Handle;\r
389 EFI_STATUS Status;\r
390 UINTN BufferSize;\r
391 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
0c2b5da8 392 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 393 FV_DEVICE *FvDevice;\r
394 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
395 //\r
396 // Examine all new handles\r
397 //\r
398 for (;;) {\r
399 //\r
400 // Get the next handle\r
401 //\r
402 BufferSize = sizeof (Handle);\r
403 Status = CoreLocateHandle (\r
404 ByRegisterNotify,\r
405 NULL,\r
406 gEfiFwVolBlockNotifyReg,\r
407 &BufferSize,\r
408 &Handle\r
409 );\r
410\r
411 //\r
412 // If not found, we're done\r
413 //\r
414 if (EFI_NOT_FOUND == Status) {\r
415 break;\r
416 }\r
417\r
418 if (EFI_ERROR (Status)) {\r
419 continue;\r
420 }\r
022c6d45 421\r
28a00297 422 //\r
423 // Get the FirmwareVolumeBlock protocol on that handle\r
424 //\r
022c6d45 425 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
28a00297 426 ASSERT_EFI_ERROR (Status);\r
022c6d45 427\r
28a00297 428\r
429 //\r
430 // Make sure the Fv Header is O.K.\r
431 //\r
432 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
433 if (EFI_ERROR (Status)) {\r
434 return;\r
435 }\r
436\r
437 if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
438 CoreFreePool (FwVolHeader);\r
439 continue;\r
440 }\r
441\r
442\r
443 //\r
444 // Check to see that the file system is indeed formatted in a way we can\r
445 // understand it...\r
446 //\r
9767823f 447 if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) {\r
28a00297 448 continue;\r
449 }\r
450\r
451 //\r
452 // Check if there is an FV protocol already installed in that handle\r
453 //\r
0c2b5da8 454 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
28a00297 455 if (!EFI_ERROR (Status)) {\r
456 //\r
457 // Update Fv to use a new Fvb\r
458 //\r
459 FvDevice = _CR (Fv, FV_DEVICE, Fv);\r
0c2b5da8 460 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {\r
28a00297 461 //\r
462 // Only write into our device structure if it's our device structure\r
463 //\r
464 FvDevice->Fvb = Fvb;\r
465 }\r
466\r
467 } else {\r
468 //\r
469 // No FwVol protocol on the handle so create a new one\r
470 //\r
9c4ac31c 471 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
28a00297 472 if (FvDevice == NULL) {\r
473 return;\r
474 }\r
022c6d45 475\r
e94a9ff7 476 FvDevice->Fvb = Fvb;\r
477 FvDevice->Handle = Handle;\r
478 FvDevice->FwVolHeader = FwVolHeader;\r
28a00297 479 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
022c6d45 480\r
28a00297 481 //\r
482 // Install an New FV protocol on the existing handle\r
483 //\r
484 Status = CoreInstallProtocolInterface (\r
485 &Handle,\r
0c2b5da8 486 &gEfiFirmwareVolume2ProtocolGuid,\r
28a00297 487 EFI_NATIVE_INTERFACE,\r
488 &FvDevice->Fv\r
489 );\r
490 ASSERT_EFI_ERROR (Status);\r
491 }\r
492 }\r
022c6d45 493\r
28a00297 494 return;\r
495}\r
496\r
497\r
162ed594 498\r
499/**\r
13492369 500 This routine is the driver initialization entry point. It registers\r
501 a notification function. This notification function are responsible\r
502 for building the FV stack dynamically.\r
162ed594 503\r
022c6d45 504 @param ImageHandle The image handle.\r
505 @param SystemTable The system table.\r
162ed594 506\r
507 @retval EFI_SUCCESS Function successfully returned.\r
508\r
509**/\r
28a00297 510EFI_STATUS\r
511EFIAPI\r
512FwVolDriverInit (\r
513 IN EFI_HANDLE ImageHandle,\r
514 IN EFI_SYSTEM_TABLE *SystemTable\r
515 )\r
28a00297 516{\r
7899b797 517 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (\r
28a00297 518 &gEfiFirmwareVolumeBlockProtocolGuid,\r
519 TPL_CALLBACK,\r
520 NotifyFwVolBlock,\r
521 NULL,\r
7899b797 522 &gEfiFwVolBlockNotifyReg\r
28a00297 523 );\r
524 return EFI_SUCCESS;\r
525}\r
526\r
162ed594 527\r