#!/usr/bin/perl # Create a UEFI "Firmware Volume" (FV) from "Firmware FileS" (FFS). # # Typical usage is to create a FFS for each file that will be included, # then to wrap them in a (compressed) FV. # # for file in *.efi; do # ./bin/create-ffs -o $file.ffs -t DRIVER $file # done # ./bin/create-ffs -o raw.ffs -t FREEFORM raw.bin # ./bin/create-fv -o firmware.fv *.ffs use warnings; use strict; use FindBin; use lib "$FindBin::Bin/../lib"; use Getopt::Long; use Digest::SHA 'sha1'; use EFI; my $usage = <<"END"; Usage: $0 -o output.fv [options] file.ffs [...] Options: -h | -? | --help This help -o | --output output.ffs Output file (default is stdout) -s | --size BYTES Final size in bytes (default is 4 MB) -v | --verbose Increase verbosity -z | --compress BYTES Create an internal LZMA compresed FV For compressed firmware volumes, the --size is the final size of the output and --compress size is the internal volume. So to create a 4MB volume with a 8MB internal use --size 0x4000000 --compress 0x800000 Sizes are limited to less than 16 MB until FFSv3 support is added. END # if invoked with no options, we should probably print some help die $usage unless @ARGV; my $output = '-'; my $size = 4 * 1024 * 1024; my $verbose = 0; my $compress_size; GetOptions( "h|?|help" => sub { print $usage; exit 0 }, "o|output=s" => \$output, "s|size=o" => \$size, "z|compress=o" => \$compress_size, "v|verbose+" => \$verbose, ) or die $usage; #my $guid = EFI::guid($guid_str) # or die "$guid_str: Unable to parse GUID\n"; # Read entire files at a time and append a new file # for each input read. local $/ = undef; my @ffs; my $length_sum = 0; while(<>) { push @ffs, $_; $length_sum += length $_; warn sprintf "%s: 0x%x bytes\n", $ARGV, length $_, if $verbose > 1; } warn sprintf "%s: 0x%08x out of %08x bytes in FV%s\n", $output, $length_sum, $compress_size || $size, $compress_size ? " (uncompressed)" : "", if $verbose > 0; my $fv = EFI::fv($compress_size || $size, @ffs) or die "$output: Unable to create FV\n"; if ($compress_size) { my $sec_lz = EFI::compress(EFI::section(FIRMWARE_VOLUME_IMAGE => $fv)); my $ffs_lz = EFI::ffs(FIRMWARE_VOLUME_IMAGE => '', $sec_lz); warn sprintf "%s: 0x%08x out of %08x bytes in FV (compressed)\n", $output, length($ffs_lz), $size, if $verbose > 0; my $outer_fv = EFI::fv($size, $ffs_lz) or die sprintf "%s: Unable to append 0x%08x compressed bytes\n", $output, length($ffs_lz), ; $fv = $outer_fv; } if ($output eq '-') { print $fv; } else { open OUTPUT, ">", $output or die "$output: Unable to open: $!\n"; print OUTPUT $fv; close OUTPUT; } __END__