#!/usr/bin/perl # Create a UEFI "Firmware File" (FFS) with optional features. use warnings; use strict; use FindBin; use lib "$FindBin::Bin/../lib"; use Getopt::Long; use Digest::SHA 'sha1'; use EFI; my $usage = <<""; Usage: $0 -o output.ffs [options] file.efi [...] Options: -o | --output output.ffs Output file (default is stdout) -n | --name FileName Name to include in UI Section -t | --type Type FREEFORM|DRIVER|SMM|DXE_CORE|SMM_CORE|PEIM -v | --version 1.0 Version section -g | --guid GUID This file GUID (default is hash of Name) -d | --depex 'guid guid..' Optional dependencies (all ANDed, or TRUE) -z | --compress Enable LZMA compression my $output = '-'; my $name; my $type = 'FREEFORM'; my $version; my $guid; my $depex; my $compress; GetOptions( "o|output=s" => \$output, "n|name=s" => \$name, "t|type=s" => \$type, "v|version=s" => \$version, "g|guid=s" => \$guid, "d|depex=s" => \$depex, "z|compress+" => \$compress, ) or die $usage; die "$type: unknown file type\n" unless exists $EFI::file_types{$type}; my @sections; # Read entire files at a time and append a new section # for each file read. Some special types have their own # section type; otherwise we're adding a PE32 # The file goes first so that it will be aligned correctly # on the 4 KB page inside the FV. local $/ = undef; while(<>) { push @sections, EFI::section($EFI::section_type_map{$type} || 'PE32', $_); } # Put the optional parts after the input data push @sections, EFI::section(USER_INTERFACE => EFI::ucs16($name)) if $name; push @sections, EFI::section(VERSION => EFI::ucs16(chr(0x00) . $version)) if $version; push @sections, EFI::depex($type, split /\s+/, $depex) if $depex; # If we're compressing, compress the data and wrap it with a GUIDed header # replacing all of the existing sections. @sections = ( EFI::compress(@sections) ) if $compress; # If no GUID was provided, make one from the name # if there is no name from the data if ($guid) { $guid = EFI::guid($guid); } elsif ($name) { # Generate a deterministic GUID based on the UI name $guid = substr(sha1($name), 0, 16); } # Create the FFS header for the sections my $ffs = EFI::ffs($type, $guid, @sections); if ($output eq '-') { print $ffs; } else { open OUTPUT, ">", $output or die "$output: Unable to open: $!\n"; print OUTPUT $ffs; close OUTPUT; }