]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
IntelFrameworkModulePkg: Add FwVolDxe driver
[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 - 2010, 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 UINTN FileLength;
210 EFI_FFS_FILE_STATE FileState;
211 UINT8 *TopFvAddress;
212 UINTN TestLength;
213 EFI_PHYSICAL_ADDRESS BaseAddress;
214
215 Fvb = FvDevice->Fvb;
216
217 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
218 if (EFI_ERROR (Status)) {
219 return Status;
220 }
221
222 InitializeListHead (&FvDevice->LbaHeader);
223 InitializeListHead (&FvDevice->FreeSpaceHeader);
224 InitializeListHead (&FvDevice->FfsFileListHeader);
225
226 FwVolHeader = NULL;
227 Status = GetFwVolHeader (Fvb, &FwVolHeader);
228 if (EFI_ERROR (Status)) {
229 return Status;
230 }
231 ASSERT (FwVolHeader != NULL);
232
233 //
234 // Double Check firmware volume header here
235 //
236 if (!VerifyFvHeaderChecksum (FwVolHeader)) {
237 FreePool (FwVolHeader);
238 return EFI_VOLUME_CORRUPTED;
239 }
240
241 BlockMap = FwVolHeader->BlockMap;
242
243 //
244 // FwVolHeader->FvLength is the whole FV length including FV header
245 //
246 FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
247 if (FwCache == NULL) {
248 FreePool (FwVolHeader);
249 return EFI_OUT_OF_RESOURCES;
250 }
251
252 FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;
253
254 //
255 // Copy to memory
256 //
257 LbaStart = FwCache;
258 LbaIndex = 0;
259 Ptr = NULL;
260
261 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
262 //
263 // Get volume base address
264 //
265 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
266 if (EFI_ERROR (Status)) {
267 FreePool (FwVolHeader);
268 return Status;
269 }
270
271 Ptr = (UINT8 *) ((UINTN) BaseAddress);
272
273 DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
274 }
275 //
276 // Copy whole FV into the memory
277 //
278 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
279
280 for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
281 LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
282 if (LbaEntry == NULL) {
283 FreePool (FwVolHeader);
284 FreeFvDeviceResource (FvDevice);
285 return EFI_OUT_OF_RESOURCES;
286 }
287
288 LbaEntry->LbaIndex = LbaIndex;
289 LbaEntry->StartingAddress = LbaStart;
290 LbaEntry->BlockLength = BlockMap->Length;
291
292 //
293 // Copy each LBA into memory
294 //
295 if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
296
297 CopyMem (LbaStart, Ptr, BlockMap->Length);
298 Ptr += BlockMap->Length;
299
300 } else {
301
302 Size = BlockMap->Length;
303 Status = Fvb->Read (
304 Fvb,
305 LbaIndex,
306 0,
307 &Size,
308 LbaStart
309 );
310 //
311 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
312 //
313 if (EFI_ERROR (Status)) {
314 FreePool (FwVolHeader);
315 FreeFvDeviceResource (FvDevice);
316 return Status;
317 }
318
319 }
320
321 LbaIndex++;
322 LbaStart += BlockMap->Length;
323
324 InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
325 }
326
327 BlockMap++;
328 }
329
330 FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;
331
332 //
333 // it is not used any more, so free FwVolHeader
334 //
335 FreePool (FwVolHeader);
336
337 //
338 // Scan to check the free space & File list
339 //
340 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
341 ErasePolarity = 1;
342 } else {
343 ErasePolarity = 0;
344 }
345
346 FvDevice->ErasePolarity = ErasePolarity;
347
348 //
349 // go through the whole FV cache, check the consistence of the FV
350 //
351 Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
352 TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength - 1);
353
354 //
355 // Build FFS list & Free Space List here
356 //
357 while (Ptr <= TopFvAddress) {
358 TestLength = TopFvAddress - Ptr + 1;
359
360 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
361 TestLength = sizeof (EFI_FFS_FILE_HEADER);
362 }
363
364 if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
365 //
366 // We found free space
367 //
368 FreeStart = Ptr;
369 FreeSize = 0;
370
371 do {
372 TestLength = TopFvAddress - Ptr + 1;
373
374 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
375 TestLength = sizeof (EFI_FFS_FILE_HEADER);
376 }
377
378 if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
379 break;
380 }
381
382 FreeSize += TestLength;
383 Ptr += TestLength;
384 } while (Ptr <= TopFvAddress);
385
386 FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
387 if (FreeSpaceEntry == NULL) {
388 FreeFvDeviceResource (FvDevice);
389 return EFI_OUT_OF_RESOURCES;
390 }
391 //
392 // Create a Free space entry
393 //
394 FreeSpaceEntry->StartingAddress = FreeStart;
395 FreeSpaceEntry->Length = FreeSize;
396 InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
397 continue;
398 }
399 //
400 // double check boundry
401 //
402 if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
403 break;
404 }
405
406 if (!IsValidFFSHeader (
407 FvDevice->ErasePolarity,
408 (EFI_FFS_FILE_HEADER *) Ptr
409 )) {
410 FileState = GetFileState (
411 FvDevice->ErasePolarity,
412 (EFI_FFS_FILE_HEADER *) Ptr
413 );
414 if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
415 Ptr += sizeof (EFI_FFS_FILE_HEADER);
416
417 continue;
418
419 } else {
420 //
421 // File system is corrputed, return
422 //
423 FreeFvDeviceResource (FvDevice);
424 return EFI_VOLUME_CORRUPTED;
425 }
426 }
427
428 if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
429 FileLength = *(UINT32 *) ((EFI_FFS_FILE_HEADER *) Ptr)->Size & 0x00FFFFFF;
430 FileState = GetFileState (
431 FvDevice->ErasePolarity,
432 (EFI_FFS_FILE_HEADER *) Ptr
433 );
434
435 //
436 // check for non-deleted file
437 //
438 if (FileState != EFI_FILE_DELETED) {
439 //
440 // Create a FFS list entry for each non-deleted file
441 //
442 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
443 if (FfsFileEntry == NULL) {
444 FreeFvDeviceResource (FvDevice);
445 return EFI_OUT_OF_RESOURCES;
446 }
447
448 FfsFileEntry->FfsHeader = Ptr;
449 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
450 }
451
452 Ptr += FileLength;
453
454 //
455 // Adjust Ptr to the next 8-byte aligned boundry.
456 //
457 while (((UINTN) Ptr & 0x07) != 0) {
458 Ptr++;
459 }
460 } else {
461 //
462 // File system is corrupted, return
463 //
464 FreeFvDeviceResource (FvDevice);
465 return EFI_VOLUME_CORRUPTED;
466 }
467 }
468
469 FvDevice->CurrentFfsFile = NULL;
470
471 return EFI_SUCCESS;
472 }
473
474 /**
475 Entry point function does install/reinstall FV2 protocol with full functionality.
476
477 @param ImageHandle A handle for the image that is initializing this driver
478 @param SystemTable A pointer to the EFI system table
479
480 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
481 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
482 **/
483 EFI_STATUS
484 EFIAPI
485 FwVolDriverInit (
486 IN EFI_HANDLE ImageHandle,
487 IN EFI_SYSTEM_TABLE *SystemTable
488 )
489 {
490 EFI_STATUS Status;
491 EFI_HANDLE *HandleBuffer;
492 UINTN HandleCount;
493 UINTN Index;
494 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
495 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
496 FV_DEVICE *FvDevice;
497 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
498 BOOLEAN Reinstall;
499 BOOLEAN InstallFlag;
500
501 DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));
502 InstallFlag = FALSE;
503 //
504 // Locate all handles of Fvb protocol
505 //
506 Status = gBS->LocateHandleBuffer (
507 ByProtocol,
508 &gEfiFirmwareVolumeBlockProtocolGuid,
509 NULL,
510 &HandleCount,
511 &HandleBuffer
512 );
513 if (EFI_ERROR (Status)) {
514 return EFI_NOT_FOUND;
515 }
516 //
517 // Get FV with gEfiFirmwareFileSystemGuid
518 //
519 for (Index = 0; Index < HandleCount; Index += 1) {
520 Status = gBS->HandleProtocol (
521 HandleBuffer[Index],
522 &gEfiFirmwareVolumeBlockProtocolGuid,
523 (VOID **) &Fvb
524 );
525 if (EFI_ERROR (Status)) {
526 continue;
527 }
528
529 FwVolHeader = NULL;
530 Status = GetFwVolHeader (Fvb, &FwVolHeader);
531 if (EFI_ERROR (Status)) {
532 continue;
533 }
534 ASSERT (FwVolHeader != NULL);
535 //
536 // Check to see that the file system is indeed formatted in a way we can
537 // understand it...
538 //
539 if (!CompareGuid (
540 &FwVolHeader->FileSystemGuid,
541 &gEfiFirmwareFileSystem2Guid
542 )) {
543 FreePool (FwVolHeader);
544 continue;
545 }
546 FreePool (FwVolHeader);
547
548 Reinstall = FALSE;
549 //
550 // Check if there is an FV protocol already installed in that handle
551 //
552 Status = gBS->HandleProtocol (
553 HandleBuffer[Index],
554 &gEfiFirmwareVolume2ProtocolGuid,
555 (VOID **) &Fv
556 );
557 if (!EFI_ERROR (Status)) {
558 Reinstall = TRUE;
559 }
560 //
561 // FwVol protocol on the handle so create a new one
562 //
563 FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));
564 if (FvDevice == NULL) {
565 goto Done;
566 }
567
568 FvDevice->Signature = FV_DEVICE_SIGNATURE;
569 FvDevice->Fvb = Fvb;
570
571 //
572 // Firmware Volume Protocol interface
573 //
574 FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;
575 FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;
576 FvDevice->Fv.ReadFile = FvReadFile;
577 FvDevice->Fv.ReadSection = FvReadFileSection;
578 FvDevice->Fv.WriteFile = FvWriteFile;
579 FvDevice->Fv.GetNextFile = FvGetNextFile;
580 FvDevice->Fv.KeySize = KEYSIZE;
581 FvDevice->Fv.GetInfo = FvGetVolumeInfo;
582 FvDevice->Fv.SetInfo = FvSetVolumeInfo;
583
584 Status = FvCheck (FvDevice);
585 if (EFI_ERROR (Status)) {
586 //
587 // The file system is not consistence
588 //
589 FreePool (FvDevice);
590 continue;
591 }
592
593 if (Reinstall) {
594 //
595 // Reinstall an New FV protocol
596 //
597 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
598 // FvDevice->Fvb = Fvb;
599 // FreeFvDeviceResource (FvDevice);
600 //
601 Status = gBS->ReinstallProtocolInterface (
602 HandleBuffer[Index],
603 &gEfiFirmwareVolume2ProtocolGuid,
604 Fv,
605 &FvDevice->Fv
606 );
607 if (!EFI_ERROR (Status)) {
608 InstallFlag = TRUE;
609 } else {
610 FreePool (FvDevice);
611 }
612
613 DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));
614 ASSERT_EFI_ERROR (Status);
615 } else {
616 //
617 // Install an New FV protocol
618 //
619 Status = gBS->InstallProtocolInterface (
620 &FvDevice->Handle,
621 &gEfiFirmwareVolume2ProtocolGuid,
622 EFI_NATIVE_INTERFACE,
623 &FvDevice->Fv
624 );
625 if (!EFI_ERROR (Status)) {
626 InstallFlag = TRUE;
627 } else {
628 FreePool (FvDevice);
629 }
630
631 DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));
632 ASSERT_EFI_ERROR (Status);
633 }
634 }
635
636 Done:
637 //
638 // As long as one Fv protocol install/reinstall successfully,
639 // success should return to ensure this image will be not unloaded.
640 // Otherwise, new Fv protocols are corrupted by other loaded driver.
641 //
642 if (InstallFlag) {
643 return EFI_SUCCESS;
644 }
645
646 //
647 // No FV protocol install/reinstall successfully.
648 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
649 //
650 return EFI_NOT_FOUND;
651 }