summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/util')
-rw-r--r--qemu/roms/ipxe/src/util/Option/ROM.pm20
-rwxr-xr-xqemu/roms/ipxe/src/util/disrom.pl4
-rw-r--r--qemu/roms/ipxe/src/util/elf2efi.c6
-rwxr-xr-xqemu/roms/ipxe/src/util/licence.pl13
-rwxr-xr-xqemu/roms/ipxe/src/util/parserom.pl296
-rwxr-xr-xqemu/roms/ipxe/src/util/relicense.pl169
-rw-r--r--qemu/roms/ipxe/src/util/zbin.c96
7 files changed, 541 insertions, 63 deletions
diff --git a/qemu/roms/ipxe/src/util/Option/ROM.pm b/qemu/roms/ipxe/src/util/Option/ROM.pm
index 6c396730e..232cf16b8 100644
--- a/qemu/roms/ipxe/src/util/Option/ROM.pm
+++ b/qemu/roms/ipxe/src/util/Option/ROM.pm
@@ -529,6 +529,26 @@ sub new {
return $hash;
}
+sub device_list {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $device_list = $hash->{device_list};
+ return undef unless $device_list;
+
+ my @ids;
+ my $offset = ( $self->{offset} + $device_list );
+ while ( 1 ) {
+ my $raw = substr ( ${$self->{data}}, $offset, 2 );
+ my $id = unpack ( "S", $raw );
+ last unless $id;
+ push @ids, $id;
+ $offset += 2;
+ }
+
+ return @ids;
+}
+
##############################################################################
#
# Option::ROM::PnP
diff --git a/qemu/roms/ipxe/src/util/disrom.pl b/qemu/roms/ipxe/src/util/disrom.pl
index 574957acd..920a86b24 100755
--- a/qemu/roms/ipxe/src/util/disrom.pl
+++ b/qemu/roms/ipxe/src/util/disrom.pl
@@ -55,6 +55,10 @@ do {
printf " %-16s %s\n", "Signature:", $pci->{signature};
printf " %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id};
printf " %-16s 0x%04x\n", "Device ID:", $pci->{device_id};
+ if ( $pci->{device_list} ) {
+ printf " %-16s %s\n", "Device list:",
+ ( join ( ", ", map { sprintf "0x%04x", $_ } $pci->device_list ) );
+ }
printf " %-16s 0x%02x%02x%02x\n", "Device class:",
$pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
printf " %-16s 0x%04x (%d)\n", "Image length:",
diff --git a/qemu/roms/ipxe/src/util/elf2efi.c b/qemu/roms/ipxe/src/util/elf2efi.c
index 45d539574..e68fa5d14 100644
--- a/qemu/roms/ipxe/src/util/elf2efi.c
+++ b/qemu/roms/ipxe/src/util/elf2efi.c
@@ -478,11 +478,13 @@ static void process_reloc ( bfd *bfd __attribute__ (( unused )),
/* Skip absolute symbols; the symbol value won't
* change when the object is loaded.
*/
+ } else if ( ( strcmp ( howto->name, "R_386_NONE" ) == 0 ) ||
+ ( strcmp ( howto->name, "R_X86_64_NONE" ) == 0 ) ) {
+ /* Ignore dummy relocations used by REQUIRE_SYMBOL() */
} else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
/* Generate an 8-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 8 );
- } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
- ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
+ } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) {
/* Generate a 4-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 4 );
} else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
diff --git a/qemu/roms/ipxe/src/util/licence.pl b/qemu/roms/ipxe/src/util/licence.pl
index 0e43c7b4c..79e70fd65 100755
--- a/qemu/roms/ipxe/src/util/licence.pl
+++ b/qemu/roms/ipxe/src/util/licence.pl
@@ -37,6 +37,7 @@ my $known_licences = {
desc => "GPL version 2 (or, at your option, any later version)",
can_subsume => {
gpl_any => 1,
+ gpl2_or_later_or_ubdl => 1,
public_domain => 1,
bsd3 => 1,
bsd2 => 1,
@@ -49,6 +50,7 @@ my $known_licences = {
can_subsume => {
gpl_any => 1,
gpl2_or_later => 1,
+ gpl2_or_later_or_ubdl => 1,
public_domain => 1,
bsd3 => 1,
bsd2 => 1,
@@ -56,6 +58,17 @@ my $known_licences = {
isc => 1,
},
},
+ gpl2_or_later_or_ubdl => {
+ desc => ( "GPL version 2 (or, at your option, any later version) or ".
+ "Unmodified Binary Distribution Licence" ),
+ can_subsume => {
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
public_domain => {
desc => "Public Domain",
can_subsume => {},
diff --git a/qemu/roms/ipxe/src/util/parserom.pl b/qemu/roms/ipxe/src/util/parserom.pl
index e278e6336..28df60652 100755
--- a/qemu/roms/ipxe/src/util/parserom.pl
+++ b/qemu/roms/ipxe/src/util/parserom.pl
@@ -1,66 +1,260 @@
#!/usr/bin/env perl
#
-# Parse PCI_ROM and ISA_ROM entries from a source file on stdin and
-# output the relevant Makefile variable definitions to stdout
+# Parse PCI_ROM and ISA_ROM entries from source file(s) specified as
+# arguments and output the relevant Makefile rules to STDOUT.
#
-# Based upon portions of Ken Yap's genrules.pl
+# Originally based on portions of Ken Yap's genrules.pl. Completely
+# rewritten by Robin Smidsrød to be more maintainable.
use strict;
use warnings;
+use Getopt::Long;
-die "Syntax: $0 driver_source.c" unless @ARGV == 1;
-my $source = shift;
-open DRV, "<$source" or die "Could not open $source: $!\n";
+# Parse command-line options
+my @exclude_driver_classes = ();
+my @exclude_drivers = ();
+my $debug = 0;
+my $help = 0;
+GetOptions(
+ "exclude-driver-class=s" => \@exclude_driver_classes,
+ "exclude-driver=s" => \@exclude_drivers,
+ "debug" => \$debug,
+ "help" => \$help,
+);
-( my $family, my $driver_name ) = ( $source =~ /^(.*?([^\/]+))\..$/ )
- or die "Could not parse source file name \"$source\"\n";
+# Convert exclution arrays to lookup tables
+my $exclude_driver_class_map = { map { $_ => 1 } @exclude_driver_classes };
+my $exclude_driver_map = { map { $_ => 1 } @exclude_drivers };
-my $printed_family;
+# Ensure STDOUT and STDERR are synchronized if debugging
+if ( $debug ) {
+ STDOUT->autoflush(1);
+ STDERR->autoflush(1);
+}
+
+# Compile regular expressions here for slight performance boost
+my %RE = (
+ 'parse_driver_class' => qr{ drivers/ (\w+?) / }x,
+ 'parse_family' => qr{^ (?:\./)? (.*) \..+? $}x,
+ 'find_rom_line' => qr/^ \s* ( (PCI|ISA)_ROM \s* \( \s* (.*?) ) $/x,
+ 'extract_pci_id' => qr/^ \s* 0x([0-9A-Fa-f]{4}) \s* ,? \s* (.*) $/x,
+ 'extract_quoted_string' => qr/^ \s* \" ([^\"]*?) \" \s* ,? \s* (.*) $/x,
+);
+
+# Show help if required arguments are missing or help was requested
+show_usage_and_exit() if $help or @ARGV < 1;
+
+# Process each source file specified
+process_source_file($_) for @ARGV;
+
+exit;
+
+sub show_usage_and_exit {
+ print STDERR <<"EOM";
+Syntax: $0 [<options>] <source-file> [<source-file>]
+Options:
+ --exclude-driver-class Exclude specified driver classes
+ --exclude-driver Exclude specified drivers
+ --debug Output debug information on STDERR
+ --help This help information
+EOM
+ exit 1;
+}
+
+# Figure out if source file is a driver and look for ROM declarations
+sub process_source_file {
+ my ($source_file) = @_;
+ return unless defined $source_file;
+ return unless length $source_file;
+ my $state = { 'source_file' => $source_file };
+ log_debug("SOURCE_FILE", $state->{source_file});
+ # Skip source files that aren't drivers
+ parse_driver_class( $state );
+ unless ( $state->{'driver_class'} ) {
+ log_debug("SKIP_NOT_DRIVER", $state->{source_file} );
+ return;
+ }
+ # Skip source files with driver classes that are explicitly excluded
+ if ( $exclude_driver_class_map->{ $state->{'driver_class'} } ) {
+ log_debug("SKIP_EXCL_CLASS", $state->{'driver_class'} );
+ return;
+ }
+ # Skip source files without driver information
+ parse_family( $state );
+ parse_driver_name( $state );
+ unless ( $state->{'family'} and $state->{'driver_name'} ) {
+ log_debug("SKIP_NO_DRV_INFO", $state->{source_file} );
+ return;
+ }
+ # Skip source files with drivers that are explicitly excluded
+ if ( $exclude_driver_map->{ $state->{'driver_name'} } ) {
+ log_debug("SKIP_EXCL_DRV", $state->{'driver_name'} );
+ return;
+ }
+ # Iterate through lines in source files looking for ROM declarations
+ # and # output Makefile rules
+ open( my $fh, "<", $state->{'source_file'} )
+ or die "Couldn't open $state->{source_file}: $!\n";
+ while (<$fh>) {
+ process_rom_decl($state, $1, $2, $3) if m/$RE{find_rom_line}/;
+ }
+ close($fh) or die "Couldn't close $source_file: $!\n";
+ return 1;
+}
+
+# Verify that the found ROM declaration is sane and dispatch to the right
+# handler depending on type
+sub process_rom_decl {
+ my ($state, $rom_line, $rom_type, $rom_decl) = @_;
+ return unless defined $rom_line;
+ return unless length $rom_line;
+ log_debug("ROM_LINE", $rom_line);
+ return unless defined $rom_type;
+ return unless length $rom_type;
+ log_debug("ROM_TYPE", $rom_type);
+ $state->{'type'} = lc $rom_type;
+ return process_pci_rom($state, $rom_decl) if $rom_type eq "PCI";
+ return process_isa_rom($state, $rom_decl) if $rom_type eq "ISA";
+ return;
+}
+
+# Extract values from PCI_ROM declaration lines and dispatch to
+# Makefile rule generator
+sub process_pci_rom {
+ my ($state, $decl) = @_;
+ return unless defined $decl;
+ return unless length $decl;
+ (my $vendor, $decl) = extract_pci_id($decl, 'PCI_VENDOR');
+ (my $device, $decl) = extract_pci_id($decl, 'PCI_DEVICE');
+ (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
+ (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
+ if ( $vendor and $device and $image and $desc ) {
+ print_make_rules( $state, "${vendor}${device}", $desc, $vendor, $device );
+ print_make_rules( $state, $image, $desc, $vendor, $device, 1 );
+ }
+ else {
+ log_debug("WARNING", "Malformed PCI_ROM macro on line $. of $state->{source_file}");
+ }
+ return 1;
+}
+
+# Extract values from ISA_ROM declaration lines and dispatch to
+# Makefile rule generator
+sub process_isa_rom {
+ my ($state, $decl) = @_;
+ return unless defined $decl;
+ return unless length $decl;
+ (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
+ (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
+ if ( $image and $desc ) {
+ print_make_rules( $state, $image, $desc );
+ }
+ else {
+ log_debug("WARNING", "Malformed ISA_ROM macro on line $. of $state->{source_file}");
+ }
+ return 1;
+}
-sub rom {
- ( my $type, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
- my $ids = $vendor ? "$vendor,$device" : "-";
- unless ( $printed_family ) {
+# Output Makefile rules for the specified ROM declarations
+sub print_make_rules {
+ my ( $state, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
+ unless ( $state->{'is_header_printed'} ) {
+ print "# NIC\t\n";
+ print "# NIC\tfamily\t$state->{family}\n";
+ print "DRIVERS_$state->{driver_class} += $state->{driver_name}\n";
+ print "DRIVERS += $state->{driver_name}\n";
+ print "\n";
+ $state->{'is_header_printed'} = 1;
+ }
+ return if $vendor and ( $vendor eq "ffff" or $device eq "ffff" );
+ my $ids = $vendor ? "$vendor,$device" : "-";
+ print "# NIC\t$image\t$ids\t$desc\n";
+ print "DRIVER_$image = $state->{driver_name}\n";
+ print "ROM_TYPE_$image = $state->{type}\n";
+ print "ROM_DESCRIPTION_$image = \"$desc\"\n";
+ print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
+ print "PCI_DEVICE_$image = 0x$device\n" if $device;
+ print "ROMS += $image\n" unless $dup;
+ print "ROMS_$state->{driver_name} += $image\n" unless $dup;
print "\n";
- print "# NIC\t\n";
- print "# NIC\tfamily\t$family\n";
- print "DRIVERS += $driver_name\n";
- $printed_family = 1;
- }
- print "\n";
- return if ( $vendor && ( ( $vendor eq "ffff" ) || ( $device eq "ffff" ) ) );
- print "# NIC\t$image\t$ids\t$desc\n";
- print "DRIVER_$image = $driver_name\n";
- print "ROM_TYPE_$image = $type\n";
- print "ROM_DESCRIPTION_$image = \"$desc\"\n";
- print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
- print "PCI_DEVICE_$image = 0x$device\n" if $device;
- print "ROMS += $image\n" unless $dup;
- print "ROMS_$driver_name += $image\n" unless $dup;
+ return 1;
+}
+
+# Driver class is whatever comes after the "drivers" part of the filename (relative path)
+sub parse_driver_class {
+ my ($state) = @_;
+ my $filename = $state->{'source_file'};
+ return unless defined $filename;
+ return unless length $filename;
+ if ( $filename =~ m/$RE{parse_driver_class}/ ) {
+ log_debug("DRIVER_CLASS", $1);
+ $state->{'driver_class'} = $1;
+ }
+ return;
+}
+
+# Family name is filename (relative path) without extension
+sub parse_family {
+ my ($state) = @_;
+ my $filename = $state->{'source_file'};
+ return unless defined $filename;
+ return unless length $filename;
+ if ( $filename =~ m/$RE{parse_family}/ ) {
+ log_debug("FAMILY", $1);
+ $state->{'family'} = $1;
+ }
+ return;
+}
+
+# Driver name is last part of family name
+sub parse_driver_name {
+ my ($state) = @_;
+ my $family = $state->{'family'};
+ return unless defined $family;
+ return unless length $family;
+ my @parts = split "/", $family;
+ $state->{'driver_name'} = $parts[-1];
+ log_debug("DRIVER", $state->{'driver_name'});
+ return;
}
-while ( <DRV> ) {
- next unless /(PCI|ISA)_ROM\s*\(/;
-
- if ( /^\s*PCI_ROM\s*\(
- \s*0x([0-9A-Fa-f]{4})\s*, # PCI vendor
- \s*0x([0-9A-Fa-f]{4})\s*, # PCI device
- \s*\"([^\"]*)\"\s*, # Image
- \s*\"([^\"]*)\"\s*, # Description
- \s*.*\s* # Driver data
- \)/x ) {
- ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 );
- rom ( "pci", lc "${vendor}${device}", $desc, $vendor, $device );
- rom ( "pci", $image, $desc, $vendor, $device, 1 );
- } elsif ( /^\s*ISA_ROM\s*\(
- \s*\"([^\"]*)\"\s*, # Image
- \s*\"([^\"]*)\"\s* # Description
- \)/x ) {
- ( my $image, my $desc ) = ( $1, $2 );
- rom ( "isa", $image, $desc );
- } else {
- warn "Malformed PCI_ROM or ISA_ROM macro on line $. of $source\n";
- }
+# Extract a PCI vendor/device ID e.g. 0x8086, possibly followed by a comma
+# Should always be 4-digit lower-case hex number
+sub extract_pci_id {
+ my ($str, $label) = @_;
+ return "", $str unless defined $str;
+ return "", $str unless length $str;
+ if ( $str =~ m/$RE{extract_pci_id}/ ) {
+ my $id = lc $1;
+ log_debug($label, $id);
+ return $id, $2;
+ }
+ return "", $str;
}
-close DRV;
+# Extract a double-quoted string, possibly followed by a comma
+sub extract_quoted_string {
+ my ($str, $label) = @_;
+ return "", $str unless defined $str;
+ return "", $str unless length $str;
+ if ( $str =~ m/$RE{extract_quoted_string}/ ) {
+ log_debug($label, $1);
+ return $1, $2;
+ }
+ return "", $str;
+}
+
+# Output debug info to STDERR (off by default)
+sub log_debug {
+ my ($label, $str) = @_;
+ return unless $debug;
+ return unless defined $str;
+ print STDERR "\n" if $label eq 'SOURCE_FILE';
+ print STDERR "=";
+ if ( defined $label ) {
+ my $pad_count = 16 - length $label;
+ print STDERR $label . ":" . ( " " x $pad_count );
+ }
+ print STDERR $str . "\n";
+ return;
+}
diff --git a/qemu/roms/ipxe/src/util/relicense.pl b/qemu/roms/ipxe/src/util/relicense.pl
new file mode 100755
index 000000000..41954c1b3
--- /dev/null
+++ b/qemu/roms/ipxe/src/util/relicense.pl
@@ -0,0 +1,169 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+relicense.pl
+
+=head1 SYNOPSIS
+
+relicense.pl [options] -p <permissions file> <file> [<file>...]
+
+Option:
+
+ -p,--permitted=FILE Specify file of emails with relicensing permission
+ -f,--force Manually force relicensing
+ -h,--help Display brief help message
+ -v,--verbose Increase verbosity
+ -q,--quiet Decrease verbosity
+
+=cut
+
+use File::Slurp;
+use IPC::Run qw ( run );
+use Getopt::Long;
+use Pod::Usage;
+use strict;
+use warnings;
+
+# Parse command-line options
+my $verbosity = 0;
+my $permfile;
+my $force;
+Getopt::Long::Configure ( "bundling", "auto_abbrev" );
+GetOptions (
+ 'permitted|p=s' => \$permfile,
+ 'force|f' => \$force,
+ 'verbose|v+' => sub { $verbosity++; },
+ 'quiet|q+' => sub { $verbosity--; },
+ 'help|h' => sub { pod2usage ( 1 ); },
+) or die "Could not parse command-line options";
+pod2usage ( 1 ) unless @ARGV;
+
+# Read permitted emails file
+my @emails = ( $permfile ? read_file ( $permfile ) : () );
+chomp @emails;
+my $permitted = { map { /^.*<(\S+)>$/; ( $1 || $_ ) => 1 } @emails };
+
+# Define list of relicensable licences
+my $relicensable = {
+ GPL2_OR_LATER => 1,
+};
+
+# Define blurb to be added to copyright notice
+my $blurb = '
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.';
+
+# Process files
+my @succeeded;
+my @failed;
+while ( my $filename = shift @ARGV ) {
+
+ # Read file to determine existing licence
+ my $file = read_file ( $filename );
+ my @licences = ( $file =~ /^\s*FILE_LICENCE\s*\(\s*(\S+)\s*\)\s*;?$/mg );
+ die "No licence declaration in $filename\n" unless @licences;
+ die "Multiple licence declarations in $filename\n" if @licences > 1;
+ my $licence = $licences[0];
+
+ # Skip if file is already UBDL-licensed
+ next if $licence =~ /_OR_UBDL$/;
+
+ # Fail immediately if file is not a candidate for relicensing
+ if ( ! exists $relicensable->{$licence} ) {
+ print "Non-relicensable licence $licence in $filename\n";
+ push @failed, $filename;
+ next;
+ }
+
+ # Run git-blame
+ my $stdout;
+ my $stderr;
+ run [ "git", "blame", "-M", "-C", "-p", "-w", $filename ],
+ \undef, \$stdout, \$stderr
+ or die "git-blame $filename: $?";
+ die $stderr if $stderr;
+
+ # Process output
+ my @stdout = split ( /\n/, $stdout );
+ chomp @stdout;
+ my $details = {};
+ my $failures = 0;
+ while ( @stdout ) {
+
+ # Parse output
+ my $commit_line = shift @stdout;
+ ( my $commit, undef, my $lineno, undef, my $count ) =
+ ( $commit_line =~
+ /^([0-9a-f]{40})\s+([0-9]+)\s+([0-9]+)(\s+([0-9]+))?$/ )
+ or die "Malformed commit line \"$commit_line\"\n";
+ if ( $count ) {
+ $details->{$commit} ||= {};
+ while ( ! ( $stdout[0] =~ /^\t/ ) ) {
+ my $detail_line = shift @stdout;
+ ( my $key, undef, my $value ) =
+ ( $detail_line =~ /^([a-z-]+)(\s+(.+))?$/ )
+ or die "Malformed detail line \"$detail_line\" for $commit_line\n";
+ $details->{$commit}->{$key} = $value;
+ }
+ }
+ die "Missing commit details for $commit_line\n"
+ unless %{$details->{$commit}};
+ my $code_line = shift @stdout;
+ ( my $line ) = ( $code_line =~ /^\t(.*)$/ )
+ or die "Malformed code line \"$code_line\" for $commit_line\n";
+
+ # Skip trivial lines and lines so common that they are likely to
+ # be misattributed by git-blame
+ next if $line =~ /^\s*$/; # Empty lines
+ next if $line =~ /^\s*\/\*/; # Start of comments
+ next if $line =~ /^\s*\*/; # Middle (or end) of comments
+ next if $line =~ /^\s*\{\s*$/; # Standalone opening braces
+ next if $line =~ /^\s*\};?\s*$/; # Standalone closing braces
+ next if $line =~ /^\#include/; # Header inclusions
+ next if $line =~ /^\s*return\s+0;/; # return 0;
+ next if $line =~ /^\s*return\s+rc;/; # return rc;
+ next if $line =~ /^\s*PCI_ROM\s*\(.*\)\s*,\s*$/; # PCI IDs
+ next if $line =~ /^\s*FILE_LICENCE\s*\(.*\)\s*;$/; # Licence declarations
+
+ # Identify author
+ my $author_mail = $details->{$commit}->{"author-mail"}
+ or die "Missing author email for $commit_line\n";
+ ( my $email ) = ( $author_mail =~ /^<(\S+)>$/ )
+ or die "Malformed author email \"$author_mail\" for $commit_line\n";
+ undef $email if exists $details->{$commit}->{boundary};
+
+ # Check for relicensing permission
+ next if defined $email && exists $permitted->{$email};
+
+ # Print out lines lacking permission
+ printf $filename."\n" unless $failures;
+ printf "%4d %-30s %s\n", $lineno, ( $email || "<root>" ), $line;
+ $failures++;
+ }
+
+ # Fail if there are any non-trivial lines lacking relicensing permission
+ if ( $failures && ! $force ) {
+ push @failed, $filename;
+ next;
+ }
+
+ # Modify FILE_LICENCE() line
+ $file =~ s/(^\s*FILE_LICENCE\s*\(\s*${licence})(\s*\)\s*;?$)/$1_OR_UBDL$2/m
+ or die "Could not modify FILE_LICENCE() in $filename\n";
+
+ # Modify copyright notice, if present
+ if ( $file =~ /GNU General Public License/i ) {
+ $file =~ s/(02110-1301, USA.$)/$1${blurb}/m
+ or die "Could not modify copyright notice in $filename\n";
+ }
+
+ # Write out modified file
+ write_file ( $filename, { atomic => 1 }, $file );
+ push @succeeded, $filename;
+}
+
+print "Relicensed: ".join ( " ", @succeeded )."\n" if @succeeded;
+die "Cannot relicense: ".join ( " ", @failed )."\n" if @failed;
diff --git a/qemu/roms/ipxe/src/util/zbin.c b/qemu/roms/ipxe/src/util/zbin.c
index 3b7cf95b3..1862a3827 100644
--- a/qemu/roms/ipxe/src/util/zbin.c
+++ b/qemu/roms/ipxe/src/util/zbin.c
@@ -1,13 +1,21 @@
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include <sys/stat.h>
-
-#define ENCODE
-#define VERBOSE
-#include "nrv2b.c"
-FILE *infile, *outfile;
+#include <lzma.h>
#define DEBUG 0
+/* LZMA filter choices. Must match those used by unlzma.S */
+#define LZMA_LC 2
+#define LZMA_LP 0
+#define LZMA_PB 0
+
+/* LZMA preset choice. This is a policy decision */
+#define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
+
struct input_file {
void *buf;
size_t len;
@@ -177,13 +185,75 @@ static int process_zinfo_copy ( struct input_file *input,
return 0;
}
+#define OPCODE_CALL 0xe8
+#define OPCODE_JMP 0xe9
+
+static void bcj_filter ( void *data, size_t len ) {
+ struct {
+ uint8_t opcode;
+ int32_t target;
+ } __attribute__ (( packed )) *jump;
+ ssize_t limit = ( len - sizeof ( *jump ) );
+ ssize_t offset;
+
+ /* liblzma does include an x86 BCJ filter, but it's hideously
+ * convoluted and undocumented. This BCJ filter is
+ * substantially simpler and achieves the same compression (at
+ * the cost of requiring the decompressor to know the size of
+ * the decompressed data, which we already have in iPXE).
+ */
+ for ( offset = 0 ; offset <= limit ; offset++ ) {
+ jump = ( data + offset );
+
+ /* Skip instructions that are not followed by a rel32 address */
+ if ( ( jump->opcode != OPCODE_CALL ) &&
+ ( jump->opcode != OPCODE_JMP ) )
+ continue;
+
+ /* Convert rel32 address to an absolute address. To
+ * avoid false positives (which damage the compression
+ * ratio), we should check that the jump target is
+ * within the range [0,limit).
+ *
+ * Some output values would then end up being mapped
+ * from two distinct input values, making the
+ * transformation irreversible. To solve this, we
+ * transform such values back into the part of the
+ * range which would otherwise correspond to no input
+ * values.
+ */
+ if ( ( jump->target >= -offset ) &&
+ ( jump->target < ( limit - offset ) ) ) {
+ /* Convert relative addresses in the range
+ * [-offset,limit-offset) to absolute
+ * addresses in the range [0,limit).
+ */
+ jump->target += offset;
+ } else if ( ( jump->target >= ( limit - offset ) ) &&
+ ( jump->target < limit ) ) {
+ /* Convert positive numbers in the range
+ * [limit-offset,limit) to negative numbers in
+ * the range [-offset,0).
+ */
+ jump->target -= limit;
+ }
+ offset += sizeof ( jump->target );
+ };
+}
+
static int process_zinfo_pack ( struct input_file *input,
struct output_file *output,
union zinfo_record *zinfo ) {
struct zinfo_pack *pack = &zinfo->pack;
size_t offset = pack->offset;
size_t len = pack->len;
- unsigned long packed_len;
+ size_t packed_len = 0;
+ size_t remaining = ( output->max_len - output->len );
+ lzma_options_lzma options;
+ const lzma_filter filters[] = {
+ { .id = LZMA_FILTER_LZMA1, .options = &options },
+ { .id = LZMA_VLI_UNKNOWN }
+ };
if ( ( offset + len ) > input->len ) {
fprintf ( stderr, "Input buffer overrun on pack\n" );
@@ -196,9 +266,15 @@ static int process_zinfo_pack ( struct input_file *input,
return -1;
}
- if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
- ( output->buf + output->len ),
- &packed_len, 0 ) != UCL_E_OK ) {
+ bcj_filter ( ( input->buf + offset ), len );
+
+ lzma_lzma_preset ( &options, LZMA_PRESET );
+ options.lc = LZMA_LC;
+ options.lp = LZMA_LP;
+ options.pb = LZMA_PB;
+ if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
+ len, ( output->buf + output->len ),
+ &packed_len, remaining ) != LZMA_OK ) {
fprintf ( stderr, "Compression failure\n" );
return -1;
}
@@ -206,7 +282,7 @@ static int process_zinfo_pack ( struct input_file *input,
if ( DEBUG ) {
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
offset, ( offset + len ), output->len,
- ( size_t )( output->len + packed_len ) );
+ ( output->len + packed_len ) );
}
output->len += packed_len;