]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
Add core FFS3 support, FwVolDxe and SectionExtraction.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwVol.c
1 /** @file
2
3 Firmware File System driver that produce full Firmware Volume2 protocol.
4 Layers on top of Firmware Block protocol to produce a file abstraction
5 of FV based files.
6
7 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
8
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions
11 of the BSD License which accompanies this distribution. The
12 full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
14
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17
18 **/
19
20 #include "FwVolDriver.h"
21
22 #define KEYSIZE sizeof (UINTN)
23
24 /**
25 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
26 copy the real length volume header into it.
27
28 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
29 read the volume header
30 @param FwVolHeader Pointer to pointer to allocated buffer in which
31 the volume header is returned.
32
33 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
34 @retval EFI_SUCCESS Successfully read volume header to the allocated
35 buffer.
36 @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
37 **/
38 EFI_STATUS
39 GetFwVolHeader (
40 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
41 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
42 )
43 {
44 EFI_STATUS Status;
45 EFI_FIRMWARE_VOLUME_HEADER TempFvh;
46 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
47 UINTN FvhLength;
48 EFI_PHYSICAL_ADDRESS BaseAddress;
49
50 //
51 // Determine the real length of FV header
52 //
53 Status = Fvb->GetAttributes (
54 Fvb,
55 &FvbAttributes
56 );
57 if (EFI_ERROR (Status)) {
58 return Status;
59 }
60
61 if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
62 return EFI_ACCESS_DENIED;
63 }
64
65 //
66 // Just avoid compiling warning
67 //
68 BaseAddress = 0;
69 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
70
71 //
72 // memory-mapped FV and non memory-mapped has different ways to read
73 //
74 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
75 Status = Fvb->GetPhysicalAddress (
76 Fvb,
77 &BaseAddress
78 );
79 if (EFI_ERROR (Status)) {
80 return Status;
81 }
82 CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);
83 } else {
84 Status = Fvb->Read (
85 Fvb,
86 0,
87 0,
88 &FvhLength,
89 (UINT8 *) &TempFvh
90 );
91 }
92
93 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
94 if (*FwVolHeader == NULL) {
95 return EFI_OUT_OF_RESOURCES;
96 }
97 //
98 // Read the whole header
99 //
100 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
101 CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);
102 } else {
103 //
104 // Assumed the first block is bigger than the length of Fv headder
105 //
106 FvhLength = TempFvh.HeaderLength;
107 Status = Fvb->Read (
108 Fvb,
109 0,
110 0,
111 &FvhLength,
112 (UINT8 *) *FwVolHeader
113 );
114 //
115 // Check whether Read successes.
116 //
117 if (EFI_ERROR (Status)) {
118 FreePool (*FwVolHeader);
119 *FwVolHeader = NULL;
120 return Status;
121 }
122 }
123
124 return EFI_SUCCESS;
125 }
126
127 /**
128 Free FvDevice resource when error happens.
129
130 @param FvDevice Pointer to the FvDevice to be freed.
131 **/
132 VOID
133 FreeFvDeviceResource (
134 IN FV_DEVICE *FvDevice
135 )
136 {
137 LBA_ENTRY *LbaEntry;
138 FREE_SPACE_ENTRY *FreeSpaceEntry;
139 FFS_FILE_LIST_ENTRY *FfsFileEntry;
140 LIST_ENTRY *NextEntry;
141
142 //
143 // Free LAB Entry
144 //
145 LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;
146 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
147 NextEntry = (&LbaEntry->Link)->ForwardLink;
148 FreePool (LbaEntry);
149 LbaEntry = (LBA_ENTRY *) NextEntry;
150 }
151 //
152 // Free File List Entry
153 //
154 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
155 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
156 NextEntry = (&FfsFileEntry->Link)->ForwardLink;
157 FreePool (FfsFileEntry);
158 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
159 }
160 //
161 // Free Space Entry
162 //
163 FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;
164 while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {
165 NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;
166 FreePool (FreeSpaceEntry);
167 FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;
168 }
169 //
170 // Free the cache
171 //
172 FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);
173
174 return ;
175 }
176
177 /**
178 Check if an FV is consistent and allocate cache for it.
179
180 @param FvDevice A pointer to the FvDevice to be checked.
181
182 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
183 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
184 @retval EFI_SUCCESS FV is consistent and cache is allocated.
185
186 **/
187 EFI_STATUS
188 FvCheck (
189 IN FV_DEVICE *FvDevice
190 )
191 {
192 EFI_STATUS Status;
193 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
194 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
195 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
196 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
197 UINT8 *FwCache;
198 LBA_ENTRY *LbaEntry;
199 FREE_SPACE_ENTRY *FreeSpaceEntry;
200 FFS_FILE_LIST_ENTRY *FfsFileEntry;
201 UINT8 *LbaStart;
202 UINTN Index;
203 EFI_LBA LbaIndex;
204 UINT8 *Ptr;
205 UINTN Size;
206 UINT8 *FreeStart;
207 UINTN FreeSize;
208 UINT8 ErasePolarity;
209 EFI_FFS_FILE_STATE FileState;
210 UINT8 *TopFvAddress;
211 UINTN TestLength;
212 EFI_PHYSICAL_ADDRESS BaseAddress;
213
214 Fvb = FvDevice->Fvb;
215
216 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
217 if (EFI_ERROR (Status)) {
218 return Status;
219 }
220
221 InitializeListHead (&FvDevice->LbaHeader);
222 InitializeListHead (&FvDevice->FreeSpaceHeader);
223 InitializeListHead (&FvDevice->FfsFileListHeader);
224
225 FwVolHeader = NULL;
226 Status = GetFwVolHeader (Fvb, &FwVolHeader);
227 if (EFI_ERROR (Status)) {
228 return Status;
229 }
230 ASSERT (FwVolHeader != NULL);
231
232 FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
233
234 //
235 // Double Check firmware volume header here
236 //
237 if (!VerifyFvHeaderChecksum (FwVolHeader)) {
238 FreePool (FwVolHeader);
239 return EFI_VOLUME_CORRUPTED;
240 }
241
242 BlockMap = FwVolHeader->BlockMap;
243
244 //
245 // FwVolHeader->FvLength is the whole FV length including FV header
246 //
247 FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
248 if (FwCache == NULL) {
249 FreePool (FwVolHeader);
250 return EFI_OUT_OF_RESOURCES;
251 }
252
253 FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;
254
255 //
256 // Copy to memory
257 //
258 LbaStart = FwCache;
259 LbaIndex = 0;
260 Ptr = NULL;
261
262 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
263 //
264 // Get volume base address
265 //
266 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
267 if (EFI_ERROR (Status)) {
268 FreePool (FwVolHeader);
269 return Status;
270 }
271
272 Ptr = (UINT8 *) ((UINTN) BaseAddress);
273
274 DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
275 }
276 //
277 // Copy whole FV into the memory
278 //
279 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
280
281 for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
282 LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
283 if (LbaEntry == NULL) {
284 FreePool (FwVolHeader);
285 FreeFvDeviceResource (FvDevice);
286 return EFI_OUT_OF_RESOURCES;
287 }
288
289 LbaEntry->LbaIndex = LbaIndex;
290 LbaEntry->StartingAddress = LbaStart;
291 LbaEntry->BlockLength = BlockMap->Length;
292
293 //
294 // Copy each LBA into memory
295 //
296 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
297
298 CopyMem (LbaStart, Ptr, BlockMap->Length);
299 Ptr += BlockMap->Length;
300
301 } else {
302
303 Size = BlockMap->Length;
304 Status = Fvb->Read (
305 Fvb,
306 LbaIndex,
307 0,
308 &Size,
309 LbaStart
310 );
311 //
312 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
313 //
314 if (EFI_ERROR (Status)) {
315 FreePool (FwVolHeader);
316 FreeFvDeviceResource (FvDevice);
317 return Status;
318 }
319
320 }
321
322 LbaIndex++;
323 LbaStart += BlockMap->Length;
324
325 InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
326 }
327
328 BlockMap++;
329 }
330
331 FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;
332
333 //
334 // it is not used any more, so free FwVolHeader
335 //
336 FreePool (FwVolHeader);
337
338 //
339 // Scan to check the free space & File list
340 //
341 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
342 ErasePolarity = 1;
343 } else {
344 ErasePolarity = 0;
345 }
346
347 FvDevice->ErasePolarity = ErasePolarity;
348
349 //
350 // go through the whole FV cache, check the consistence of the FV
351 //
352 Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
353 TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength - 1);
354
355 //
356 // Build FFS list & Free Space List here
357 //
358 while (Ptr <= TopFvAddress) {
359 TestLength = TopFvAddress - Ptr + 1;
360
361 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
362 TestLength = sizeof (EFI_FFS_FILE_HEADER);
363 }
364
365 if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
366 //
367 // We found free space
368 //
369 FreeStart = Ptr;
370 FreeSize = 0;
371
372 do {
373 TestLength = TopFvAddress - Ptr + 1;
374
375 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
376 TestLength = sizeof (EFI_FFS_FILE_HEADER);
377 }
378
379 if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
380 break;
381 }
382
383 FreeSize += TestLength;
384 Ptr += TestLength;
385 } while (Ptr <= TopFvAddress);
386
387 FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
388 if (FreeSpaceEntry == NULL) {
389 FreeFvDeviceResource (FvDevice);
390 return EFI_OUT_OF_RESOURCES;
391 }
392 //
393 // Create a Free space entry
394 //
395 FreeSpaceEntry->StartingAddress = FreeStart;
396 FreeSpaceEntry->Length = FreeSize;
397 InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
398 continue;
399 }
400 //
401 // double check boundry
402 //
403 if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
404 break;
405 }
406
407 if (!IsValidFFSHeader (
408 FvDevice->ErasePolarity,
409 (EFI_FFS_FILE_HEADER *) Ptr
410 )) {
411 FileState = GetFileState (
412 FvDevice->ErasePolarity,
413 (EFI_FFS_FILE_HEADER *) Ptr
414 );
415 if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
416 if (IS_FFS_FILE2 (Ptr)) {
417 if (!FvDevice->IsFfs3Fv) {
418 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
419 }
420 Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2);
421 } else {
422 Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER);
423 }
424
425 continue;
426
427 } else {
428 //
429 // File system is corrputed, return
430 //
431 FreeFvDeviceResource (FvDevice);
432 return EFI_VOLUME_CORRUPTED;
433 }
434 }
435
436 if (IS_FFS_FILE2 (Ptr)) {
437 ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF);
438 if (!FvDevice->IsFfs3Fv) {
439 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
440 Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
441 //
442 // Adjust Ptr to the next 8-byte aligned boundry.
443 //
444 while (((UINTN) Ptr & 0x07) != 0) {
445 Ptr++;
446 }
447 continue;
448 }
449 }
450
451 if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
452 FileState = GetFileState (
453 FvDevice->ErasePolarity,
454 (EFI_FFS_FILE_HEADER *) Ptr
455 );
456
457 //
458 // check for non-deleted file
459 //
460 if (FileState != EFI_FILE_DELETED) {
461 //
462 // Create a FFS list entry for each non-deleted file
463 //
464 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
465 if (FfsFileEntry == NULL) {
466 FreeFvDeviceResource (FvDevice);
467 return EFI_OUT_OF_RESOURCES;
468 }
469
470 FfsFileEntry->FfsHeader = Ptr;
471 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
472 }
473
474 if (IS_FFS_FILE2 (Ptr)) {
475 Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
476 } else {
477 Ptr = Ptr + FFS_FILE_SIZE (Ptr);
478 }
479
480 //
481 // Adjust Ptr to the next 8-byte aligned boundry.
482 //
483 while (((UINTN) Ptr & 0x07) != 0) {
484 Ptr++;
485 }
486 } else {
487 //
488 // File system is corrupted, return
489 //
490 FreeFvDeviceResource (FvDevice);
491 return EFI_VOLUME_CORRUPTED;
492 }
493 }
494
495 FvDevice->CurrentFfsFile = NULL;
496
497 return EFI_SUCCESS;
498 }
499
500 /**
501 Entry point function does install/reinstall FV2 protocol with full functionality.
502
503 @param ImageHandle A handle for the image that is initializing this driver
504 @param SystemTable A pointer to the EFI system table
505
506 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
507 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
508 **/
509 EFI_STATUS
510 EFIAPI
511 FwVolDriverInit (
512 IN EFI_HANDLE ImageHandle,
513 IN EFI_SYSTEM_TABLE *SystemTable
514 )
515 {
516 EFI_STATUS Status;
517 EFI_HANDLE *HandleBuffer;
518 UINTN HandleCount;
519 UINTN Index;
520 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
521 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
522 FV_DEVICE *FvDevice;
523 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
524 BOOLEAN Reinstall;
525 BOOLEAN InstallFlag;
526
527 DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));
528 InstallFlag = FALSE;
529 //
530 // Locate all handles of Fvb protocol
531 //
532 Status = gBS->LocateHandleBuffer (
533 ByProtocol,
534 &gEfiFirmwareVolumeBlockProtocolGuid,
535 NULL,
536 &HandleCount,
537 &HandleBuffer
538 );
539 if (EFI_ERROR (Status)) {
540 return EFI_NOT_FOUND;
541 }
542
543 for (Index = 0; Index < HandleCount; Index += 1) {
544 Status = gBS->HandleProtocol (
545 HandleBuffer[Index],
546 &gEfiFirmwareVolumeBlockProtocolGuid,
547 (VOID **) &Fvb
548 );
549 if (EFI_ERROR (Status)) {
550 continue;
551 }
552
553 FwVolHeader = NULL;
554 Status = GetFwVolHeader (Fvb, &FwVolHeader);
555 if (EFI_ERROR (Status)) {
556 continue;
557 }
558 ASSERT (FwVolHeader != NULL);
559 //
560 // Check to see that the file system is indeed formatted in a way we can
561 // understand it...
562 //
563 if ((!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
564 (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
565 FreePool (FwVolHeader);
566 continue;
567 }
568 FreePool (FwVolHeader);
569
570 Reinstall = FALSE;
571 //
572 // Check if there is an FV protocol already installed in that handle
573 //
574 Status = gBS->HandleProtocol (
575 HandleBuffer[Index],
576 &gEfiFirmwareVolume2ProtocolGuid,
577 (VOID **) &Fv
578 );
579 if (!EFI_ERROR (Status)) {
580 Reinstall = TRUE;
581 }
582 //
583 // FwVol protocol on the handle so create a new one
584 //
585 FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));
586 if (FvDevice == NULL) {
587 goto Done;
588 }
589
590 FvDevice->Signature = FV_DEVICE_SIGNATURE;
591 FvDevice->Fvb = Fvb;
592
593 //
594 // Firmware Volume Protocol interface
595 //
596 FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;
597 FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;
598 FvDevice->Fv.ReadFile = FvReadFile;
599 FvDevice->Fv.ReadSection = FvReadFileSection;
600 FvDevice->Fv.WriteFile = FvWriteFile;
601 FvDevice->Fv.GetNextFile = FvGetNextFile;
602 FvDevice->Fv.KeySize = KEYSIZE;
603 FvDevice->Fv.GetInfo = FvGetVolumeInfo;
604 FvDevice->Fv.SetInfo = FvSetVolumeInfo;
605
606 Status = FvCheck (FvDevice);
607 if (EFI_ERROR (Status)) {
608 //
609 // The file system is not consistence
610 //
611 FreePool (FvDevice);
612 continue;
613 }
614
615 if (Reinstall) {
616 //
617 // Reinstall an New FV protocol
618 //
619 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
620 // FvDevice->Fvb = Fvb;
621 // FreeFvDeviceResource (FvDevice);
622 //
623 Status = gBS->ReinstallProtocolInterface (
624 HandleBuffer[Index],
625 &gEfiFirmwareVolume2ProtocolGuid,
626 Fv,
627 &FvDevice->Fv
628 );
629 if (!EFI_ERROR (Status)) {
630 InstallFlag = TRUE;
631 } else {
632 FreePool (FvDevice);
633 }
634
635 DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));
636 ASSERT_EFI_ERROR (Status);
637 } else {
638 //
639 // Install an New FV protocol
640 //
641 Status = gBS->InstallProtocolInterface (
642 &FvDevice->Handle,
643 &gEfiFirmwareVolume2ProtocolGuid,
644 EFI_NATIVE_INTERFACE,
645 &FvDevice->Fv
646 );
647 if (!EFI_ERROR (Status)) {
648 InstallFlag = TRUE;
649 } else {
650 FreePool (FvDevice);
651 }
652
653 DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));
654 ASSERT_EFI_ERROR (Status);
655 }
656 }
657
658 Done:
659 //
660 // As long as one Fv protocol install/reinstall successfully,
661 // success should return to ensure this image will be not unloaded.
662 // Otherwise, new Fv protocols are corrupted by other loaded driver.
663 //
664 if (InstallFlag) {
665 return EFI_SUCCESS;
666 }
667
668 //
669 // No FV protocol install/reinstall successfully.
670 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
671 //
672 return EFI_NOT_FOUND;
673 }