summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/gpxe/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/util')
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/.gitignore8
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/Makefile22
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/Option/ROM.pm501
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/catrom.pl48
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/diffsize.pl101
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/disrom.pl81
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/efirom.c280
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/elf2efi.c808
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/geniso55
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/genliso74
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/gensdsk65
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/get-pci-ids135
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/hijack.c628
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/iccfix.c156
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/licence.pl149
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/makerom.pl232
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/mergerom.pl98
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/modrom.pl226
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/mucurses_test.c63
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/nrv2b.c1501
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/padimg.pl44
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/parserom.pl65
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/sortobjdump.pl40
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/swapdevids.pl49
-rwxr-xr-xcontrib/syslinux-4.02/gpxe/src/util/symcheck.pl191
-rw-r--r--contrib/syslinux-4.02/gpxe/src/util/zbin.c383
26 files changed, 6003 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/util/.gitignore b/contrib/syslinux-4.02/gpxe/src/util/.gitignore
new file mode 100644
index 0000000..a375247
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/.gitignore
@@ -0,0 +1,8 @@
+nrv2b
+zbin
+hijack
+prototester
+elf2efi32
+elf2efi64
+efirom
+iccfix
diff --git a/contrib/syslinux-4.02/gpxe/src/util/Makefile b/contrib/syslinux-4.02/gpxe/src/util/Makefile
new file mode 100644
index 0000000..d72661e
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/Makefile
@@ -0,0 +1,22 @@
+BLIB = ../bin/blib.a
+CFLAGS = -Os
+
+all : hijack prototester mucurses_test
+
+hijack : hijack.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -lpcap -o $@ $<
+
+prototester.o : prototester.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $< -idirafter ../include
+
+prototester : prototester.o $(BLIB)
+ $(CC) -o $@ $< -lc $(BLIB)
+
+mucurses_test.o : mucurses_test.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $<
+
+mucurses_test : mucurses_test.o $(BLIB)
+ $(CC) -o $@ $< -lc $(BLIB)
+
+clean :
+ rm -f hijack prototester mucurses_test *.o
diff --git a/contrib/syslinux-4.02/gpxe/src/util/Option/ROM.pm b/contrib/syslinux-4.02/gpxe/src/util/Option/ROM.pm
new file mode 100644
index 0000000..a86d326
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/Option/ROM.pm
@@ -0,0 +1,501 @@
+package Option::ROM;
+
+# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=head1 NAME
+
+Option::ROM - Option ROM manipulation
+
+=head1 SYNOPSIS
+
+ use Option::ROM;
+
+ # Load a ROM image
+ my $rom = new Option::ROM;
+ $rom->load ( "rtl8139.rom" );
+
+ # Modify the PCI device ID
+ $rom->pci_header->{device_id} = 0x1234;
+ $rom->fix_checksum();
+
+ # Write ROM image out to a new file
+ $rom->save ( "rtl8139-modified.rom" );
+
+=head1 DESCRIPTION
+
+C<Option::ROM> provides a mechanism for manipulating Option ROM
+images.
+
+=head1 METHODS
+
+=cut
+
+##############################################################################
+#
+# Option::ROM::Fields
+#
+##############################################################################
+
+package Option::ROM::Fields;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub TIEHASH {
+ my $class = shift;
+ my $self = shift;
+
+ bless $self, $class;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my $key = shift;
+
+ return undef unless $self->EXISTS ( $key );
+ my $raw = substr ( ${$self->{data}},
+ ( $self->{offset} + $self->{fields}->{$key}->{offset} ),
+ $self->{fields}->{$key}->{length} );
+ my $unpack = ( ref $self->{fields}->{$key}->{unpack} ?
+ $self->{fields}->{$key}->{unpack} :
+ sub { unpack ( $self->{fields}->{$key}->{pack}, shift ); } );
+ return &$unpack ( $raw );
+}
+
+sub STORE {
+ my $self = shift;
+ my $key = shift;
+ my $value = shift;
+
+ croak "Nonexistent field \"$key\"" unless $self->EXISTS ( $key );
+ my $pack = ( ref $self->{fields}->{$key}->{pack} ?
+ $self->{fields}->{$key}->{pack} :
+ sub { pack ( $self->{fields}->{$key}->{pack}, shift ); } );
+ my $raw = &$pack ( $value );
+ substr ( ${$self->{data}},
+ ( $self->{offset} + $self->{fields}->{$key}->{offset} ),
+ $self->{fields}->{$key}->{length} ) = $raw;
+}
+
+sub DELETE {
+ my $self = shift;
+ my $key = shift;
+
+ $self->STORE ( $key, 0 );
+}
+
+sub CLEAR {
+ my $self = shift;
+
+ foreach my $key ( keys %{$self->{fields}} ) {
+ $self->DELETE ( $key );
+ }
+}
+
+sub EXISTS {
+ my $self = shift;
+ my $key = shift;
+
+ return ( exists $self->{fields}->{$key} &&
+ ( ( $self->{fields}->{$key}->{offset} +
+ $self->{fields}->{$key}->{length} ) <= $self->{length} ) );
+}
+
+sub FIRSTKEY {
+ my $self = shift;
+
+ keys %{$self->{fields}};
+ return each %{$self->{fields}};
+}
+
+sub NEXTKEY {
+ my $self = shift;
+ my $lastkey = shift;
+
+ return each %{$self->{fields}};
+}
+
+sub SCALAR {
+ my $self = shift;
+
+ return 1;
+}
+
+sub UNTIE {
+ my $self = shift;
+}
+
+sub DESTROY {
+ my $self = shift;
+}
+
+sub checksum {
+ my $self = shift;
+
+ my $raw = substr ( ${$self->{data}}, $self->{offset}, $self->{length} );
+ return unpack ( "%8C*", $raw );
+}
+
+##############################################################################
+#
+# Option::ROM
+#
+##############################################################################
+
+package Option::ROM;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+use Exporter 'import';
+
+use constant ROM_SIGNATURE => 0xaa55;
+use constant PCI_SIGNATURE => 'PCIR';
+use constant PNP_SIGNATURE => '$PnP';
+
+our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PNP_SIGNATURE );
+our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
+
+use constant JMP_SHORT => 0xeb;
+use constant JMP_NEAR => 0xe9;
+
+sub pack_init {
+ my $dest = shift;
+
+ # Always create a near jump; it's simpler
+ if ( $dest ) {
+ return pack ( "CS", JMP_NEAR, ( $dest - 6 ) );
+ } else {
+ return pack ( "CS", 0, 0 );
+ }
+}
+
+sub unpack_init {
+ my $instr = shift;
+
+ # Accept both short and near jumps
+ my $jump = unpack ( "C", $instr );
+ if ( $jump == JMP_SHORT ) {
+ my $offset = unpack ( "xC", $instr );
+ return ( $offset + 5 );
+ } elsif ( $jump == JMP_NEAR ) {
+ my $offset = unpack ( "xS", $instr );
+ return ( $offset + 6 );
+ } elsif ( $jump == 0 ) {
+ return 0;
+ } else {
+ croak "Unrecognised jump instruction in init vector\n";
+ }
+}
+
+=pod
+
+=item C<< new () >>
+
+Construct a new C<Option::ROM> object.
+
+=cut
+
+sub new {
+ my $class = shift;
+
+ my $hash = {};
+ tie %$hash, "Option::ROM::Fields", {
+ data => undef,
+ offset => 0x00,
+ length => 0x20,
+ fields => {
+ signature => { offset => 0x00, length => 0x02, pack => "S" },
+ length => { offset => 0x02, length => 0x01, pack => "C" },
+ # "init" is part of a jump instruction
+ init => { offset => 0x03, length => 0x03,
+ pack => \&pack_init, unpack => \&unpack_init },
+ checksum => { offset => 0x06, length => 0x01, pack => "C" },
+ bofm_header => { offset => 0x14, length => 0x02, pack => "S" },
+ undi_header => { offset => 0x16, length => 0x02, pack => "S" },
+ pci_header => { offset => 0x18, length => 0x02, pack => "S" },
+ pnp_header => { offset => 0x1a, length => 0x02, pack => "S" },
+ },
+ };
+ bless $hash, $class;
+ return $hash;
+}
+
+=pod
+
+=item C<< load ( $filename ) >>
+
+Load option ROM contents from the file C<$filename>.
+
+=cut
+
+sub load {
+ my $hash = shift;
+ my $self = tied(%$hash);
+ my $filename = shift;
+
+ $self->{filename} = $filename;
+
+ open my $fh, "<$filename"
+ or croak "Cannot open $filename for reading: $!";
+ read $fh, my $data, ( 128 * 1024 ); # 128kB is theoretical max size
+ $self->{data} = \$data;
+ close $fh;
+}
+
+=pod
+
+=item C<< save ( [ $filename ] ) >>
+
+Write the ROM data back out to the file C<$filename>. If C<$filename>
+is omitted, the file used in the call to C<load()> will be used.
+
+=cut
+
+sub save {
+ my $hash = shift;
+ my $self = tied(%$hash);
+ my $filename = shift;
+
+ $filename ||= $self->{filename};
+
+ open my $fh, ">$filename"
+ or croak "Cannot open $filename for writing: $!";
+ print $fh ${$self->{data}};
+ close $fh;
+}
+
+=pod
+
+=item C<< length () >>
+
+Length of option ROM data. This is the length of the file, not the
+length from the ROM header length field.
+
+=cut
+
+sub length {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ return length ${$self->{data}};
+}
+
+=pod
+
+=item C<< pci_header () >>
+
+Return a C<Option::ROM::PCI> object representing the ROM's PCI header,
+if present.
+
+=cut
+
+sub pci_header {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $offset = $hash->{pci_header};
+ return undef unless $offset != 0;
+
+ return Option::ROM::PCI->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< pnp_header () >>
+
+Return a C<Option::ROM::PnP> object representing the ROM's PnP header,
+if present.
+
+=cut
+
+sub pnp_header {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $offset = $hash->{pnp_header};
+ return undef unless $offset != 0;
+
+ return Option::ROM::PnP->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< checksum () >>
+
+Calculate the byte checksum of the ROM.
+
+=cut
+
+sub checksum {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ return unpack ( "%8C*", ${$self->{data}} );
+}
+
+=pod
+
+=item C<< fix_checksum () >>
+
+Fix the byte checksum of the ROM.
+
+=cut
+
+sub fix_checksum {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
+##############################################################################
+#
+# Option::ROM::PCI
+#
+##############################################################################
+
+package Option::ROM::PCI;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+ my $class = shift;
+ my $data = shift;
+ my $offset = shift;
+
+ my $hash = {};
+ tie %$hash, "Option::ROM::Fields", {
+ data => $data,
+ offset => $offset,
+ length => 0x0c,
+ fields => {
+ signature => { offset => 0x00, length => 0x04, pack => "a4" },
+ vendor_id => { offset => 0x04, length => 0x02, pack => "S" },
+ device_id => { offset => 0x06, length => 0x02, pack => "S" },
+ device_list => { offset => 0x08, length => 0x02, pack => "S" },
+ struct_length => { offset => 0x0a, length => 0x02, pack => "S" },
+ struct_revision =>{ offset => 0x0c, length => 0x01, pack => "C" },
+ base_class => { offset => 0x0d, length => 0x01, pack => "C" },
+ sub_class => { offset => 0x0e, length => 0x01, pack => "C" },
+ prog_intf => { offset => 0x0f, length => 0x01, pack => "C" },
+ image_length => { offset => 0x10, length => 0x02, pack => "S" },
+ revision => { offset => 0x12, length => 0x02, pack => "S" },
+ code_type => { offset => 0x14, length => 0x01, pack => "C" },
+ last_image => { offset => 0x15, length => 0x01, pack => "C" },
+ runtime_length => { offset => 0x16, length => 0x02, pack => "S" },
+ conf_header => { offset => 0x18, length => 0x02, pack => "S" },
+ clp_entry => { offset => 0x1a, length => 0x02, pack => "S" },
+ },
+ };
+ bless $hash, $class;
+
+ # Retrieve true length of structure
+ my $self = tied ( %$hash );
+ $self->{length} = $hash->{struct_length};
+
+ return $hash;
+}
+
+##############################################################################
+#
+# Option::ROM::PnP
+#
+##############################################################################
+
+package Option::ROM::PnP;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+ my $class = shift;
+ my $data = shift;
+ my $offset = shift;
+
+ my $hash = {};
+ tie %$hash, "Option::ROM::Fields", {
+ data => $data,
+ offset => $offset,
+ length => 0x06,
+ fields => {
+ signature => { offset => 0x00, length => 0x04, pack => "a4" },
+ struct_revision =>{ offset => 0x04, length => 0x01, pack => "C" },
+ struct_length => { offset => 0x05, length => 0x01, pack => "C" },
+ checksum => { offset => 0x09, length => 0x01, pack => "C" },
+ manufacturer => { offset => 0x0e, length => 0x02, pack => "S" },
+ product => { offset => 0x10, length => 0x02, pack => "S" },
+ bcv => { offset => 0x16, length => 0x02, pack => "S" },
+ bdv => { offset => 0x18, length => 0x02, pack => "S" },
+ bev => { offset => 0x1a, length => 0x02, pack => "S" },
+ },
+ };
+ bless $hash, $class;
+
+ # Retrieve true length of structure
+ my $self = tied ( %$hash );
+ $self->{length} = ( $hash->{struct_length} * 16 );
+
+ return $hash;
+}
+
+sub checksum {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ return $self->checksum();
+}
+
+sub fix_checksum {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
+sub manufacturer {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $manufacturer = $hash->{manufacturer};
+ return undef unless $manufacturer;
+
+ my $raw = substr ( ${$self->{data}}, $manufacturer );
+ return unpack ( "Z*", $raw );
+}
+
+sub product {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $product = $hash->{product};
+ return undef unless $product;
+
+ my $raw = substr ( ${$self->{data}}, $product );
+ return unpack ( "Z*", $raw );
+}
+
+1;
diff --git a/contrib/syslinux-4.02/gpxe/src/util/catrom.pl b/contrib/syslinux-4.02/gpxe/src/util/catrom.pl
new file mode 100755
index 0000000..fe37e6b
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/catrom.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+
+use bytes;
+
+use constant MAX_ROM_LEN => 1024*1024;
+use constant PCI_OFF => 0x18;
+use constant INDICATOR_OFF => 0x15;
+
+my $total_len = 0;
+my @romfiles = @ARGV
+ or die "Usage: $0 rom-file-1 rom-file-2 ... > multi-rom-file\n";
+
+while ( my $romfile = shift @romfiles ) {
+ my $last = @romfiles ? 0 : 1;
+
+ open ROM, "<$romfile" or die "Could not open $romfile: $!\n";
+ my $len = read ( ROM, my $romdata, MAX_ROM_LEN )
+ or die "Could not read $romfile: $!\n";
+ close ROM;
+
+ die "$romfile is not a ROM file\n"
+ unless substr ( $romdata, 0, 2 ) eq "\x55\xAA";
+
+ ( my $checklen ) = unpack ( 'C', substr ( $romdata, 2, 1 ) );
+ $checklen *= 512;
+ die "$romfile has incorrect length field $checklen (should be $len)\n"
+ unless $len == $checklen;
+
+ ( my $pci ) = unpack ( 'v', substr ( $romdata, PCI_OFF, 2 ) );
+ die "Invalid PCI offset field in $romfile\n"
+ if $pci >= $len;
+ die "No PCIR signature in $romfile\n"
+ unless substr ( $romdata, $pci, 4 ) eq "PCIR";
+
+ ( my $indicator ) =
+ unpack ( 'C', substr ( $romdata, $pci + INDICATOR_OFF, 1 ) );
+ my $msg = sprintf ( "$romfile: indicator was %02x, ", $indicator );
+ $indicator &= ! ( 1 << 7 );
+ $indicator |= ( $last << 7 );
+ $msg .= sprintf ( "now %02x\n", $indicator );
+ substr ( $romdata, $pci + INDICATOR_OFF, 1 ) = pack ( 'C', $indicator );
+ warn $msg;
+
+ print $romdata;
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/diffsize.pl b/contrib/syslinux-4.02/gpxe/src/util/diffsize.pl
new file mode 100755
index 0000000..d4978c2
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/diffsize.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+# usage:
+# [somebody@somewhere ~/gpxe/src]$ ./util/diffsize.pl [<old rev> [<new rev>]]
+# by default <old rev> is HEAD and <new rev> is the working tree
+
+use strict;
+
+-d "bin" or die "Please run me in the gPXE src directory\n";
+mkdir ".sizes";
+
+my($oldrev, $newrev);
+my($oldname, $newname);
+
+if (@ARGV) {
+ $oldname = shift;
+} else {
+ $oldname = "HEAD";
+}
+
+if (@ARGV) {
+ $newname = shift;
+} else {
+ $newrev = "tree" . time();
+}
+
+$oldrev = `git rev-parse $oldname`;
+chomp $oldrev;
+
+unless (defined $newrev) {
+ $newrev = `git rev-parse $newname`;
+ chomp $newrev;
+}
+
+sub calc_sizes($$) {
+ my($name, $rev) = @_;
+ my $output;
+ my $lastrev;
+ my $stashed = 0;
+ my $res = 0;
+
+ return if -e ".sizes/$rev.sizes";
+
+ if (defined $name) {
+ $output = `git stash`;
+ $stashed = 1 unless $output =~ /No local changes to save/;
+ $lastrev = `git name-rev --name-only HEAD`;
+ system("git checkout $name >/dev/null"); $res ||= $?;
+ }
+
+ system("make -j4 bin/gpxe.lkrn >/dev/null"); $res ||= $?;
+ system("make bin/gpxe.lkrn.sizes > .sizes/$rev.sizes"); $res ||= $?;
+
+ if (defined $name) {
+ system("git checkout $lastrev >/dev/null"); $res ||= $?;
+ system("git stash pop >/dev/null") if $stashed; $res ||= $?;
+ }
+
+ if ($res) {
+ unlink(".sizes/$rev.sizes");
+ die "Error making sizes file\n";
+ }
+}
+
+our %Sizes;
+
+sub save_sizes($$) {
+ my($id, $rev) = @_;
+ my $file = ".sizes/$rev.sizes";
+
+ open SIZES, $file or die "opening $file: $!\n";
+ while (<SIZES>) {
+ my($text, $data, $bss, $total, $hex, $name) = split;
+ $name =~ s|bin/||; $name =~ s|\.o$||;
+
+ # Skip the header and totals lines
+ next if $total =~ /[a-z]/ or $name =~ /TOTALS/;
+
+ # Skip files named with dash, due to old Makefile bug
+ next if $name =~ /-/;
+
+ $Sizes{$name} = {old => 0, new => 0} unless exists $Sizes{$name};
+ $Sizes{$name}{$id} = $total;
+ }
+}
+
+calc_sizes($oldname, $oldrev);
+calc_sizes($newname, $newrev);
+
+save_sizes('old', $oldrev);
+save_sizes('new', $newrev);
+
+my $total = 0;
+
+for (sort keys %Sizes) {
+ my $diff = $Sizes{$_}{new} - $Sizes{$_}{old};
+ if (abs($diff) >= 16) {
+ printf "%12s %+d\n", substr($_, 0, 12), $Sizes{$_}{new} - $Sizes{$_}{old};
+ }
+ $total += $diff;
+}
+printf " TOTAL: %+d\n", $total;
diff --git a/contrib/syslinux-4.02/gpxe/src/util/disrom.pl b/contrib/syslinux-4.02/gpxe/src/util/disrom.pl
new file mode 100755
index 0000000..1fb4cc3
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/disrom.pl
@@ -0,0 +1,81 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
+
+my $romfile = shift || "-";
+my $rom = new Option::ROM;
+$rom->load ( $romfile );
+
+die "Not an option ROM image\n"
+ unless $rom->{signature} == ROM_SIGNATURE;
+
+my $romlength = ( $rom->{length} * 512 );
+my $filelength = $rom->length;
+die "ROM image truncated (is $filelength, should be $romlength)\n"
+ if $filelength < $romlength;
+
+printf "ROM header:\n\n";
+printf " %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 );
+printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum},
+ ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum;
+printf " %-16s 0x%04x\n", "Init:", $rom->{init};
+printf " %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header};
+printf " %-16s 0x%04x\n", "PCI header:", $rom->{pci_header};
+printf " %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header};
+printf "\n";
+
+my $pci = $rom->pci_header();
+if ( $pci ) {
+ printf "PCI header:\n\n";
+ 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};
+ 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:",
+ $pci->{image_length}, ( $pci->{image_length} * 512 );
+ printf " %-16s 0x%04x (%d)\n", "Runtime length:",
+ $pci->{runtime_length}, ( $pci->{runtime_length} * 512 );
+ if ( exists $pci->{conf_header} ) {
+ printf " %-16s 0x%04x\n", "Config header:", $pci->{conf_header};
+ printf " %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry};
+ }
+ printf "\n";
+}
+
+my $pnp = $rom->pnp_header();
+if ( $pnp ) {
+ printf "PnP header:\n\n";
+ printf " %-16s %s\n", "Signature:", $pnp->{signature};
+ printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum},
+ ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum;
+ printf " %-16s 0x%04x \"%s\"\n", "Manufacturer:",
+ $pnp->{manufacturer}, $pnp->manufacturer;
+ printf " %-16s 0x%04x \"%s\"\n", "Product:",
+ $pnp->{product}, $pnp->product;
+ printf " %-16s 0x%04x\n", "BCV:", $pnp->{bcv};
+ printf " %-16s 0x%04x\n", "BDV:", $pnp->{bdv};
+ printf " %-16s 0x%04x\n", "BEV:", $pnp->{bev};
+ printf "\n";
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/efirom.c b/contrib/syslinux-4.02/gpxe/src/util/efirom.c
new file mode 100644
index 0000000..9369db8
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/efirom.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+#include <gpxe/efi/IndustryStandard/Pci22.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+/** Command-line options */
+struct options {
+ uint16_t vendor;
+ uint16_t device;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ eprintf ( "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Get file size
+ *
+ * @v file File
+ * @v len File size
+ */
+static size_t file_size ( FILE *file ) {
+ ssize_t len;
+
+ return len;
+}
+
+/**
+ * Read information from PE headers
+ *
+ * @v pe PE file
+ * @ret machine Machine type
+ * @ret subsystem EFI subsystem
+ */
+static void read_pe_info ( void *pe, uint16_t *machine,
+ uint16_t *subsystem ) {
+ EFI_IMAGE_DOS_HEADER *dos;
+ union {
+ EFI_IMAGE_NT_HEADERS32 nt32;
+ EFI_IMAGE_NT_HEADERS64 nt64;
+ } *nt;
+
+ /* Locate NT header */
+ dos = pe;
+ nt = ( pe + dos->e_lfanew );
+
+ /* Parse out PE information */
+ *machine = nt->nt32.FileHeader.Machine;
+ switch ( *machine ) {
+ case EFI_IMAGE_MACHINE_IA32:
+ *subsystem = nt->nt32.OptionalHeader.Subsystem;
+ break;
+ case EFI_IMAGE_MACHINE_X64:
+ *subsystem = nt->nt64.OptionalHeader.Subsystem;
+ break;
+ default:
+ eprintf ( "Unrecognised machine type %04x\n", *machine );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Convert EFI image to ROM image
+ *
+ * @v pe EFI file
+ * @v rom ROM file
+ */
+static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
+ struct {
+ EFI_PCI_EXPANSION_ROM_HEADER rom;
+ PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
+ uint8_t checksum;
+ } *headers;
+ struct stat pe_stat;
+ size_t pe_size;
+ size_t rom_size;
+ void *buf;
+ void *payload;
+ unsigned int i;
+ uint8_t checksum;
+
+ /* Determine PE file size */
+ if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
+ eprintf ( "Could not stat PE file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+ pe_size = pe_stat.st_size;
+
+ /* Determine ROM file size */
+ rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
+
+ /* Allocate ROM buffer and read in PE file */
+ buf = xmalloc ( rom_size );
+ memset ( buf, 0, rom_size );
+ headers = buf;
+ payload = ( buf + sizeof ( *headers ) );
+ if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
+ eprintf ( "Could not read PE file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Construct ROM header */
+ headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
+ headers->rom.InitializationSize = ( rom_size / 512 );
+ headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
+ read_pe_info ( payload, &headers->rom.EfiMachineType,
+ &headers->rom.EfiSubsystem );
+ headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
+ headers->rom.PcirOffset =
+ offsetof ( typeof ( *headers ), pci );
+ headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
+ headers->pci.VendorId = opts->vendor;
+ headers->pci.DeviceId = opts->device;
+ headers->pci.Length = sizeof ( headers->pci );
+ headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
+ headers->pci.ImageLength = ( rom_size / 512 );
+ headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
+ headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
+
+ /* Fix image checksum */
+ for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
+ checksum += *( ( uint8_t * ) buf + i );
+ headers->checksum -= checksum;
+
+ /* Write out ROM */
+ if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
+ eprintf ( "Could not write ROM file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Print help
+ *
+ * @v program_name Program name
+ */
+static void print_help ( const char *program_name ) {
+ eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] "
+ "infile outfile\n", program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @v opts Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+ struct options *opts ) {
+ char *end;
+ int c;
+
+ while (1) {
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "vendor", required_argument, NULL, 'v' },
+ { "device", required_argument, NULL, 'd' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ( ( c = getopt_long ( argc, argv, "v:d:h",
+ long_options,
+ &option_index ) ) == -1 ) {
+ break;
+ }
+
+ switch ( c ) {
+ case 'v':
+ opts->vendor = strtoul ( optarg, &end, 16 );
+ if ( *end ) {
+ eprintf ( "Invalid vendor \"%s\"\n", optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'd':
+ opts->device = strtoul ( optarg, &end, 16 );
+ if ( *end ) {
+ eprintf ( "Invalid device \"%s\"\n", optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'h':
+ print_help ( argv[0] );
+ exit ( 0 );
+ case '?':
+ default:
+ exit ( 2 );
+ }
+ }
+ return optind;
+}
+
+int main ( int argc, char **argv ) {
+ struct options opts = {
+ };
+ unsigned int infile_index;
+ const char *infile_name;
+ const char *outfile_name;
+ FILE *infile;
+ FILE *outfile;
+
+ /* Parse command-line arguments */
+ infile_index = parse_options ( argc, argv, &opts );
+ if ( argc != ( infile_index + 2 ) ) {
+ print_help ( argv[0] );
+ exit ( 2 );
+ }
+ infile_name = argv[infile_index];
+ outfile_name = argv[infile_index + 1];
+
+ /* Open input and output files */
+ infile = fopen ( infile_name, "r" );
+ if ( ! infile ) {
+ eprintf ( "Could not open %s for reading: %s\n",
+ infile_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ outfile = fopen ( outfile_name, "w" );
+ if ( ! outfile ) {
+ eprintf ( "Could not open %s for writing: %s\n",
+ outfile_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Convert file */
+ make_efi_rom ( infile, outfile, &opts );
+
+ fclose ( outfile );
+ fclose ( infile );
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/elf2efi.c b/contrib/syslinux-4.02/gpxe/src/util/elf2efi.c
new file mode 100644
index 0000000..bb766bd
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/elf2efi.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <bfd.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+#include <libgen.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define EFI_FILE_ALIGN 0x20
+
+struct pe_section {
+ struct pe_section *next;
+ EFI_IMAGE_SECTION_HEADER hdr;
+ uint8_t contents[0];
+};
+
+struct pe_relocs {
+ struct pe_relocs *next;
+ unsigned long start_rva;
+ unsigned int used_relocs;
+ unsigned int total_relocs;
+ uint16_t *relocs;
+};
+
+struct pe_header {
+ EFI_IMAGE_DOS_HEADER dos;
+ uint8_t padding[128];
+#if defined(MDE_CPU_IA32)
+ EFI_IMAGE_NT_HEADERS32 nt;
+#elif defined(MDE_CPU_X64)
+ EFI_IMAGE_NT_HEADERS64 nt;
+#endif
+};
+
+static struct pe_header efi_pe_header = {
+ .dos = {
+ .e_magic = EFI_IMAGE_DOS_SIGNATURE,
+ .e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
+ },
+ .nt = {
+ .Signature = EFI_IMAGE_NT_SIGNATURE,
+ .FileHeader = {
+#if defined(MDE_CPU_IA32)
+ .Machine = EFI_IMAGE_MACHINE_IA32,
+#elif defined(MDE_CPU_X64)
+ .Machine = EFI_IMAGE_MACHINE_X64,
+#endif
+ .TimeDateStamp = 0x10d1a884,
+ .SizeOfOptionalHeader =
+ sizeof ( efi_pe_header.nt.OptionalHeader ),
+ .Characteristics = ( EFI_IMAGE_FILE_DLL |
+#if defined(MDE_CPU_IA32)
+ EFI_IMAGE_FILE_32BIT_MACHINE |
+#endif
+ EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
+ },
+ .OptionalHeader = {
+#if defined(MDE_CPU_IA32)
+ .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
+#elif defined(MDE_CPU_X64)
+ .Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
+#endif
+ .SectionAlignment = EFI_FILE_ALIGN,
+ .FileAlignment = EFI_FILE_ALIGN,
+ .SizeOfImage = sizeof ( efi_pe_header ),
+ .SizeOfHeaders = sizeof ( efi_pe_header ),
+ .NumberOfRvaAndSizes =
+ EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+ },
+ },
+};
+
+/** Command-line options */
+struct options {
+ unsigned int subsystem;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ eprintf ( "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Align section within PE file
+ *
+ * @v offset Unaligned offset
+ * @ret aligned_offset Aligned offset
+ */
+static unsigned long efi_file_align ( unsigned long offset ) {
+ return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v rva RVA
+ * @v size Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+ unsigned long rva, size_t size ) {
+ unsigned long start_rva;
+ uint16_t reloc;
+ struct pe_relocs *pe_rel;
+ uint16_t *relocs;
+
+ /* Construct */
+ start_rva = ( rva & ~0xfff );
+ reloc = ( rva & 0xfff );
+ switch ( size ) {
+ case 8:
+ reloc |= 0xa000;
+ break;
+ case 4:
+ reloc |= 0x3000;
+ break;
+ case 2:
+ reloc |= 0x2000;
+ break;
+ default:
+ eprintf ( "Unsupported relocation size %zd\n", size );
+ exit ( 1 );
+ }
+
+ /* Locate or create PE relocation table */
+ for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ if ( pe_rel->start_rva == start_rva )
+ break;
+ }
+ if ( ! pe_rel ) {
+ pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+ memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+ pe_rel->next = *pe_reltab;
+ *pe_reltab = pe_rel;
+ pe_rel->start_rva = start_rva;
+ }
+
+ /* Expand relocation list if necessary */
+ if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+ relocs = pe_rel->relocs;
+ } else {
+ pe_rel->total_relocs = ( pe_rel->total_relocs ?
+ ( pe_rel->total_relocs * 2 ) : 256 );
+ relocs = xmalloc ( pe_rel->total_relocs *
+ sizeof ( pe_rel->relocs[0] ) );
+ memset ( relocs, 0,
+ pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+ memcpy ( relocs, pe_rel->relocs,
+ pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+ free ( pe_rel->relocs );
+ pe_rel->relocs = relocs;
+ }
+
+ /* Store relocation */
+ pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v buffer Buffer to contain binary table, or NULL
+ * @ret size Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+ void *buffer ) {
+ struct pe_relocs *pe_rel;
+ unsigned int num_relocs;
+ size_t size;
+ size_t total_size = 0;
+
+ for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+ size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+ sizeof ( uint32_t ) /* SizeOfBlock */ +
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ if ( buffer ) {
+ *( (uint32_t *) ( buffer + total_size + 0 ) )
+ = pe_rel->start_rva;
+ *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+ memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ }
+ total_size += size;
+ }
+
+ return total_size;
+}
+
+/**
+ * Open input BFD file
+ *
+ * @v filename File name
+ * @ret ibfd BFD file
+ */
+static bfd * open_input_bfd ( const char *filename ) {
+ bfd *bfd;
+
+ /* Open the file */
+ bfd = bfd_openr ( filename, NULL );
+ if ( ! bfd ) {
+ eprintf ( "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* The call to bfd_check_format() must be present, otherwise
+ * we get a segfault from later BFD calls.
+ */
+ if ( bfd_check_format ( bfd, bfd_object ) < 0 ) {
+ eprintf ( "%s is not an object file\n", filename );
+ exit ( 1 );
+ }
+
+ return bfd;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd BFD file
+ */
+static asymbol ** read_symtab ( bfd *bfd ) {
+ long symtab_size;
+ asymbol **symtab;
+ long symcount;
+
+ /* Get symbol table size */
+ symtab_size = bfd_get_symtab_upper_bound ( bfd );
+ if ( symtab_size < 0 ) {
+ bfd_perror ( "Could not get symbol table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read symbol table */
+ symtab = xmalloc ( symtab_size );
+ symcount = bfd_canonicalize_symtab ( bfd, symtab );
+ if ( symcount < 0 ) {
+ bfd_perror ( "Cannot read symbol table" );
+ exit ( 1 );
+ }
+
+ return symtab;
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd BFD file
+ * @v symtab Symbol table
+ * @v section Section
+ * @v symtab Symbol table
+ * @ret reltab Relocation table
+ */
+static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
+ asection *section ) {
+ long reltab_size;
+ arelent **reltab;
+ long numrels;
+
+ /* Get relocation table size */
+ reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
+ if ( reltab_size < 0 ) {
+ bfd_perror ( "Could not get relocation table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read relocation table */
+ reltab = xmalloc ( reltab_size );
+ numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
+ if ( numrels < 0 ) {
+ bfd_perror ( "Cannot read relocation table" );
+ exit ( 1 );
+ }
+
+ return reltab;
+}
+
+/**
+ * Process section
+ *
+ * @v bfd BFD file
+ * @v pe_header PE file header
+ * @v section Section
+ * @ret new New PE section
+ */
+static struct pe_section * process_section ( bfd *bfd,
+ struct pe_header *pe_header,
+ asection *section ) {
+ struct pe_section *new;
+ size_t section_memsz;
+ size_t section_filesz;
+ unsigned long flags = bfd_get_section_flags ( bfd, section );
+ unsigned long code_start;
+ unsigned long code_end;
+ unsigned long data_start;
+ unsigned long data_mid;
+ unsigned long data_end;
+ unsigned long start;
+ unsigned long end;
+ unsigned long *applicable_start;
+ unsigned long *applicable_end;
+
+ /* Extract current RVA limits from file header */
+ code_start = pe_header->nt.OptionalHeader.BaseOfCode;
+ code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+#if defined(MDE_CPU_IA32)
+ data_start = pe_header->nt.OptionalHeader.BaseOfData;
+#elif defined(MDE_CPU_X64)
+ data_start = code_end;
+#endif
+ data_mid = ( data_start +
+ pe_header->nt.OptionalHeader.SizeOfInitializedData );
+ data_end = ( data_mid +
+ pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+
+ /* Allocate PE section */
+ section_memsz = bfd_section_size ( bfd, section );
+ section_filesz = ( ( flags & SEC_LOAD ) ?
+ efi_file_align ( section_memsz ) : 0 );
+ new = xmalloc ( sizeof ( *new ) + section_filesz );
+ memset ( new, 0, sizeof ( *new ) + section_filesz );
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) new->hdr.Name, section->name,
+ sizeof ( new->hdr.Name ) );
+ new->hdr.Misc.VirtualSize = section_memsz;
+ new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
+ new->hdr.SizeOfRawData = section_filesz;
+
+ /* Fill in section characteristics and update RVA limits */
+ if ( flags & SEC_CODE ) {
+ /* .text-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_CODE |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_EXECUTE |
+ EFI_IMAGE_SCN_MEM_READ );
+ applicable_start = &code_start;
+ applicable_end = &code_end;
+ } else if ( flags & SEC_DATA ) {
+ /* .data-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ |
+ EFI_IMAGE_SCN_MEM_WRITE );
+ applicable_start = &data_start;
+ applicable_end = &data_mid;
+ } else if ( flags & SEC_READONLY ) {
+ /* .rodata-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+ applicable_start = &data_start;
+ applicable_end = &data_mid;
+ } else if ( ! ( flags & SEC_LOAD ) ) {
+ /* .bss-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ |
+ EFI_IMAGE_SCN_MEM_WRITE );
+ applicable_start = &data_mid;
+ applicable_end = &data_end;
+ }
+
+ /* Copy in section contents */
+ if ( flags & SEC_LOAD ) {
+ if ( ! bfd_get_section_contents ( bfd, section, new->contents,
+ 0, section_memsz ) ) {
+ eprintf ( "Cannot read section %s: ", section->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+ }
+
+ /* Update RVA limits */
+ start = new->hdr.VirtualAddress;
+ end = ( start + new->hdr.Misc.VirtualSize );
+ if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
+ *applicable_start = start;
+ if ( *applicable_end < end )
+ *applicable_end = end;
+ if ( data_start < code_end )
+ data_start = code_end;
+ if ( data_mid < data_start )
+ data_mid = data_start;
+ if ( data_end < data_mid )
+ data_end = data_mid;
+
+ /* Write RVA limits back to file header */
+ pe_header->nt.OptionalHeader.BaseOfCode = code_start;
+ pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
+#if defined(MDE_CPU_IA32)
+ pe_header->nt.OptionalHeader.BaseOfData = data_start;
+#endif
+ pe_header->nt.OptionalHeader.SizeOfInitializedData =
+ ( data_mid - data_start );
+ pe_header->nt.OptionalHeader.SizeOfUninitializedData =
+ ( data_end - data_mid );
+
+ /* Update remaining file header fields */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage =
+ efi_file_align ( data_end );
+
+ return new;
+}
+
+/**
+ * Process relocation record
+ *
+ * @v bfd BFD file
+ * @v section Section
+ * @v rel Relocation entry
+ * @v pe_reltab PE relocation table to fill in
+ */
+static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
+ struct pe_relocs **pe_reltab ) {
+ reloc_howto_type *howto = rel->howto;
+ asymbol *sym = *(rel->sym_ptr_ptr);
+ unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
+ rel->address );
+
+ if ( bfd_is_abs_section ( sym->section ) ) {
+ /* Skip absolute symbols; the symbol value won't
+ * change when the object is loaded.
+ */
+ } 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 ) ) {
+ /* Generate a 4-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 4 );
+ } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+ /* Generate a 2-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 2 );
+ } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
+ ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
+ /* Skip PC-relative relocations; all relative offsets
+ * remain unaltered when the object is loaded.
+ */
+ } else {
+ eprintf ( "Unrecognised relocation type %s\n", howto->name );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Create relocations section
+ *
+ * @v pe_header PE file header
+ * @v pe_reltab PE relocation table
+ * @ret section Relocation section
+ */
+static struct pe_section *
+create_reloc_section ( struct pe_header *pe_header,
+ struct pe_relocs *pe_reltab ) {
+ struct pe_section *reloc;
+ size_t section_memsz;
+ size_t section_filesz;
+ EFI_IMAGE_DATA_DIRECTORY *relocdir;
+
+ /* Allocate PE section */
+ section_memsz = output_pe_reltab ( pe_reltab, NULL );
+ section_filesz = efi_file_align ( section_memsz );
+ reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
+ memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
+ sizeof ( reloc->hdr.Name ) );
+ reloc->hdr.Misc.VirtualSize = section_memsz;
+ reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+ reloc->hdr.SizeOfRawData = section_filesz;
+ reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+
+ /* Copy in section contents */
+ output_pe_reltab ( pe_reltab, reloc->contents );
+
+ /* Update file header details */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+ relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
+ [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+ relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
+ relocdir->Size = reloc->hdr.Misc.VirtualSize;
+
+ return reloc;
+}
+
+/**
+ * Create debug section
+ *
+ * @v pe_header PE file header
+ * @ret section Debug section
+ */
+static struct pe_section *
+create_debug_section ( struct pe_header *pe_header, const char *filename ) {
+ struct pe_section *debug;
+ size_t section_memsz;
+ size_t section_filesz;
+ EFI_IMAGE_DATA_DIRECTORY *debugdir;
+ struct {
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
+ EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
+ char name[ strlen ( filename ) + 1 ];
+ } *contents;
+
+ /* Allocate PE section */
+ section_memsz = sizeof ( *contents );
+ section_filesz = efi_file_align ( section_memsz );
+ debug = xmalloc ( sizeof ( *debug ) + section_filesz );
+ memset ( debug, 0, sizeof ( *debug ) + section_filesz );
+ contents = ( void * ) debug->contents;
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) debug->hdr.Name, ".debug",
+ sizeof ( debug->hdr.Name ) );
+ debug->hdr.Misc.VirtualSize = section_memsz;
+ debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+ debug->hdr.SizeOfRawData = section_filesz;
+ debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+
+ /* Create section contents */
+ contents->debug.TimeDateStamp = 0x10d1a884;
+ contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
+ contents->debug.SizeOfData =
+ ( sizeof ( *contents ) - sizeof ( contents->debug ) );
+ contents->debug.RVA = ( debug->hdr.VirtualAddress +
+ offsetof ( typeof ( *contents ), rsds ) );
+ contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
+ snprintf ( contents->name, sizeof ( contents->name ), "%s",
+ filename );
+
+ /* Update file header details */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+ debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
+ [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ debugdir->VirtualAddress = debug->hdr.VirtualAddress;
+ debugdir->Size = debug->hdr.Misc.VirtualSize;
+
+ return debug;
+}
+
+/**
+ * Write out PE file
+ *
+ * @v pe_header PE file header
+ * @v pe_sections List of PE sections
+ * @v pe Output file
+ */
+static void write_pe_file ( struct pe_header *pe_header,
+ struct pe_section *pe_sections,
+ FILE *pe ) {
+ struct pe_section *section;
+ unsigned long fpos = 0;
+
+ /* Assign raw data pointers */
+ fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( section->hdr.SizeOfRawData ) {
+ section->hdr.PointerToRawData = fpos;
+ fpos += section->hdr.SizeOfRawData;
+ fpos = efi_file_align ( fpos );
+ }
+ }
+
+ /* Write file header */
+ if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
+ perror ( "Could not write PE header" );
+ exit ( 1 );
+ }
+
+ /* Write section headers */
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
+ 1, pe ) != 1 ) {
+ perror ( "Could not write section header" );
+ exit ( 1 );
+ }
+ }
+
+ /* Write sections */
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( fseek ( pe, section->hdr.PointerToRawData,
+ SEEK_SET ) != 0 ) {
+ eprintf ( "Could not seek to %lx: %s\n",
+ section->hdr.PointerToRawData,
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+ if ( section->hdr.SizeOfRawData &&
+ ( fwrite ( section->contents, section->hdr.SizeOfRawData,
+ 1, pe ) != 1 ) ) {
+ eprintf ( "Could not write section %.8s: %s\n",
+ section->hdr.Name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ }
+}
+
+/**
+ * Convert ELF to PE
+ *
+ * @v elf_name ELF file name
+ * @v pe_name PE file name
+ */
+static void elf2pe ( const char *elf_name, const char *pe_name,
+ struct options *opts ) {
+ char pe_name_tmp[ strlen ( pe_name ) + 1 ];
+ bfd *bfd;
+ asymbol **symtab;
+ asection *section;
+ arelent **reltab;
+ arelent **rel;
+ struct pe_relocs *pe_reltab = NULL;
+ struct pe_section *pe_sections = NULL;
+ struct pe_section **next_pe_section = &pe_sections;
+ struct pe_header pe_header;
+ FILE *pe;
+
+ /* Create a modifiable copy of the PE name */
+ memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
+
+ /* Open the file */
+ bfd = open_input_bfd ( elf_name );
+ symtab = read_symtab ( bfd );
+
+ /* Initialise the PE header */
+ memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
+ pe_header.nt.OptionalHeader.AddressOfEntryPoint =
+ bfd_get_start_address ( bfd );
+ pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
+
+ /* For each input section, build an output section and create
+ * the appropriate relocation records
+ */
+ for ( section = bfd->sections ; section ; section = section->next ) {
+ /* Discard non-allocatable sections */
+ if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
+ continue;
+ /* Create output section */
+ *(next_pe_section) = process_section ( bfd, &pe_header,
+ section );
+ next_pe_section = &(*next_pe_section)->next;
+ /* Add relocations from this section */
+ reltab = read_reltab ( bfd, symtab, section );
+ for ( rel = reltab ; *rel ; rel++ )
+ process_reloc ( bfd, section, *rel, &pe_reltab );
+ free ( reltab );
+ }
+
+ /* Create the .reloc section */
+ *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
+ next_pe_section = &(*next_pe_section)->next;
+
+ /* Create the .reloc section */
+ *(next_pe_section) = create_debug_section ( &pe_header,
+ basename ( pe_name_tmp ) );
+ next_pe_section = &(*next_pe_section)->next;
+
+ /* Write out PE file */
+ pe = fopen ( pe_name, "w" );
+ if ( ! pe ) {
+ eprintf ( "Could not open %s for writing: %s\n",
+ pe_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ write_pe_file ( &pe_header, pe_sections, pe );
+ fclose ( pe );
+
+ /* Close BFD file */
+ bfd_close ( bfd );
+}
+
+/**
+ * Print help
+ *
+ * @v program_name Program name
+ */
+static void print_help ( const char *program_name ) {
+ eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
+ program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @v opts Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+ struct options *opts ) {
+ char *end;
+ int c;
+
+ while (1) {
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "subsystem", required_argument, NULL, 's' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ( ( c = getopt_long ( argc, argv, "s:h",
+ long_options,
+ &option_index ) ) == -1 ) {
+ break;
+ }
+
+ switch ( c ) {
+ case 's':
+ opts->subsystem = strtoul ( optarg, &end, 0 );
+ if ( *end ) {
+ eprintf ( "Invalid subsytem \"%s\"\n",
+ optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'h':
+ print_help ( argv[0] );
+ exit ( 0 );
+ case '?':
+ default:
+ exit ( 2 );
+ }
+ }
+ return optind;
+}
+
+int main ( int argc, char **argv ) {
+ struct options opts = {
+ .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
+ };
+ unsigned int infile_index;
+ const char *infile;
+ const char *outfile;
+
+ /* Initialise libbfd */
+ bfd_init();
+
+ /* Parse command-line arguments */
+ infile_index = parse_options ( argc, argv, &opts );
+ if ( argc != ( infile_index + 2 ) ) {
+ print_help ( argv[0] );
+ exit ( 2 );
+ }
+ infile = argv[infile_index];
+ outfile = argv[infile_index + 1];
+
+ /* Convert file */
+ elf2pe ( infile, outfile, &opts );
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/geniso b/contrib/syslinux-4.02/gpxe/src/util/geniso
new file mode 100755
index 0000000..7c2f767
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/geniso
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# Generate a isolinux ISO boot image
+#
+# geniso foo.iso foo.lkrn
+#
+# the ISO image is the first argument so that a list of .lkrn images
+# to include can be specified
+#
+case $# in
+0|1)
+ echo Usage: $0 foo.iso foo.lkrn ...
+ exit 1
+ ;;
+esac
+# This should be the default location of the isolinux.bin file
+isolinux_bin=${ISOLINUX_BIN:-util/isolinux.bin}
+if [ ! -r $isolinux_bin ]
+then
+ echo $0: $isolinux_bin not found, please install, or set ISOLINUX_BIN in arch/i386/Makefile correctly
+ exit 1
+fi
+out=$1
+shift
+dir=`mktemp -d bin/iso.dir.XXXXXX`
+cfg=$dir/isolinux.cfg
+cp -p $isolinux_bin $dir
+cat > $cfg <<EOF
+# These default options can be changed in the geniso script
+SAY Etherboot ISO boot image generated by geniso
+TIMEOUT 30
+EOF
+first=
+for f
+do
+ if [ ! -r $f ]
+ then
+ echo $f does not exist, skipping 1>&2
+ continue
+ fi
+ b=$(basename $f)
+ g=${b%.lkrn}
+ g=${g//[^a-z0-9]}.krn
+ case "$first" in
+ "")
+ echo DEFAULT $g
+ ;;
+ esac
+ first=$g
+ echo LABEL $b
+ echo "" KERNEL $g
+ cp -p $f $dir/$g
+done >> $cfg
+mkisofs -q -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
+rm -fr $dir
diff --git a/contrib/syslinux-4.02/gpxe/src/util/genliso b/contrib/syslinux-4.02/gpxe/src/util/genliso
new file mode 100755
index 0000000..1f1c116
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/genliso
@@ -0,0 +1,74 @@
+#!/bin/bash
+#
+# Generate a legacy floppy emulation ISO boot image
+#
+# genliso foo.liso foo.lkrn bar.lkrn ...
+#
+# The .liso image filename is the first argument followed by
+# a list of .lkrn images include in .liso image
+
+case $# in
+0|1)
+ echo Usage: $0 foo.liso foo.lkrn ...
+ exit 1
+ ;;
+esac
+
+case "`mtools -V`" in
+Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*)
+ ;;
+*)
+ echo Mtools version 3.9.9 or later is required
+ exit 1
+ ;;
+esac
+
+out=$1
+shift
+
+dir=`mktemp -d bin/liso.dir.XXXXXX`
+
+img=$dir/boot.img
+mformat -f 1440 -C -i $img ::
+
+cfg=$dir/syslinux.cfg
+cat > $cfg <<EOF
+# These default options can be changed in the genliso script
+SAY gPXE ISO boot image generated by genliso
+TIMEOUT 30
+EOF
+
+first=
+for f
+do
+ if [ ! -r $f ]
+ then
+ echo $f does not exist, skipping 1>&2
+ continue
+ fi
+ # shorten name for 8.3 filesystem
+ b=$(basename $f)
+ g=${b%.lkrn}
+ g=${g//[^a-z0-9]}
+ g=${g:0:8}.krn
+ case "$first" in
+ "")
+ echo DEFAULT $g
+ ;;
+ esac
+ first=$g
+ echo LABEL $b
+ echo "" KERNEL $g
+ mcopy -m -i $img $f ::$g
+done >> $cfg
+
+mcopy -i $img $cfg ::syslinux.cfg
+
+if ! syslinux $img
+then
+ exit 1
+fi
+
+mkisofs -q -o $out -c boot.cat -b boot.img $dir
+
+rm -fr $dir
diff --git a/contrib/syslinux-4.02/gpxe/src/util/gensdsk b/contrib/syslinux-4.02/gpxe/src/util/gensdsk
new file mode 100755
index 0000000..a866158
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/gensdsk
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Generate a syslinux floppy that loads a gPXE image
+#
+# gensdsk foo.sdsk foo.lkrn
+#
+# the floppy image is the first argument
+# followed by list of .lkrn images
+#
+
+case $# in
+0|1)
+ echo Usage: $0 foo.sdsk foo.lkrn ...
+ exit 1
+ ;;
+esac
+case "`mtools -V`" in
+Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*)
+ ;;
+*)
+ echo Mtools version 3.9.9 or later is required
+ exit 1
+ ;;
+esac
+img=$1
+shift
+dir=`mktemp -d bin/sdsk.dir.XXXXXX`
+
+mformat -f 1440 -C -i $img ::
+cfg=$dir/syslinux.cfg
+cat > $cfg <<EOF
+
+# These default options can be changed in the gensdsk script
+TIMEOUT 30
+EOF
+first=
+for f
+do
+ if [ ! -r $f ]
+ then
+ echo $f does not exist, skipping 1>&2
+ continue
+ fi
+ # shorten name for 8.3 filesystem
+ b=$(basename $f)
+ g=${b%.lkrn}
+ g=${g//[^a-z0-9]}
+ g=${g:0:8}.krn
+ case "$first" in
+ "")
+ echo DEFAULT $g
+ ;;
+ esac
+ first=$g
+ echo LABEL $b
+ echo "" KERNEL $g
+ mcopy -m -i $img $f ::$g
+done >> $cfg
+mcopy -i $img $cfg ::syslinux.cfg
+if ! syslinux $img
+then
+ exit 1
+fi
+
+rm -fr $dir
diff --git a/contrib/syslinux-4.02/gpxe/src/util/get-pci-ids b/contrib/syslinux-4.02/gpxe/src/util/get-pci-ids
new file mode 100755
index 0000000..6501a7f
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/get-pci-ids
@@ -0,0 +1,135 @@
+#! /usr/bin/perl -w
+
+# get-pci-ids: extract pci vendor/device ids from linux net drivers
+
+# Copyright (C) 2003 Georg Baum <gbaum@users.sf.net>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Known bugs/limitations:
+# - Does not recognize all drivers because some require special cflags.
+# Fails also on some drivers that do belong to other architectures
+# than the one of the machine this script is running on.
+# This is currently not so important because all drivers that have an
+# Etherboot counterpart are recognized.
+
+
+use strict;
+use File::Basename "dirname";
+use POSIX "uname";
+
+# Where to find the kernel sources
+my $kernel_src = "/usr/src/linux";
+
+if($#ARGV >= 0) {
+ $kernel_src = shift;
+}
+
+# Sanity checks
+if($#ARGV >= 0) {
+ print STDERR "Too many arguments.\n";
+ print STDERR "Usage: get-pci-ids [path to kernel sources]\n";
+ print STDERR " /usr/src/linux is assumed if no path is given.\n";
+ exit 1;
+}
+
+unless(-f "$kernel_src/include/linux/version.h") {
+ print STDERR "Could not find $kernel_src/include/linux/version.h.\n";
+ print STDERR "$kernel_src is probably no Linux kernel source tree.\n";
+ exit 1;
+}
+
+# Flags that are needed to preprocess the drivers.
+# Some drivers need optimization
+my $cflags="-D__KERNEL__ -I$kernel_src/include -I$kernel_src/net/inet -O2";
+
+# The C preprocessor. It needs to spit out the preprocessed source on stdout.
+my $cpp="gcc -E";
+
+# List of drivers. We parse every .c file. It does not harm if it does not contain a driver.
+my @drivers = split /\s+/, `find $kernel_src/drivers/net -name '*.c' | sort`;
+
+# Kernel version
+my $version = `grep UTS_RELEASE $kernel_src/include/linux/version.h`;
+chomp $version;
+$version =~ s/\s*#define\s+UTS_RELEASE\s+"(\S+)".*$/$1/g;
+
+# Architecture
+my @uname = uname();
+
+
+# Print header
+print "# PCI vendor/device ids extracted from Linux $version on $uname[4] at " . gmtime() . "\n";
+
+my $driver;
+
+# Process the drivers
+foreach $driver (@drivers) {
+
+ # Preprocess to expand macros
+ my $command = "$cpp $cflags -I" . dirname($driver) . " $driver";
+ open DRIVER, "$command |" or die "Could not execute\n\"$command\".\n";
+
+ # Extract the pci_device_id structure
+ my $found = 0;
+ my $line = "";
+ my @lines;
+ while(<DRIVER>) {
+ if(/^\s*static\s+struct\s+pci_device_id/) {
+ # This file contains a driver. Print the name.
+ $driver =~ s!$kernel_src/drivers/net/!!g;
+ print "\n$driver\n";
+ $found = 1;
+ next;
+ }
+ if($found == 1){
+ if(/\};/ or /{\s*0\s*,?\s*}/) {
+ # End of struct
+ $found = 0;
+ } else {
+ chomp;
+ if(/\}\s*,?\s*\n?$/) {
+ # This line contains a full entry or the last part of it.
+ $_ = $line . $_;
+ $line = "";
+ s/[,\{\};\(\)]//g; # Strip punctuation
+ s/^\s+//g; # Eat whitespace at beginning of line
+ tr[A-Z][a-z]; # Convert to lowercase
+ # Push the vendor and device id to @lines if this line is not empty.
+ # We ignore everything else that might be there
+ my ($vendor_id, $device_id, $remainder) = split /\W+/, $_, 3;
+ push @lines, "$vendor_id $device_id\n" if($vendor_id && $device_id);
+ } else {
+ # This line does contain a partial entry. Remember it.
+ $line .= "$_ ";
+ }
+ }
+ }
+ }
+ close DRIVER; # No "or die", because $cpp fails on some files
+
+ # Now print out the sorted values
+ @lines = sort @lines;
+ my $lastline = "";
+ foreach(@lines) {
+ # Print each vendor/device id combination only once.
+ # Some drivers (e.g. e100) do contain subfamilies
+ print if($_ ne $lastline);
+ $lastline = $_;
+ }
+}
+
+
diff --git a/contrib/syslinux-4.02/gpxe/src/util/hijack.c b/contrib/syslinux-4.02/gpxe/src/util/hijack.c
new file mode 100644
index 0000000..ed89592
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/hijack.c
@@ -0,0 +1,628 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <pcap.h>
+
+#define SNAPLEN 1600
+
+/*
+ * FIXME: is there a way to detect the version of the libpcap library?
+ * Version 0.9 has pcap_inject; version 0.8 doesn't, but both report
+ * their version number as 2.4.
+ */
+#define HAVE_PCAP_INJECT 0
+
+struct hijack {
+ pcap_t *pcap;
+ int fd;
+ int datalink;
+ int filtered;
+ unsigned long rx_count;
+ unsigned long tx_count;
+};
+
+struct hijack_listener {
+ struct sockaddr_un sun;
+ int fd;
+};
+
+struct hijack_options {
+ char interface[IF_NAMESIZE];
+ int daemonise;
+};
+
+static int daemonised = 0;
+
+static int signalled = 0;
+
+static void flag_signalled ( int signal __attribute__ (( unused )) ) {
+ signalled = 1;
+}
+
+#if ! HAVE_PCAP_INJECT
+/**
+ * Substitute for pcap_inject(), if this version of libpcap doesn't
+ * have it. Will almost certainly only work under Linux.
+ *
+ */
+int pcap_inject ( pcap_t *pcap, const void *data, size_t len ) {
+ int fd;
+ char *errbuf = pcap_geterr ( pcap );
+
+ fd = pcap_get_selectable_fd ( pcap );
+ if ( fd < 0 ) {
+ snprintf ( errbuf, PCAP_ERRBUF_SIZE,
+ "could not get file descriptor" );
+ return -1;
+ }
+ if ( write ( fd, data, len ) != len ) {
+ snprintf ( errbuf, PCAP_ERRBUF_SIZE,
+ "could not write data: %s", strerror ( errno ) );
+ return -1;
+ }
+ return len;
+}
+#endif /* ! HAVE_PCAP_INJECT */
+
+/**
+ * Log error message
+ *
+ */
+static __attribute__ (( format ( printf, 2, 3 ) )) void
+logmsg ( int level, const char *format, ... ) {
+ va_list ap;
+
+ va_start ( ap, format );
+ if ( daemonised ) {
+ vsyslog ( ( LOG_DAEMON | level ), format, ap );
+ } else {
+ vfprintf ( stderr, format, ap );
+ }
+ va_end ( ap );
+}
+
+/**
+ * Open pcap device
+ *
+ */
+static int hijack_open ( const char *interface, struct hijack *hijack ) {
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ /* Open interface via pcap */
+ errbuf[0] = '\0';
+ hijack->pcap = pcap_open_live ( interface, SNAPLEN, 1, 0, errbuf );
+ if ( ! hijack->pcap ) {
+ logmsg ( LOG_ERR, "Failed to open %s: %s\n",
+ interface, errbuf );
+ goto err;
+ }
+ if ( errbuf[0] )
+ logmsg ( LOG_WARNING, "Warning: %s\n", errbuf );
+
+ /* Set capture interface to non-blocking mode */
+ if ( pcap_setnonblock ( hijack->pcap, 1, errbuf ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not make %s non-blocking: %s\n",
+ interface, errbuf );
+ goto err;
+ }
+
+ /* Get file descriptor for select() */
+ hijack->fd = pcap_get_selectable_fd ( hijack->pcap );
+ if ( hijack->fd < 0 ) {
+ logmsg ( LOG_ERR, "Cannot get selectable file descriptor "
+ "for %s\n", interface );
+ goto err;
+ }
+
+ /* Get link layer type */
+ hijack->datalink = pcap_datalink ( hijack->pcap );
+
+ return 0;
+
+ err:
+ if ( hijack->pcap )
+ pcap_close ( hijack->pcap );
+ return -1;
+}
+
+/**
+ * Close pcap device
+ *
+ */
+static void hijack_close ( struct hijack *hijack ) {
+ pcap_close ( hijack->pcap );
+}
+
+/**
+ * Install filter for hijacked connection
+ *
+ */
+static int hijack_install_filter ( struct hijack *hijack,
+ char *filter ) {
+ struct bpf_program program;
+
+ /* Compile filter */
+ if ( pcap_compile ( hijack->pcap, &program, filter, 1, 0 ) < 0 ) {
+ logmsg ( LOG_ERR, "could not compile filter \"%s\": %s\n",
+ filter, pcap_geterr ( hijack->pcap ) );
+ goto err_nofree;
+ }
+
+ /* Install filter */
+ if ( pcap_setfilter ( hijack->pcap, &program ) < 0 ) {
+ logmsg ( LOG_ERR, "could not install filter \"%s\": %s\n",
+ filter, pcap_geterr ( hijack->pcap ) );
+ goto err;
+ }
+
+ logmsg ( LOG_INFO, "using filter \"%s\"\n", filter );
+
+ pcap_freecode ( &program );
+ return 0;
+
+ err:
+ pcap_freecode ( &program );
+ err_nofree:
+ return -1;
+}
+
+/**
+ * Set up filter for hijacked ethernet connection
+ *
+ */
+static int hijack_filter_ethernet ( struct hijack *hijack, const char *buf,
+ size_t len ) {
+ char filter[55]; /* see format string */
+ struct ether_header *ether_header = ( struct ether_header * ) buf;
+ unsigned char *hwaddr = ether_header->ether_shost;
+
+ if ( len < sizeof ( *ether_header ) )
+ return -1;
+
+ snprintf ( filter, sizeof ( filter ), "broadcast or multicast or "
+ "ether host %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0],
+ hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] );
+
+ return hijack_install_filter ( hijack, filter );
+}
+
+/**
+ * Set up filter for hijacked connection
+ *
+ */
+static int hijack_filter ( struct hijack *hijack, const char *buf,
+ size_t len ) {
+ switch ( hijack->datalink ) {
+ case DLT_EN10MB:
+ return hijack_filter_ethernet ( hijack, buf, len );
+ default:
+ logmsg ( LOG_ERR, "unsupported protocol %s: cannot filter\n",
+ ( pcap_datalink_val_to_name ( hijack->datalink ) ?
+ pcap_datalink_val_to_name ( hijack->datalink ) :
+ "UNKNOWN" ) );
+ /* Return success so we don't get called again */
+ return 0;
+ }
+}
+
+/**
+ * Forward data from hijacker
+ *
+ */
+static ssize_t forward_from_hijacker ( struct hijack *hijack, int fd ) {
+ char buf[SNAPLEN];
+ ssize_t len;
+
+ /* Read packet from hijacker */
+ len = read ( fd, buf, sizeof ( buf ) );
+ if ( len < 0 ) {
+ logmsg ( LOG_ERR, "read from hijacker failed: %s\n",
+ strerror ( errno ) );
+ return -1;
+ }
+ if ( len == 0 )
+ return 0;
+
+ /* Set up filter if not already in place */
+ if ( ! hijack->filtered ) {
+ if ( hijack_filter ( hijack, buf, len ) == 0 )
+ hijack->filtered = 1;
+ }
+
+ /* Transmit packet to network */
+ if ( pcap_inject ( hijack->pcap, buf, len ) != len ) {
+ logmsg ( LOG_ERR, "write to hijacked port failed: %s\n",
+ pcap_geterr ( hijack->pcap ) );
+ return -1;
+ }
+
+ hijack->tx_count++;
+ return len;
+};
+
+/**
+ * Forward data to hijacker
+ *
+ */
+static ssize_t forward_to_hijacker ( int fd, struct hijack *hijack ) {
+ struct pcap_pkthdr *pkt_header;
+ const unsigned char *pkt_data;
+ ssize_t len;
+
+ /* Receive packet from network */
+ if ( pcap_next_ex ( hijack->pcap, &pkt_header, &pkt_data ) < 0 ) {
+ logmsg ( LOG_ERR, "read from hijacked port failed: %s\n",
+ pcap_geterr ( hijack->pcap ) );
+ return -1;
+ }
+ if ( pkt_header->caplen != pkt_header->len ) {
+ logmsg ( LOG_ERR, "read partial packet (%d of %d bytes)\n",
+ pkt_header->caplen, pkt_header->len );
+ return -1;
+ }
+ if ( pkt_header->caplen == 0 )
+ return 0;
+ len = pkt_header->caplen;
+
+ /* Write packet to hijacker */
+ if ( write ( fd, pkt_data, len ) != len ) {
+ logmsg ( LOG_ERR, "write to hijacker failed: %s\n",
+ strerror ( errno ) );
+ return -1;
+ }
+
+ hijack->rx_count++;
+ return len;
+};
+
+
+/**
+ * Run hijacker
+ *
+ */
+static int run_hijacker ( const char *interface, int fd ) {
+ struct hijack hijack;
+ fd_set fdset;
+ int max_fd;
+ ssize_t len;
+
+ logmsg ( LOG_INFO, "new connection for %s\n", interface );
+
+ /* Open connection to network */
+ memset ( &hijack, 0, sizeof ( hijack ) );
+ if ( hijack_open ( interface, &hijack ) < 0 )
+ goto err;
+
+ /* Do the forwarding */
+ max_fd = ( ( fd > hijack.fd ) ? fd : hijack.fd );
+ while ( 1 ) {
+ /* Wait for available data */
+ FD_ZERO ( &fdset );
+ FD_SET ( fd, &fdset );
+ FD_SET ( hijack.fd, &fdset );
+ if ( select ( ( max_fd + 1 ), &fdset, NULL, NULL, 0 ) < 0 ) {
+ logmsg ( LOG_ERR, "select failed: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+ if ( FD_ISSET ( fd, &fdset ) ) {
+ len = forward_from_hijacker ( &hijack, fd );
+ if ( len < 0 )
+ goto err;
+ if ( len == 0 )
+ break;
+ }
+ if ( FD_ISSET ( hijack.fd, &fdset ) ) {
+ len = forward_to_hijacker ( fd, &hijack );
+ if ( len < 0 )
+ goto err;
+ if ( len == 0 )
+ break;
+ }
+ }
+
+ hijack_close ( &hijack );
+ logmsg ( LOG_INFO, "closed connection for %s\n", interface );
+ logmsg ( LOG_INFO, "received %ld packets, sent %ld packets\n",
+ hijack.rx_count, hijack.tx_count );
+
+ return 0;
+
+ err:
+ if ( hijack.pcap )
+ hijack_close ( &hijack );
+ return -1;
+}
+
+/**
+ * Open listener socket
+ *
+ */
+static int open_listener ( const char *interface,
+ struct hijack_listener *listener ) {
+
+ /* Create socket */
+ listener->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
+ if ( listener->fd < 0 ) {
+ logmsg ( LOG_ERR, "Could not create socket: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+
+ /* Bind to local filename */
+ listener->sun.sun_family = AF_UNIX,
+ snprintf ( listener->sun.sun_path, sizeof ( listener->sun.sun_path ),
+ "/var/run/hijack-%s", interface );
+ if ( bind ( listener->fd, ( struct sockaddr * ) &listener->sun,
+ sizeof ( listener->sun ) ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not bind socket to %s: %s\n",
+ listener->sun.sun_path, strerror ( errno ) );
+ goto err;
+ }
+
+ /* Set as a listening socket */
+ if ( listen ( listener->fd, 0 ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not listen to %s: %s\n",
+ listener->sun.sun_path, strerror ( errno ) );
+ goto err;
+ }
+
+ return 0;
+
+ err:
+ if ( listener->fd >= 0 )
+ close ( listener->fd );
+ return -1;
+}
+
+/**
+ * Listen on listener socket
+ *
+ */
+static int listen_for_hijackers ( struct hijack_listener *listener,
+ const char *interface ) {
+ int fd;
+ pid_t child;
+ int rc;
+
+ logmsg ( LOG_INFO, "Listening on %s\n", listener->sun.sun_path );
+
+ while ( ! signalled ) {
+ /* Accept new connection, interruptibly */
+ siginterrupt ( SIGINT, 1 );
+ siginterrupt ( SIGHUP, 1 );
+ fd = accept ( listener->fd, NULL, 0 );
+ siginterrupt ( SIGINT, 0 );
+ siginterrupt ( SIGHUP, 0 );
+ if ( fd < 0 ) {
+ if ( errno == EINTR ) {
+ continue;
+ } else {
+ logmsg ( LOG_ERR, "accept failed: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+ }
+
+ /* Fork child process */
+ child = fork();
+ if ( child < 0 ) {
+ logmsg ( LOG_ERR, "fork failed: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+ if ( child == 0 ) {
+ /* I am the child; run the hijacker */
+ rc = run_hijacker ( interface, fd );
+ close ( fd );
+ exit ( rc );
+ }
+
+ close ( fd );
+ }
+
+ logmsg ( LOG_INFO, "Stopped listening on %s\n",
+ listener->sun.sun_path );
+ return 0;
+
+ err:
+ if ( fd >= 0 )
+ close ( fd );
+ return -1;
+}
+
+/**
+ * Close listener socket
+ *
+ */
+static void close_listener ( struct hijack_listener *listener ) {
+ close ( listener->fd );
+ unlink ( listener->sun.sun_path );
+}
+
+/**
+ * Print usage
+ *
+ */
+static void usage ( char **argv ) {
+ logmsg ( LOG_ERR,
+ "Usage: %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -h|--help Print this help message\n"
+ " -i|--interface intf Use specified network interface\n"
+ " -n|--nodaemon Run in foreground\n",
+ argv[0] );
+}
+
+/**
+ * Parse command-line options
+ *
+ */
+static int parse_options ( int argc, char **argv,
+ struct hijack_options *options ) {
+ static struct option long_options[] = {
+ { "interface", 1, NULL, 'i' },
+ { "nodaemon", 0, NULL, 'n' },
+ { "help", 0, NULL, 'h' },
+ { },
+ };
+ int c;
+
+ /* Set default options */
+ memset ( options, 0, sizeof ( *options ) );
+ strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
+ options->daemonise = 1;
+
+ /* Parse command-line options */
+ while ( 1 ) {
+ int option_index = 0;
+
+ c = getopt_long ( argc, argv, "i:hn", long_options,
+ &option_index );
+ if ( c < 0 )
+ break;
+
+ switch ( c ) {
+ case 'i':
+ strncpy ( options->interface, optarg,
+ sizeof ( options->interface ) );
+ break;
+ case 'n':
+ options->daemonise = 0;
+ break;
+ case 'h':
+ usage( argv );
+ return -1;
+ case '?':
+ /* Unrecognised option */
+ return -1;
+ default:
+ logmsg ( LOG_ERR, "Unrecognised option '-%c'\n", c );
+ return -1;
+ }
+ }
+
+ /* Check there's nothing left over on the command line */
+ if ( optind != argc ) {
+ usage ( argv );
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Daemonise
+ *
+ */
+static int daemonise ( const char *interface ) {
+ char pidfile[16 + IF_NAMESIZE + 4]; /* "/var/run/hijack-<intf>.pid" */
+ char pid[16];
+ int pidlen;
+ int fd = -1;
+
+ /* Daemonise */
+ if ( daemon ( 0, 0 ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not daemonise: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+ daemonised = 1; /* Direct messages to syslog now */
+
+ /* Open pid file */
+ snprintf ( pidfile, sizeof ( pidfile ), "/var/run/hijack-%s.pid",
+ interface );
+ fd = open ( pidfile, ( O_WRONLY | O_CREAT | O_TRUNC ),
+ ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) );
+ if ( fd < 0 ) {
+ logmsg ( LOG_ERR, "Could not open %s for writing: %s\n",
+ pidfile, strerror ( errno ) );
+ goto err;
+ }
+
+ /* Write pid to file */
+ pidlen = snprintf ( pid, sizeof ( pid ), "%d\n", getpid() );
+ if ( write ( fd, pid, pidlen ) != pidlen ) {
+ logmsg ( LOG_ERR, "Could not write %s: %s\n",
+ pidfile, strerror ( errno ) );
+ goto err;
+ }
+
+ close ( fd );
+ return 0;
+
+ err:
+ if ( fd >= 0 )
+ close ( fd );
+ return -1;
+}
+
+int main ( int argc, char **argv ) {
+ struct hijack_options options;
+ struct hijack_listener listener;
+ struct sigaction sa;
+
+ /* Parse command-line options */
+ if ( parse_options ( argc, argv, &options ) < 0 )
+ exit ( 1 );
+
+ /* Set up syslog connection */
+ openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON );
+
+ /* Set up listening socket */
+ if ( open_listener ( options.interface, &listener ) < 0 )
+ exit ( 1 );
+
+ /* Daemonise on demand */
+ if ( options.daemonise ) {
+ if ( daemonise ( options.interface ) < 0 )
+ exit ( 1 );
+ }
+
+ /* Avoid creating zombies */
+ memset ( &sa, 0, sizeof ( sa ) );
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_RESTART | SA_NOCLDWAIT;
+ if ( sigaction ( SIGCHLD, &sa, NULL ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not set SIGCHLD handler: %s",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Set 'signalled' flag on SIGINT or SIGHUP */
+ sa.sa_handler = flag_signalled;
+ sa.sa_flags = SA_RESTART | SA_RESETHAND;
+ if ( sigaction ( SIGINT, &sa, NULL ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not set SIGINT handler: %s",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+ if ( sigaction ( SIGHUP, &sa, NULL ) < 0 ) {
+ logmsg ( LOG_ERR, "Could not set SIGHUP handler: %s",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Listen for hijackers */
+ if ( listen_for_hijackers ( &listener, options.interface ) < 0 )
+ exit ( 1 );
+
+ close_listener ( &listener );
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/iccfix.c b/contrib/syslinux-4.02/gpxe/src/util/iccfix.c
new file mode 100644
index 0000000..303ae9c
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/iccfix.c
@@ -0,0 +1,156 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <elf.h>
+#include <gpxe/tables.h>
+
+#define DEBUG 0
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define dprintf(...) do { \
+ if ( DEBUG ) \
+ fprintf ( stderr, __VA_ARGS__ ); \
+ } while ( 0 )
+
+#ifdef SELF_INCLUDED
+
+/**
+ * Fix up ICC alignments
+ *
+ * @v elf ELF header
+ * @ret rc Return status code
+ *
+ * See comments in tables.h for an explanation of why this monstrosity
+ * is necessary.
+ */
+static int ICCFIX ( void *elf ) {
+ ELF_EHDR *ehdr = elf;
+ ELF_SHDR *shdr = ( elf + ehdr->e_shoff );
+ size_t shentsize = ehdr->e_shentsize;
+ unsigned int shnum = ehdr->e_shnum;
+ ELF_SHDR *strtab = ( ( ( void * ) shdr ) +
+ ( ehdr->e_shstrndx * shentsize ) );
+ char *strings = ( elf + strtab->sh_offset );
+
+ for ( ; shnum-- ; shdr = ( ( ( void * ) shdr ) + shentsize ) ) {
+ char *name = ( strings + shdr->sh_name );
+ unsigned long align = shdr->sh_addralign;
+ unsigned long new_align;
+
+ if ( ( strncmp ( name, ".tbl.", 5 ) == 0 ) &&
+ ( align >= ICC_ALIGN_HACK_FACTOR ) ) {
+ new_align = ( align / ICC_ALIGN_HACK_FACTOR );
+ shdr->sh_addralign = new_align;
+ dprintf ( "Section \"%s\": alignment %d->%d\n",
+ name, align, new_align );
+ }
+ }
+ return 0;
+}
+
+#else /* SELF_INCLUDED */
+
+#define SELF_INCLUDED
+
+/* Include iccfix32() function */
+#define ELF_EHDR Elf32_Ehdr
+#define ELF_SHDR Elf32_Shdr
+#define ICCFIX iccfix32
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+/* Include iccfix64() function */
+#define ELF_EHDR Elf64_Ehdr
+#define ELF_SHDR Elf64_Shdr
+#define ICCFIX iccfix64
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+static int iccfix ( const char *filename ) {
+ int fd;
+ struct stat stat;
+ void *elf;
+ unsigned char *eident;
+ int rc;
+
+ /* Open and mmap file */
+ fd = open ( filename, O_RDWR );
+ if ( fd < 0 ) {
+ eprintf ( "Could not open %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_open;
+ }
+ if ( fstat ( fd, &stat ) < 0 ) {
+ eprintf ( "Could not determine size of %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_fstat;
+ }
+ elf = mmap ( NULL, stat.st_size, ( PROT_READ | PROT_WRITE ),
+ MAP_SHARED, fd, 0 );
+ if ( elf == MAP_FAILED ) {
+ eprintf ( "Could not map %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_mmap;
+ }
+
+ /* Perform fixups */
+ eident = elf;
+ switch ( eident[EI_CLASS] ) {
+ case ELFCLASS32:
+ rc = iccfix32 ( elf );
+ break;
+ case ELFCLASS64:
+ rc = iccfix64 ( elf );
+ break;
+ default:
+ eprintf ( "Unknown ELF class %d in %s\n",
+ eident[EI_CLASS], filename );
+ rc = -1;
+ break;
+ }
+
+ munmap ( elf, stat.st_size );
+ err_mmap:
+ err_fstat:
+ close ( fd );
+ err_open:
+ return rc;
+}
+
+int main ( int argc, char **argv ) {
+ int i;
+ int rc;
+
+ /* Parse command line */
+ if ( argc < 2 ) {
+ eprintf ( "Syntax: %s <object_file>...\n", argv[0] );
+ exit ( 1 );
+ }
+
+ /* Process each object in turn */
+ for ( i = 1 ; i < argc ; i++ ) {
+ if ( ( rc = iccfix ( argv[i] ) ) != 0 ) {
+ eprintf ( "Could not fix up %s\n", argv[i] );
+ exit ( 1 );
+ }
+ }
+
+ return 0;
+}
+
+#endif /* SELF_INCLUDED */
diff --git a/contrib/syslinux-4.02/gpxe/src/util/licence.pl b/contrib/syslinux-4.02/gpxe/src/util/licence.pl
new file mode 100755
index 0000000..c37685d
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/licence.pl
@@ -0,0 +1,149 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+# List of licences we can handle
+my $known_licences = {
+ gpl_any => {
+ desc => "GPL (any version)",
+ can_subsume => {
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ gpl2_or_later => {
+ desc => "GPL version 2 (or, at your option, any later version)",
+ can_subsume => {
+ gpl_any => 1,
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ gpl2_only => {
+ desc => "GPL version 2 only",
+ can_subsume => {
+ gpl_any => 1,
+ gpl2_or_later => 1,
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ public_domain => {
+ desc => "Public Domain",
+ can_subsume => {},
+ },
+ bsd4 => {
+ desc => "BSD Licence (with advertising clause)",
+ can_subsume => {
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ bsd3 => {
+ desc => "BSD Licence (without advertising clause)",
+ can_subsume => {
+ public_domain => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ bsd2 => {
+ desc => "BSD Licence (without advertising or endorsement clauses)",
+ can_subsume => {
+ public_domain => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
+ mit => {
+ desc => "MIT/X11/Xorg Licence",
+ can_subsume => {
+ public_domain => 1,
+ isc => 1,
+ },
+ },
+ isc => {
+ desc => "ISC Licence",
+ can_subsume => {
+ public_domain => 1,
+ },
+ },
+};
+
+# Parse command-line options
+my $verbosity = 1;
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions (
+ 'verbose|v+' => sub { $verbosity++; },
+ 'quiet|q+' => sub { $verbosity--; },
+) or die "Could not parse command-line options\n";
+
+# Parse licence list from command line
+my $licences = {};
+foreach my $licence ( @ARGV ) {
+ die "Unknown licence \"$licence\"\n"
+ unless exists $known_licences->{$licence};
+ $licences->{$licence} = $known_licences->{$licence};
+}
+die "No licences specified\n" unless %$licences;
+
+# Dump licence list
+if ( $verbosity >= 1 ) {
+ print "The following licences appear within this file:\n";
+ foreach my $licence ( keys %$licences ) {
+ print " ".$licences->{$licence}->{desc}."\n"
+ }
+}
+
+# Apply licence compatibilities to reduce to a single resulting licence
+foreach my $licence ( keys %$licences ) {
+ # Skip already-deleted licences
+ next unless exists $licences->{$licence};
+ # Subsume any subsumable licences
+ foreach my $can_subsume ( keys %{$licences->{$licence}->{can_subsume}} ) {
+ if ( exists $licences->{$can_subsume} ) {
+ print $licences->{$licence}->{desc}." subsumes ".
+ $licences->{$can_subsume}->{desc}."\n"
+ if $verbosity >= 1;
+ delete $licences->{$can_subsume};
+ }
+ }
+}
+
+# Print resulting licence
+die "Cannot reduce to a single resulting licence!\n"
+ if ( keys %$licences ) != 1;
+( my $licence ) = keys %$licences;
+print "The overall licence for this file is:\n " if $verbosity >= 1;
+print $licences->{$licence}->{desc}."\n";
diff --git a/contrib/syslinux-4.02/gpxe/src/util/makerom.pl b/contrib/syslinux-4.02/gpxe/src/util/makerom.pl
new file mode 100755
index 0000000..68c3be9
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/makerom.pl
@@ -0,0 +1,232 @@
+#!/usr/bin/perl -w
+
+use Getopt::Std;
+
+use constant MINROMSIZE => 8192;
+use constant MAXROMSIZE => 262144;
+
+use constant PCI_PTR_LOC => 0x18; # from beginning of ROM
+use constant PCI_HDR_SIZE => 0x18;
+use constant PNP_PTR_LOC => 0x1a; # from beginning of ROM
+use constant PNP_HDR_SIZE => 0x20;
+use constant PNP_CHKSUM_OFF => 0x9; # bytes from beginning of PnP header
+use constant PNP_DEVICE_OFF => 0x10; # bytes from beginning of PnP header
+use constant PCI_VEND_ID_OFF => 0x4; # bytes from beginning of PCI header
+use constant PCI_DEV_ID_OFF => 0x6; # bytes from beginning of PCI header
+use constant PCI_SIZE_OFF => 0x10; # bytes from beginning of PCI header
+
+use constant UNDI_PTR_LOC => 0x16; # from beginning of ROM
+use constant UNDI_HDR_SIZE => 0x16;
+use constant UNDI_CHKSUM_OFF => 0x05;
+
+use strict;
+
+use vars qw(%opts);
+
+use bytes;
+
+sub getromsize ($) {
+ my ($romref) = @_;
+ my $i;
+
+ print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n"
+ if (substr($$romref, 0, 2) ne "\x55\xaa");
+ my $size = ord(substr($$romref, 2, 1)) * 512;
+ for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { }
+ print STDERR "$size is a strange size for a boot ROM\n"
+ if ($size > 0 and $i > $size);
+ return ($size);
+}
+
+sub addident ($) {
+ my ($romref) = @_;
+
+ return (0) unless (my $s = $opts{'i'});
+ # include the terminating NUL byte too
+ $s .= "\x00";
+ my $len = length($s);
+ # Put the identifier in only if the space is blank
+ my $pos = length($$romref) - $len - 2;
+ return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len));
+ substr($$romref, $pos, $len) = $s;
+ return ($pos);
+}
+
+sub pcipnpheaders ($$) {
+ my ($romref, $identoffset) = @_;
+ my ($pci_hdr_offset, $pnp_hdr_offset);
+
+ $pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2));
+ $pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2));
+ # Sanity checks
+ if ($pci_hdr_offset < PCI_PTR_LOC + 2
+ or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE
+ or $pnp_hdr_offset < PNP_PTR_LOC + 2
+ or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE
+ or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR'
+ or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') {
+ $pci_hdr_offset = $pnp_hdr_offset = 0;
+ } else {
+ printf "PCI header at %#x and PnP header at %#x\n",
+ $pci_hdr_offset, $pnp_hdr_offset if $opts{'v'};
+ }
+ if ($pci_hdr_offset > 0) {
+ my ($pci_vendor_id, $pci_device_id);
+ # if no -p option, just report what's there
+ if (!defined($opts{'p'})) {
+ $pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2));
+ $pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2));
+ printf "PCI Vendor ID %#x Device ID %#x\n",
+ $pci_vendor_id, $pci_device_id;
+ } else {
+ substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2)
+ = pack('v', length($$romref) / 512);
+ ($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'});
+ substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)
+ = pack('v', oct($pci_vendor_id)) if ($pci_vendor_id);
+ substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)
+ = pack('v', oct($pci_device_id)) if ($pci_device_id);
+ }
+ }
+ if ($pnp_hdr_offset > 0) {
+ if (defined($identoffset)) {
+ # Point to device id string at end of ROM image
+ substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2)
+ = pack('v', $identoffset);
+ }
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset,
+ PNP_HDR_SIZE));
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub undiheaders ($) {
+ my ($romref) = @_;
+ my ($undi_hdr_offset);
+
+ $undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2));
+ # Sanity checks
+ if ($undi_hdr_offset < UNDI_PTR_LOC + 2
+ or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE
+ or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') {
+ $undi_hdr_offset = 0;
+ } else {
+ printf "UNDI header at %#x\n", $undi_hdr_offset if $opts{'v'};
+ }
+ if ($undi_hdr_offset > 0) {
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset,
+ UNDI_HDR_SIZE));
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub writerom ($$) {
+ my ($filename, $romref) = @_;
+
+ open(R, ">$filename") or die "$filename: $!\n";
+ print R $$romref;
+ close(R);
+}
+
+sub checksum ($$) {
+ my ($romref, $romsize) = @_;
+
+ substr($$romref, 6, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, 0, $romsize));
+ substr($$romref, 6, 1) = chr(256 - $sum);
+ # Double check
+ $sum = unpack('%8C*', substr($$romref, 0, $romsize));
+ if ($sum != 0) {
+ print "Checksum fails\n"
+ } elsif ($opts{'v'}) {
+ print "Checksum ok\n";
+ }
+}
+
+sub makerom () {
+ my ($rom, $romsize, $stubsize);
+
+ getopts('3xni:p:s:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-n] [-x] [-3] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ # If PXE image, just fill the length field and write it out
+ if ($opts{'x'}) {
+ substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
+ writerom($ARGV[0], \$rom);
+ return;
+ }
+ # Size specified with -s overrides value in 3rd byte in image
+ # -s 0 means round up to next 512 byte block
+ if (defined($opts{'s'})) {
+ if (($romsize = oct($opts{'s'})) <= 0) {
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511
+ }
+ } else {
+ # Shrink romsize down to the smallest power of two that will do
+ for ($romsize = MAXROMSIZE;
+ $romsize > MINROMSIZE and $romsize >= 2*$filesize;
+ $romsize /= 2) { }
+ }
+ if ($filesize > $romsize) {
+ print STDERR "ROM size of $romsize not big enough for data, ";
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511;
+ print "will use $romsize instead\n"
+ }
+ # Pad with 0xFF to $romsize
+ $rom .= "\xFF" x ($romsize - length($rom));
+ # If this is a stub ROM, don't force header size to the full amount
+ if (!$opts{'n'}) {
+ if ($romsize >= 128 * 1024) {
+ print "Warning: ROM size exceeds extension BIOS limit\n";
+ }
+ substr($rom, 2, 1) = chr(($romsize / 512) % 256);
+ } else {
+ $stubsize = ord(substr($rom, 2, 1)) * 512;
+ print "Stub size is $stubsize\n" if $opts{'v'};
+ }
+ print "ROM size is $romsize\n" if $opts{'v'};
+ # set the product string only if we don't have one yet
+ my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
+ my $identoffset = substr($rom, $pnp_hdr_offset+PNP_DEVICE_OFF, 2) eq "\0\0" ? addident(\$rom) : undef;
+ pcipnpheaders(\$rom, $identoffset);
+ undiheaders(\$rom);
+ # 3c503 requires last two bytes to be 0x80
+ substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
+ if ($opts{'3'} and $romsize == MINROMSIZE);
+ checksum(\$rom, $opts{'n'} ? $stubsize : $romsize);
+ writerom($ARGV[0], \$rom);
+}
+
+sub modrom () {
+ my ($rom);
+
+ getopts('p:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ pcipnpheaders(\$rom, undef);
+ undiheaders(\$rom);
+ checksum(\$rom, ord(substr($rom, 2, 1)) * 512);
+ writerom($ARGV[0], \$rom);
+}
+
+# Main routine. See how we were called and behave accordingly
+if ($0 =~ m:modrom(\.pl)?$:) {
+ modrom();
+} else {
+ makerom();
+}
+exit(0);
diff --git a/contrib/syslinux-4.02/gpxe/src/util/mergerom.pl b/contrib/syslinux-4.02/gpxe/src/util/mergerom.pl
new file mode 100755
index 0000000..f9c5250
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/mergerom.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
+
+sub merge_entry_points {
+ my $baserom_entry = \shift;
+ my $rom_entry = \shift;
+ my $offset = shift;
+
+ if ( $$rom_entry ) {
+ my $old_entry = $$baserom_entry;
+ $$baserom_entry = ( $offset + $$rom_entry );
+ $$rom_entry = $old_entry;
+ }
+}
+
+my @romfiles = @ARGV;
+my @roms = map { my $rom = new Option::ROM; $rom->load($_); $rom } @romfiles;
+
+my $baserom = shift @roms;
+my $offset = $baserom->length;
+
+foreach my $rom ( @roms ) {
+
+ # Update base length
+ $baserom->{length} += $rom->{length};
+
+ # Merge initialisation entry point
+ merge_entry_points ( $baserom->{init}, $rom->{init}, $offset );
+
+ # Merge BOFM header
+ merge_entry_points ( $baserom->{bofm_header}, $rom->{bofm_header}, $offset );
+
+ # Update PCI header, if present in both
+ my $baserom_pci = $baserom->pci_header;
+ my $rom_pci = $rom->pci_header;
+ if ( $baserom_pci && $rom_pci ) {
+
+ # Update PCI lengths
+ $baserom_pci->{image_length} += $rom_pci->{image_length};
+ if ( exists $baserom_pci->{runtime_length} ) {
+ if ( exists $rom_pci->{runtime_length} ) {
+ $baserom_pci->{runtime_length} += $rom_pci->{runtime_length};
+ } else {
+ $baserom_pci->{runtime_length} += $rom_pci->{image_length};
+ }
+ }
+
+ # Merge CLP entry point
+ if ( exists ( $baserom_pci->{clp_entry} ) &&
+ exists ( $rom_pci->{clp_entry} ) ) {
+ merge_entry_points ( $baserom_pci->{clp_entry}, $rom_pci->{clp_entry},
+ $offset );
+ }
+ }
+
+ # Update PnP header, if present in both
+ my $baserom_pnp = $baserom->pnp_header;
+ my $rom_pnp = $rom->pnp_header;
+ if ( $baserom_pnp && $rom_pnp ) {
+ merge_entry_points ( $baserom_pnp->{bcv}, $rom_pnp->{bcv}, $offset );
+ merge_entry_points ( $baserom_pnp->{bdv}, $rom_pnp->{bdv}, $offset );
+ merge_entry_points ( $baserom_pnp->{bev}, $rom_pnp->{bev}, $offset );
+ }
+
+ # Fix checksum for this ROM segment
+ $rom->fix_checksum();
+
+ $offset += $rom->length;
+}
+
+$baserom->pnp_header->fix_checksum() if $baserom->pnp_header;
+$baserom->fix_checksum();
+$baserom->save ( "-" );
+foreach my $rom ( @roms ) {
+ $rom->save ( "-" );
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/modrom.pl b/contrib/syslinux-4.02/gpxe/src/util/modrom.pl
new file mode 100755
index 0000000..cdac0b9
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/modrom.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+
+use Getopt::Std;
+
+use constant MINROMSIZE => 8192;
+use constant MAXROMSIZE => 262144;
+
+use constant PCI_PTR_LOC => 0x18; # from beginning of ROM
+use constant PCI_HDR_SIZE => 0x18;
+use constant PNP_PTR_LOC => 0x1a; # from beginning of ROM
+use constant PNP_HDR_SIZE => 0x20;
+use constant PNP_CHKSUM_OFF => 0x9; # bytes from beginning of PnP header
+use constant PNP_DEVICE_OFF => 0x10; # bytes from beginning of PnP header
+use constant PCI_VEND_ID_OFF => 0x4; # bytes from beginning of PCI header
+use constant PCI_DEV_ID_OFF => 0x6; # bytes from beginning of PCI header
+use constant PCI_SIZE_OFF => 0x10; # bytes from beginning of PCI header
+
+use constant UNDI_PTR_LOC => 0x16; # from beginning of ROM
+use constant UNDI_HDR_SIZE => 0x16;
+use constant UNDI_CHKSUM_OFF => 0x05;
+
+use strict;
+
+use vars qw(%opts);
+
+use bytes;
+
+sub getromsize ($) {
+ my ($romref) = @_;
+ my $i;
+
+ print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n"
+ if (substr($$romref, 0, 2) ne "\x55\xaa");
+ my $size = ord(substr($$romref, 2, 1)) * 512;
+ for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { }
+ print STDERR "$size is a strange size for a boot ROM\n"
+ if ($size > 0 and $i > $size);
+ return ($size);
+}
+
+sub addident ($) {
+ my ($romref) = @_;
+
+ return (0) unless (my $s = $opts{'i'});
+ # include the terminating NUL byte too
+ $s .= "\x00";
+ my $len = length($s);
+ # Put the identifier in only if the space is blank
+ my $pos = length($$romref) - $len - 2;
+ return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len));
+ substr($$romref, $pos, $len) = $s;
+ return ($pos);
+}
+
+sub pcipnpheaders ($$) {
+ my ($romref, $identoffset) = @_;
+ my ($pci_hdr_offset, $pnp_hdr_offset);
+
+ $pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2));
+ $pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2));
+ # Sanity checks
+ if ($pci_hdr_offset < PCI_PTR_LOC + 2
+ or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE
+ or $pnp_hdr_offset < PNP_PTR_LOC + 2
+ or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE
+ or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR'
+ or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') {
+ $pci_hdr_offset = $pnp_hdr_offset = 0;
+ } else {
+ printf "PCI header at %#x and PnP header at %#x\n",
+ $pci_hdr_offset, $pnp_hdr_offset;
+ }
+ if ($pci_hdr_offset > 0) {
+ my ($pci_vendor_id, $pci_device_id);
+ # if no -p option, just report what's there
+ if (!defined($opts{'p'})) {
+ $pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2));
+ $pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2));
+ printf "PCI Vendor ID %#x Device ID %#x\n",
+ $pci_vendor_id, $pci_device_id;
+ } else {
+ substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2)
+ = pack('v', length($$romref) / 512);
+ ($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'});
+ substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)
+ = pack('v', oct($pci_vendor_id)) if ($pci_vendor_id);
+ substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)
+ = pack('v', oct($pci_device_id)) if ($pci_device_id);
+ }
+ }
+ if ($pnp_hdr_offset > 0 and defined($identoffset)) {
+ # Point to device id string at end of ROM image
+ substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2)
+ = pack('v', $identoffset);
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset,
+ PNP_HDR_SIZE));
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub undiheaders ($) {
+ my ($romref) = @_;
+ my ($undi_hdr_offset);
+
+ $undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2));
+ # Sanity checks
+ if ($undi_hdr_offset < UNDI_PTR_LOC + 2
+ or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE
+ or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') {
+ $undi_hdr_offset = 0;
+ } else {
+ printf "UNDI header at %#x\n", $undi_hdr_offset;
+ }
+ if ($undi_hdr_offset > 0) {
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset,
+ UNDI_HDR_SIZE));
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub writerom ($$) {
+ my ($filename, $romref) = @_;
+
+ open(R, ">$filename") or die "$filename: $!\n";
+ print R $$romref;
+ close(R);
+}
+
+sub checksum ($) {
+ my ($romref) = @_;
+
+ substr($$romref, 6, 1) = "\x00";
+ my $sum = unpack('%8C*', $$romref);
+ substr($$romref, 6, 1) = chr(256 - $sum);
+ # Double check
+ $sum = unpack('%8C*', $$romref);
+ if ($sum != 0) {
+ print "Checksum fails\n"
+ } elsif ($opts{'v'}) {
+ print "Checksum ok\n";
+ }
+}
+
+sub makerom () {
+ my ($rom, $romsize);
+
+ getopts('3xi:p:s:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ # If PXE image, just fill the length field and write it out
+ if ($opts{'x'}) {
+ substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
+ &writerom($ARGV[0], \$rom);
+ return;
+ }
+ # Size specified with -s overrides value in 3rd byte in image
+ # -s 0 means round up to next 512 byte block
+ if (defined($opts{'s'})) {
+ if (($romsize = oct($opts{'s'})) <= 0) {
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511
+ }
+ } else {
+ $romsize = &getromsize(\$rom);
+ # 0 put there by *loader.S means makerom should pick the size
+ if ($romsize == 0) {
+ # Shrink romsize down to the smallest power of two that will do
+ for ($romsize = MAXROMSIZE;
+ $romsize > MINROMSIZE and $romsize >= 2*$filesize;
+ $romsize /= 2) { }
+ }
+ }
+ if ($filesize > $romsize) {
+ print STDERR "ROM size of $romsize not big enough for data, ";
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511;
+ print "will use $romsize instead\n"
+ }
+ # Pad with 0xFF to $romsize
+ $rom .= "\xFF" x ($romsize - length($rom));
+ if ($romsize >= 128 * 1024) {
+ print "Warning: ROM size exceeds extension BIOS limit\n";
+ }
+ substr($rom, 2, 1) = chr(($romsize / 512) % 256);
+ print "ROM size is $romsize\n" if $opts{'v'};
+ my $identoffset = &addident(\$rom);
+ &pcipnpheaders(\$rom, $identoffset);
+ &undiheaders(\$rom);
+ # 3c503 requires last two bytes to be 0x80
+ substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
+ if ($opts{'3'} and $romsize == MINROMSIZE);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+sub modrom () {
+ my ($rom);
+
+ getopts('p:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ &pcipnpheaders(\$rom);
+ &undiheaders(\$rom);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+# Main routine. See how we were called and behave accordingly
+if ($0 =~ m:modrom(\.pl)?$:) {
+ &modrom();
+} else {
+ &makerom();
+}
+exit(0);
diff --git a/contrib/syslinux-4.02/gpxe/src/util/mucurses_test.c b/contrib/syslinux-4.02/gpxe/src/util/mucurses_test.c
new file mode 100644
index 0000000..586562d
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/mucurses_test.c
@@ -0,0 +1,63 @@
+#include "../include/curses.h"
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void get_iscsi_chap_secret( char * );
+void mdelay( int msecs );
+
+int main ( void ) {
+ char secret[16];
+ initscr();
+ echo();
+ werase(stdscr);
+ box( stdscr, '|', '-' );
+ get_iscsi_chap_secret(secret);
+
+ mvwprintw( stdscr, 3, 5, "password is \"%s\"", secret );
+ mdelay(2500);
+
+ stdscr->scr->exit(stdscr->scr);
+
+ return 0;
+}
+
+void get_iscsi_chap_secret( char *sec ) {
+ char *title = "Set new iSCSI CHAP secret",
+ *msg = "Configure the iSCSI access secret",
+ pw1[17], pw2[17];
+ WINDOW *secret;
+
+ secret = newwin( stdscr->height / 2,
+ stdscr->width / 2,
+ stdscr->height / 4,
+ stdscr->width / 4 );
+
+ wborder( secret, '|', '|', '-', '-', '+', '+', '+', '+' );
+ mvwprintw( secret, 1, 2, "%s", title );
+ mvwhline( secret, 2, 1, '-' | secret->attrs, secret->width - 2 );
+ mvwprintw( secret, 4, 2, "%s", msg );
+ mvwprintw( secret, 6, 3, "secret" );
+ mvwprintw( secret, 8, 3, "confirm" );
+ start:
+ mvwhline( secret, 6, 12, '_' | secret->attrs, 16 );
+ mvwhline( secret, 8, 12, '_' | secret->attrs, 16 );
+
+ wmove( secret, 6, 12 );
+ wgetnstr( secret, pw1, 16 );
+ wmove( secret, 8, 12 );
+ wgetnstr( secret, pw2, 16 );
+
+ if ( strcmp( pw1, pw2 ) == 0 ) {
+ strcpy( sec, pw1 );
+ werase( secret );
+ }
+ else {
+ mvwprintw( secret, 10, 3, "Passwords do not match" );
+ goto start;
+ }
+}
+
+void mdelay ( int msecs ) {
+ usleep( msecs * 1000 );
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/nrv2b.c b/contrib/syslinux-4.02/gpxe/src/util/nrv2b.c
new file mode 100644
index 0000000..6bac4cd
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/nrv2b.c
@@ -0,0 +1,1501 @@
+/**************************************************************
+ Form adapted from lzhuf.c
+ written by Haruyasu Yoshizaki 11/20/1988
+ some minor changes 4/6/1989
+ comments translated by Haruhiko Okumura 4/7/1989
+
+ minor beautifications and adjustments for compiling under Linux
+ by Markus Gutschke <gutschk@math.uni-muenster.de>
+ 1997-01-27
+
+ Modifications to allow use as a filter by Ken Yap
+ <ken_yap@users.sourceforge.net>.
+
+ 1997-07-01
+
+ Small mod to cope with running on big-endian machines
+ by Jim Hague <jim.hague@acm.org)
+ 1998-02-06
+
+ Make compression statistics report shorter
+ by Ken Yap <ken_yap@users.sourceforge.net>.
+ 2001-04-25
+
+ Replaced algorithm with nrv2b from ucl the compression
+ library from upx. That code is:
+ Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ And is distributed under the terms of the GPL.
+ The conversion was performed
+ by Eric Biederman <ebiederman@lnxi.com>.
+ 20 August 2002
+
+**************************************************************/
+#define UCLPACK_COMPAT 0
+#define NDEBUG 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <limits.h>
+#include <assert.h>
+#if UCLPACK_COMPAT
+#include <netinet/in.h>
+#endif
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr 0
+#else
+#define Fprintf(x) fprintf x
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+
+#ifndef ENDIAN
+#define ENDIAN 0
+#endif
+#ifndef BITSIZE
+#define BITSIZE 32
+#endif
+
+static __inline__ void Error(char *message)
+{
+ Fprintf((stderr, "\n%s\n", message));
+ exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+ unsigned long res = 0;
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ u.ul = ul;
+ for (i = 3; i >= 0; i--)
+ res = (res << 8) + u.c[i];
+ return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ for (i = 0; i < 4; i++)
+ {
+ u.c[i] = ul & 0xff;
+ ul >>= 8;
+ }
+ return u.ul;
+}
+#endif
+
+
+
+#if UCLPACK_COMPAT
+/* magic file header for compressed files */
+static const unsigned char magic[8] =
+{ 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a };
+
+#endif
+
+#ifdef ENCODE
+/********** NRV2B_99 compression **********/
+
+/* Note by limiting the ring buffer I have limited the maximum
+ * offset to 64K. Since etherboot rarely gets that big it
+ * is not a problem and it gives me a firm guarantee
+ * that I will never get a 3 byte string match that is encodes
+ * to more than 9/8 it's original size.
+ * That guaranteee is important to for the inplace decompressor.
+ * There are better ways to do this if a larger offset and buffer
+ * would give better compression.
+ */
+#define N (65536ul) /* size of ring buffer */
+#define THRESHOLD 1 /* lower limit for match length */
+#define F 2048 /* upper limit for match length */
+#define M2_MAX_OFFSET 0xd00
+
+/* note: to use default values pass -1, i.e. initialize
+ * this struct by a memset(x,0xff,sizeof(x)) */
+struct ucl_compress_config
+{
+ int bb_endian;
+ int bb_size;
+ unsigned int max_offset;
+ unsigned int max_match;
+ int s_level;
+ int h_level;
+ int p_level;
+ int c_flags;
+ unsigned int m_size;
+};
+
+struct ucl_compress
+{
+ int init;
+
+ unsigned int look; /* bytes in lookahead buffer */
+
+ unsigned int m_len;
+ unsigned int m_off;
+
+ unsigned int last_m_len;
+ unsigned int last_m_off;
+
+ const unsigned char *bp;
+ const unsigned char *ip;
+ const unsigned char *in;
+ const unsigned char *in_end;
+ unsigned char *out;
+
+ uint64_t bb_b;
+ unsigned bb_k;
+ unsigned bb_c_endian;
+ unsigned bb_c_s;
+ unsigned bb_c_s8;
+ unsigned char *bb_p;
+ unsigned char *bb_op;
+
+ struct ucl_compress_config conf;
+ unsigned int *result;
+
+ unsigned int textsize; /* text size counter */
+ unsigned int codesize; /* code size counter */
+ unsigned int printcount; /* counter for reporting progress every 1K
+ bytes */
+
+
+ /* some stats */
+ unsigned long lit_bytes;
+ unsigned long match_bytes;
+ unsigned long rep_bytes;
+ unsigned long lazy;
+};
+
+
+
+#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+#define UCL_E_OK 0
+#define UCL_E_INVALID_ARGUMENT 1
+#define UCL_E_OUT_OF_MEMORY 2
+#define UCL_E_ERROR 3
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define SWD_HSIZE 16384
+#define SWD_MAX_CHAIN 2048
+#define SWD_BEST_OFF 1
+
+#define HEAD3(b,p) \
+ (((0x9f5f*(((((uint32_t)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
+
+#define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
+#define NIL2 UINT_MAX
+
+struct ucl_swd
+{
+/* public - "built-in" */
+ unsigned int n;
+ unsigned int f;
+ unsigned int threshold;
+
+/* public - configuration */
+ unsigned int max_chain;
+ unsigned int nice_length;
+ int use_best_off;
+ unsigned int lazy_insert;
+
+/* public - output */
+ unsigned int m_len;
+ unsigned int m_off;
+ unsigned int look;
+ int b_char;
+#if defined(SWD_BEST_OFF)
+ unsigned int best_off[ SWD_BEST_OFF ];
+#endif
+
+/* semi public */
+ struct ucl_compress *c;
+ unsigned int m_pos;
+#if defined(SWD_BEST_OFF)
+ unsigned int best_pos[ SWD_BEST_OFF ];
+#endif
+
+/* private */
+ const uint8_t *dict;
+ const uint8_t *dict_end;
+ unsigned int dict_len;
+
+/* private */
+ unsigned int ip; /* input pointer (lookahead) */
+ unsigned int bp; /* buffer pointer */
+ unsigned int rp; /* remove pointer */
+ unsigned int b_size;
+
+ unsigned char *b_wrap;
+
+ unsigned int node_count;
+ unsigned int first_rp;
+
+ unsigned char b [ N + F + F ];
+ unsigned int head3 [ SWD_HSIZE ];
+ unsigned int succ3 [ N + F ];
+ unsigned int best3 [ N + F ];
+ unsigned int llen3 [ SWD_HSIZE ];
+ unsigned int head2 [ 65536U ];
+};
+
+#define s_head3(s,key) s->head3[key]
+
+
+#if !defined( NDEBUG)
+static void assert_match(const struct ucl_swd * swd, unsigned int m_len,
+ unsigned int m_off )
+
+{
+ const struct ucl_compress *c = swd->c;
+ unsigned int d_off;
+
+ assert(m_len >= 2);
+ if (m_off <= (unsigned int) (c->bp - c->in))
+ {
+ assert(c->bp - m_off + m_len < c->ip);
+ assert(memcmp(c->bp, c->bp - m_off, m_len) == 0);
+ }
+ else
+ {
+ assert(swd->dict != NULL);
+ d_off = m_off - (unsigned int) (c->bp - c->in);
+ assert(d_off <= swd->dict_len);
+ if (m_len > d_off)
+ {
+ assert(memcmp(c->bp, swd->dict_end - d_off, d_off) ==
+ 0);
+
+ assert(c->in + m_len - d_off < c->ip);
+ assert(memcmp(c->bp + d_off, c->in, m_len - d_off) ==
+ 0);
+
+ }
+ else
+ {
+ assert(memcmp(c->bp, swd->dict_end - d_off, m_len) ==
+ 0);
+
+ }
+ }
+}
+#else
+# define assert_match(a,b,c) ((void)0)
+#endif
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_initdict(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+
+{
+ s->dict = s->dict_end = NULL;
+ s->dict_len = 0;
+
+ if (!dict || dict_len <= 0)
+ return;
+ if (dict_len > s->n)
+ {
+ dict += dict_len - s->n;
+ dict_len = s->n;
+ }
+
+ s->dict = dict;
+ s->dict_len = dict_len;
+ s->dict_end = dict + dict_len;
+ memcpy(s->b,dict,dict_len);
+ s->ip = dict_len;
+}
+
+
+static
+void swd_insertdict(struct ucl_swd *s, unsigned int node, unsigned int len)
+{
+ unsigned int key;
+
+ s->node_count = s->n - len;
+ s->first_rp = node;
+
+ while (len-- > 0)
+ {
+ key = HEAD3(s->b,node);
+ s->succ3[node] = s_head3(s,key);
+ s->head3[key] = (unsigned int)(node);
+ s->best3[node] = (unsigned int)(s->f + 1);
+ s->llen3[key]++;
+ assert(s->llen3[key] <= s->n);
+
+ key = HEAD2(s->b,node);
+ s->head2[key] = (unsigned int)(node);
+
+ node++;
+ }
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+{
+ unsigned int i = 0;
+ int c = 0;
+
+ if (s->n == 0)
+ s->n = N;
+ if (s->f == 0)
+ s->f = F;
+ s->threshold = THRESHOLD;
+ if (s->n > N || s->f > F)
+ return UCL_E_INVALID_ARGUMENT;
+
+ /* defaults */
+ s->max_chain = SWD_MAX_CHAIN;
+ s->nice_length = s->f;
+ s->use_best_off = 0;
+ s->lazy_insert = 0;
+
+ s->b_size = s->n + s->f;
+ if (s->b_size + s->f >= UINT_MAX)
+ return UCL_E_ERROR;
+ s->b_wrap = s->b + s->b_size;
+ s->node_count = s->n;
+
+ memset(s->llen3, 0, sizeof(s->llen3[0]) * SWD_HSIZE);
+ for (i = 0; i < 65536U; i++)
+ s->head2[i] = NIL2;
+
+ s->ip = 0;
+ swd_initdict(s,dict,dict_len);
+ s->bp = s->ip;
+ s->first_rp = s->ip;
+
+ assert(s->ip + s->f <= s->b_size);
+
+ s->look = (unsigned int) (s->c->in_end - s->c->ip);
+ if (s->look > 0)
+ {
+ if (s->look > s->f)
+ s->look = s->f;
+ memcpy(&s->b[s->ip],s->c->ip,s->look);
+ s->c->ip += s->look;
+ s->ip += s->look;
+ }
+ if (s->ip == s->b_size)
+ s->ip = 0;
+
+ if (s->look >= 2 && s->dict_len > 0)
+ swd_insertdict(s,0,s->dict_len);
+
+ s->rp = s->first_rp;
+ if (s->rp >= s->node_count)
+ s->rp -= s->node_count;
+ else
+ s->rp += s->b_size - s->node_count;
+
+ /* unused i */
+ /* unused c */
+ return UCL_E_OK;
+}
+
+
+static
+void swd_exit(struct ucl_swd *s)
+{
+ /* unused s */
+
+}
+
+#define swd_pos2off(s,pos) \
+ (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
+
+/***********************************************************************
+//
+************************************************************************/
+
+static __inline__
+void swd_getbyte(struct ucl_swd *s)
+{
+ int c;
+
+ if ((c = getbyte(*(s->c))) < 0)
+ {
+ if (s->look > 0)
+ --s->look;
+ }
+ else
+ {
+ s->b[s->ip] = (uint8_t)(c);
+ if (s->ip < s->f)
+ s->b_wrap[s->ip] = (uint8_t)(c);
+ }
+ if (++s->ip == s->b_size)
+ s->ip = 0;
+ if (++s->bp == s->b_size)
+ s->bp = 0;
+ if (++s->rp == s->b_size)
+ s->rp = 0;
+}
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+
+static __inline__
+void swd_remove_node(struct ucl_swd *s, unsigned int node)
+{
+ if (s->node_count == 0)
+ {
+ unsigned int key;
+
+#ifdef UCL_DEBUG
+ if (s->first_rp != UINT_MAX)
+ {
+ if (node != s->first_rp)
+ printf("Remove %5d: %5d %5d %5d %5d %6d %6d\n",
+
+ node, s->rp, s->ip, s->bp, s->first_rp,
+ s->ip - node, s->ip - s->bp);
+ assert(node == s->first_rp);
+ s->first_rp = UINT_MAX;
+ }
+#endif
+
+ key = HEAD3(s->b,node);
+ assert(s->llen3[key] > 0);
+ --s->llen3[key];
+
+ key = HEAD2(s->b,node);
+ assert(s->head2[key] != NIL2);
+ if ((unsigned int) s->head2[key] == node)
+ s->head2[key] = NIL2;
+ }
+ else
+ --s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_accept(struct ucl_swd *s, unsigned int n)
+{
+ assert(n <= s->look);
+
+ if (n > 0) do
+ {
+ unsigned int key;
+
+ swd_remove_node(s,s->rp);
+
+ /* add bp into HEAD3 */
+ key = HEAD3(s->b,s->bp);
+ s->succ3[s->bp] = s_head3(s,key);
+ s->head3[key] = (unsigned int)(s->bp);
+ s->best3[s->bp] = (unsigned int)(s->f + 1);
+ s->llen3[key]++;
+ assert(s->llen3[key] <= s->n);
+
+ /* add bp into HEAD2 */
+ key = HEAD2(s->b,s->bp);
+ s->head2[key] = (unsigned int)(s->bp);
+
+ swd_getbyte(s);
+ } while (--n > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_search(struct ucl_swd *s, unsigned int node, unsigned int cnt)
+{
+ const unsigned char *p1;
+ const unsigned char *p2;
+ const unsigned char *px;
+
+ unsigned int m_len = s->m_len;
+ const unsigned char * b = s->b;
+ const unsigned char * bp = s->b + s->bp;
+ const unsigned char * bx = s->b + s->bp + s->look;
+ unsigned char scan_end1;
+
+ assert(s->m_len > 0);
+
+ scan_end1 = bp[m_len - 1];
+ for ( ; cnt-- > 0; node = s->succ3[node])
+ {
+ p1 = bp;
+ p2 = b + node;
+ px = bx;
+
+ assert(m_len < s->look);
+
+ if (
+ p2[m_len - 1] == scan_end1 &&
+ p2[m_len] == p1[m_len] &&
+ p2[0] == p1[0] &&
+ p2[1] == p1[1])
+ {
+ unsigned int i;
+ assert(memcmp(bp,&b[node],3) == 0);
+
+ p1 += 2; p2 += 2;
+ do {} while (++p1 < px && *p1 == *++p2);
+ i = p1 - bp;
+
+#ifdef UCL_DEBUG
+ if (memcmp(bp,&b[node],i) != 0)
+ printf("%5ld %5ld %02x%02x %02x%02x\n",
+ (long)s->bp, (long) node,
+ bp[0], bp[1], b[node], b[node+1]);
+#endif
+ assert(memcmp(bp,&b[node],i) == 0);
+
+#if defined(SWD_BEST_OFF)
+ if (i < SWD_BEST_OFF)
+ {
+ if (s->best_pos[i] == 0)
+ s->best_pos[i] = node + 1;
+ }
+#endif
+ if (i > m_len)
+ {
+ s->m_len = m_len = i;
+ s->m_pos = node;
+ if (m_len == s->look)
+ return;
+ if (m_len >= s->nice_length)
+ return;
+ if (m_len > (unsigned int) s->best3[node])
+ return;
+ scan_end1 = bp[m_len - 1];
+ }
+ }
+ }
+}
+
+static int swd_search2(struct ucl_swd *s)
+{
+ unsigned int key;
+
+ assert(s->look >= 2);
+ assert(s->m_len > 0);
+
+ key = s->head2[ HEAD2(s->b,s->bp) ];
+ if (key == NIL2)
+ return 0;
+#ifdef UCL_DEBUG
+ if (memcmp(&s->b[s->bp],&s->b[key],2) != 0)
+ printf("%5ld %5ld %02x%02x %02x%02x\n", (long)s->bp, (long)key,
+ s->b[s->bp], s->b[s->bp+1], s->b[key], s->b[key+1]);
+#endif
+ assert(memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+ if (s->best_pos[2] == 0)
+ s->best_pos[2] = key + 1;
+#endif
+
+ if (s->m_len < 2)
+ {
+ s->m_len = 2;
+ s->m_pos = key;
+ }
+ return 1;
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_findbest(struct ucl_swd *s)
+{
+ unsigned int key;
+ unsigned int cnt, node;
+ unsigned int len;
+
+ assert(s->m_len > 0);
+
+ /* get current head, add bp into HEAD3 */
+ key = HEAD3(s->b,s->bp);
+ node = s->succ3[s->bp] = s_head3(s,key);
+ cnt = s->llen3[key]++;
+ assert(s->llen3[key] <= s->n + s->f);
+ if (cnt > s->max_chain && s->max_chain > 0)
+ cnt = s->max_chain;
+ s->head3[key] = (unsigned int)(s->bp);
+
+ s->b_char = s->b[s->bp];
+ len = s->m_len;
+ if (s->m_len >= s->look)
+ {
+ if (s->look == 0)
+ s->b_char = -1;
+ s->m_off = 0;
+ s->best3[s->bp] = (unsigned int)(s->f + 1);
+ }
+ else
+ {
+ if (swd_search2(s))
+ if (s->look >= 3)
+ swd_search(s,node,cnt);
+ if (s->m_len > len)
+ s->m_off = swd_pos2off(s,s->m_pos);
+ s->best3[s->bp] = (unsigned int)(s->m_len);
+
+#if defined(SWD_BEST_OFF)
+ if (s->use_best_off)
+ {
+ int i;
+ for (i = 2; i < SWD_BEST_OFF; i++)
+ if (s->best_pos[i] > 0)
+ s->best_off[i] =
+ swd_pos2off(s,s->best_pos[i]-1);
+
+ else
+ s->best_off[i] = 0;
+ }
+#endif
+ }
+
+ swd_remove_node(s,s->rp);
+
+ /* add bp into HEAD2 */
+ key = HEAD2(s->b,s->bp);
+ s->head2[key] = (unsigned int)(s->bp);
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+init_match ( struct ucl_compress *c, struct ucl_swd *s,
+ const uint8_t *dict, unsigned int dict_len,
+ uint32_t flags )
+{
+ int r;
+
+ assert(!c->init);
+ c->init = 1;
+
+ s->c = c;
+
+ c->last_m_len = c->last_m_off = 0;
+
+ c->textsize = c->codesize = c->printcount = 0;
+ c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
+ c->lazy = 0;
+
+ r = swd_init(s,dict,dict_len);
+ if (r != UCL_E_OK)
+ {
+ swd_exit(s);
+ return r;
+ }
+
+ s->use_best_off = (flags & 1) ? 1 : 0;
+ return UCL_E_OK;
+}
+
+static int
+find_match ( struct ucl_compress *c, struct ucl_swd *s,
+ unsigned int this_len, unsigned int skip )
+{
+ assert(c->init);
+
+ if (skip > 0)
+ {
+ assert(this_len >= skip);
+ swd_accept(s, this_len - skip);
+ c->textsize += this_len - skip + 1;
+ }
+ else
+ {
+ assert(this_len <= 1);
+ c->textsize += this_len - skip;
+ }
+
+ s->m_len = THRESHOLD;
+#ifdef SWD_BEST_OFF
+ if (s->use_best_off)
+ memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+ swd_findbest(s);
+ c->m_len = s->m_len;
+ c->m_off = s->m_off;
+
+ swd_getbyte(s);
+
+ if (s->b_char < 0)
+ {
+ c->look = 0;
+ c->m_len = 0;
+ swd_exit(s);
+ }
+ else
+ {
+ c->look = s->look + 1;
+ }
+ c->bp = c->ip - c->look;
+
+#if 0
+ /* brute force match search */
+ if (c->m_len > THRESHOLD && c->m_len + 1 <= c->look)
+ {
+ const uint8_t *ip = c->bp;
+ const uint8_t *m = c->bp - c->m_off;
+ const uint8_t *in = c->in;
+
+ if (ip - in > N)
+ in = ip - N;
+ for (;;)
+ {
+ while (*in != *ip)
+ in++;
+ if (in == ip)
+ break;
+ if (in != m)
+ if (memcmp(in,ip,c->m_len+1) == 0)
+ printf("%p %p %p %5d\n",in,ip,m,c->m_len);
+
+ in++;
+ }
+ }
+#endif
+
+ return UCL_E_OK;
+}
+
+
+static int bbConfig(struct ucl_compress *c, int endian, int bitsize)
+{
+ if (endian != -1)
+ {
+ if (endian != 0)
+ return UCL_E_ERROR;
+ c->bb_c_endian = endian;
+ }
+ if (bitsize != -1)
+ {
+ if (bitsize != 8 && bitsize != 16 && bitsize != 32 && bitsize != 64)
+ return UCL_E_ERROR;
+ c->bb_c_s = bitsize;
+ c->bb_c_s8 = bitsize / 8;
+ }
+ c->bb_b = 0; c->bb_k = 0;
+ c->bb_p = NULL;
+ c->bb_op = NULL;
+ return UCL_E_OK;
+}
+
+static void bbWriteBits(struct ucl_compress *c)
+{
+ uint8_t *p = c->bb_p;
+ uint64_t b = c->bb_b;
+
+ p[0] = (uint8_t)(b >> 0);
+ if (c->bb_c_s >= 16)
+ {
+ p[1] = (uint8_t)(b >> 8);
+ if (c->bb_c_s >= 32)
+ {
+ p[2] = (uint8_t)(b >> 16);
+ p[3] = (uint8_t)(b >> 24);
+ if (c->bb_c_s == 64)
+ {
+ p[4] = (uint8_t)(b >> 32);
+ p[5] = (uint8_t)(b >> 40);
+ p[6] = (uint8_t)(b >> 48);
+ p[7] = (uint8_t)(b >> 56);
+ }
+ }
+ }
+}
+
+
+static void bbPutBit(struct ucl_compress *c, unsigned bit)
+{
+ assert(bit == 0 || bit == 1);
+ assert(c->bb_k <= c->bb_c_s);
+
+ if (c->bb_k < c->bb_c_s)
+ {
+ if (c->bb_k == 0)
+ {
+ assert(c->bb_p == NULL);
+ c->bb_p = c->bb_op;
+ c->bb_op += c->bb_c_s8;
+ }
+ assert(c->bb_p != NULL);
+ assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+ c->bb_b = (c->bb_b << 1) + bit;
+ c->bb_k++;
+ }
+ else
+ {
+ assert(c->bb_p != NULL);
+ assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+ bbWriteBits(c);
+ c->bb_p = c->bb_op;
+ c->bb_op += c->bb_c_s8;
+ c->bb_b = bit;
+ c->bb_k = 1;
+ }
+}
+
+
+static void bbPutByte(struct ucl_compress *c, unsigned b)
+{
+ /**printf("putbyte %p %p %x (%d)\n", op, bb_p, x, bb_k);*/
+ assert(c->bb_p == NULL || c->bb_p + c->bb_c_s8 <= c->bb_op);
+ *c->bb_op++ = (uint8_t)(b);
+}
+
+static void bbFlushBits(struct ucl_compress *c, unsigned filler_bit)
+{
+ if (c->bb_k > 0)
+ {
+ assert(c->bb_k <= c->bb_c_s);
+ while (c->bb_k != c->bb_c_s)
+ bbPutBit(c, filler_bit);
+ bbWriteBits(c);
+ c->bb_k = 0;
+ }
+ c->bb_p = NULL;
+}
+
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static void code_prefix_ss11(struct ucl_compress *c, uint32_t i)
+{
+ if (i >= 2)
+ {
+ uint32_t t = 4;
+ i += 2;
+ do {
+ t <<= 1;
+ } while (i >= t);
+ t >>= 1;
+ do {
+ t >>= 1;
+ bbPutBit(c, (i & t) ? 1 : 0);
+ bbPutBit(c, 0);
+ } while (t > 2);
+ }
+ bbPutBit(c, (unsigned)i & 1);
+ bbPutBit(c, 1);
+}
+
+static void
+code_match(struct ucl_compress *c, unsigned int m_len, const unsigned int m_off)
+
+{
+ while (m_len > c->conf.max_match)
+ {
+ code_match(c, c->conf.max_match - 3, m_off);
+ m_len -= c->conf.max_match - 3;
+ }
+
+ c->match_bytes += m_len;
+ if (m_len > c->result[3])
+ c->result[3] = m_len;
+ if (m_off > c->result[1])
+ c->result[1] = m_off;
+
+ bbPutBit(c, 0);
+
+ if (m_off == c->last_m_off)
+ {
+ bbPutBit(c, 0);
+ bbPutBit(c, 1);
+ }
+ else
+ {
+ code_prefix_ss11(c, 1 + ((m_off - 1) >> 8));
+ bbPutByte(c, (unsigned)m_off - 1);
+ }
+ m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
+ if (m_len >= 4)
+ {
+ bbPutBit(c,0);
+ bbPutBit(c,0);
+ code_prefix_ss11(c, m_len - 4);
+ }
+ else
+ {
+ bbPutBit(c, m_len > 1);
+ bbPutBit(c, (unsigned)m_len & 1);
+ }
+
+ c->last_m_off = m_off;
+}
+
+static void
+code_run(struct ucl_compress *c, const uint8_t *ii, unsigned int lit)
+{
+ if (lit == 0)
+ return;
+ c->lit_bytes += lit;
+ if (lit > c->result[5])
+ c->result[5] = lit;
+ do {
+ bbPutBit(c, 1);
+ bbPutByte(c, *ii++);
+ } while (--lit > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+len_of_coded_match(struct ucl_compress *c, unsigned int m_len, unsigned int
+ m_off)
+
+{
+ int b;
+ if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+ || m_off > c->conf.max_offset)
+ return -1;
+ assert(m_off > 0);
+
+ m_len = m_len - 2 - (m_off > M2_MAX_OFFSET);
+
+ if (m_off == c->last_m_off)
+ b = 1 + 2;
+ else
+ {
+ b = 1 + 10;
+ m_off = (m_off - 1) >> 8;
+ while (m_off > 0)
+ {
+ b += 2;
+ m_off >>= 1;
+ }
+ }
+
+ b += 2;
+ if (m_len < 3)
+ return b;
+ m_len -= 3;
+
+ do {
+ b += 2;
+ m_len >>= 1;
+ } while (m_len > 0);
+
+ return b;
+}
+
+int ucl_nrv2b_99_compress(
+ const uint8_t *in, unsigned long in_len,
+ uint8_t *out, unsigned long *out_len,
+ unsigned int *result)
+{
+ const uint8_t *ii;
+ unsigned int lit;
+ unsigned int m_len, m_off;
+ struct ucl_compress c_buffer;
+ struct ucl_compress * const c = &c_buffer;
+ struct ucl_swd *swd;
+ unsigned int result_buffer[16];
+ int r;
+
+/* max compression */
+#define SC_TRY_LAZY 2
+#define SC_GOOD_LENGTH F
+#define SC_MAX_LAZY F
+#define SC_NICE_LENGTH F
+#define SC_MAX_CHAIN 4096
+#define SC_FLAGS 1
+#define SC_MAX_OFFSET N
+
+ memset(c, 0, sizeof(*c));
+ c->ip = c->in = in;
+ c->in_end = in + in_len;
+ c->out = out;
+ c->result = result ? result : result_buffer;
+ memset(c->result, 0, 16*sizeof(*c->result));
+ c->result[0] = c->result[2] = c->result[4] = UINT_MAX;
+ result = NULL;
+ memset(&c->conf, 0xff, sizeof(c->conf));
+ r = bbConfig(c, ENDIAN, BITSIZE);
+ if (r == 0)
+ r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size);
+ if (r != 0)
+ return UCL_E_INVALID_ARGUMENT;
+ c->bb_op = out;
+
+ ii = c->ip; /* point to start of literal run */
+ lit = 0;
+
+
+ swd = (struct ucl_swd *) malloc(sizeof(*swd));
+ if (!swd)
+ return UCL_E_OUT_OF_MEMORY;
+
+ swd->f = F;
+ swd->n = N;
+ if (in_len >= 256 && in_len < swd->n)
+ swd->n = in_len;
+ if (swd->f < 8 || swd->n < 256)
+ return UCL_E_INVALID_ARGUMENT;
+
+ r = init_match(c,swd,NULL,0, SC_FLAGS);
+ if (r != UCL_E_OK)
+ {
+ free(swd);
+ return r;
+ }
+ if (SC_MAX_CHAIN > 0)
+ swd->max_chain = SC_MAX_CHAIN;
+ if (SC_NICE_LENGTH > 0)
+ swd->nice_length = SC_NICE_LENGTH;
+ if (c->conf.max_match < swd->nice_length)
+ swd->nice_length = c->conf.max_match;
+
+ c->last_m_off = 1;
+ r = find_match(c,swd,0,0);
+ if (r != UCL_E_OK)
+ return r;
+ while (c->look > 0)
+ {
+ unsigned int ahead;
+ unsigned int max_ahead;
+ int l1, l2;
+
+ c->codesize = c->bb_op - out;
+
+ m_len = c->m_len;
+ m_off = c->m_off;
+
+ assert(c->bp == c->ip - c->look);
+ assert(c->bp >= in);
+ if (lit == 0)
+ ii = c->bp;
+ assert(ii + lit == c->bp);
+ assert(swd->b_char == *(c->bp));
+
+ if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+ || m_off > c->conf.max_offset)
+ {
+ /* a literal */
+ lit++;
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,1,0);
+ assert(r == 0);
+ continue;
+ }
+
+ /* a match */
+ assert_match(swd,m_len,m_off);
+
+ /* shall we try a lazy match ? */
+ ahead = 0;
+ if (SC_TRY_LAZY <= 0 || m_len >= SC_MAX_LAZY || m_off ==
+ c->last_m_off)
+
+ {
+ /* no */
+ l1 = 0;
+ max_ahead = 0;
+ }
+ else
+ {
+ /* yes, try a lazy match */
+ l1 = len_of_coded_match(c,m_len,m_off);
+ assert(l1 > 0);
+ max_ahead = SC_TRY_LAZY;
+ if ((m_len - 1) < max_ahead) {
+ max_ahead = m_len -1;
+ }
+ }
+
+ while (ahead < max_ahead && c->look > m_len)
+ {
+ if (m_len >= SC_GOOD_LENGTH)
+ swd->max_chain = SC_MAX_CHAIN >> 2;
+ else
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,1,0);
+ ahead++;
+
+ assert(r == 0);
+ assert(c->look > 0);
+ assert(ii + lit + ahead == c->bp);
+
+ if (c->m_len < 2)
+ continue;
+ l2 = len_of_coded_match(c,c->m_len,c->m_off);
+ if (l2 < 0)
+ continue;
+ if (l1 + (int)(ahead + c->m_len - m_len) * 5 > l2 +
+ (int)(ahead) * 9)
+ {
+ c->lazy++;
+ assert_match(swd,c->m_len,c->m_off);
+ lit += ahead;
+ assert(ii + lit == c->bp);
+ goto lazy_match_done;
+ }
+ }
+
+ assert(ii + lit + ahead == c->bp);
+
+ /* 1 - code run */
+ code_run(c,ii,lit);
+ lit = 0;
+
+ /* 2 - code match */
+ code_match(c,m_len,m_off);
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,m_len,1+ahead);
+ assert(r == 0);
+
+ lazy_match_done: ;
+ }
+
+ /* store final run */
+ code_run(c,ii,lit);
+
+ /* EOF */
+ bbPutBit(c, 0);
+ code_prefix_ss11(c, 0x1000000U);
+ bbPutByte(c, 0xff);
+
+ bbFlushBits(c, 0);
+
+ assert(c->textsize == in_len);
+ c->codesize = c->bb_op - out;
+ *out_len = c->bb_op - out;
+
+#if 0
+ printf("%7ld %7ld -> %7ld %7ld %7ld %ld (max: %d %d %d)\n",
+ (long) c->textsize, (long) in_len, (long) c->codesize,
+ c->match_bytes, c->lit_bytes, c->lazy,
+ c->result[1], c->result[3], c->result[5]);
+#endif
+ assert(c->lit_bytes + c->match_bytes == in_len);
+
+ swd_exit(swd);
+ free(swd);
+
+ return UCL_E_OK;
+}
+
+
+void Encode(void) /* compression */
+{
+ uint8_t *in, *out;
+ unsigned long in_len, out_len;
+ uint32_t tw;
+ int r;
+ fseek(infile, 0, SEEK_END);
+ in_len = ftell(infile);
+#ifdef VERBOSE
+ if ((signed long)in_len < 0)
+ Fprintf((stderr, "Errno: %d", errno));
+#endif
+#if UCLPACK_COMPAT
+ {
+ uint8_t byte;
+ if (fwrite(magic, sizeof(magic), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(0); /* flags */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+ byte = 0x2b; /* method */
+ if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+ Error("Can't write.");
+ byte = 10; /* level */
+ if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(256*1024); /* block_size */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(in_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* output size of text */
+ }
+#else
+ tw = host_to_i86ul(in_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* output size of text */
+#endif
+ if (in_len == 0)
+ return;
+ rewind(infile);
+
+ in = malloc(in_len);
+ out_len = in_len + (in_len/8) + 256;
+ out = malloc(out_len);
+ if (!in || !out) {
+ Error("Can't malloc");
+ }
+ if (fread(in, in_len, 1, infile) != 1) {
+ Error("Can't read");
+ }
+ r = ucl_nrv2b_99_compress(in, in_len, out, &out_len, 0 );
+ if (r != UCL_E_OK)
+ Error("Compression failure\n");
+#if UCLPACK_COMPAT
+ tw = htonl(out_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* file size of text */
+
+#endif
+ if (fwrite(out, out_len, 1, outfile) != 1) {
+ Error("Write error\n");
+ }
+#if UCLPACK_COMPAT
+ tw = htonl(0); /* EOF marker */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+
+#endif
+
+#ifdef LONG_REPORT
+ Fprintf((stdout, "input size %ld bytes\n", in_len));
+ Fprintf((stdout, "output size %ld bytes\n", out_len));
+ Fprintf((stdout, "input/output %.3f\n", (double)in_len / out_len));
+#else
+ Fprintf((stdout, "input/output = %ld/%ld = %.3f\n", in_len, out_len,
+ (double)in_len / out_len));
+#endif
+
+}
+
+#endif
+
+#ifdef DECODE
+
+#define GETBIT_8(bb, src, ilen) \
+ (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
+
+#define GETBIT_LE16(bb, src, ilen) \
+ (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))
+
+#define GETBIT_LE32(bb, src, ilen) \
+ (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
+ bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))
+
+#define GETBIT_LE64(bb, src, ilen) \
+ (bc > 0 ? ((bb>>--bc)&1) : (bc=63, \
+ bb=*(const uint64_t *)((src)+ilen),ilen+=8,(bb>>63)&1))
+
+#if ENDIAN == 0 && BITSIZE == 8
+#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 16
+#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 32
+#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 64
+#define GETBIT(bb, src, ilen) GETBIT_LE64(bb, src, ilen)
+#endif
+#ifndef GETBIT
+#error "Bad Combination of ENDIAN and BITSIZE values specified"
+#endif
+
+#undef SAFE
+
+#ifdef SAFE
+#define FAIL(x,r) if (x) { Error(r); }
+#else
+#define FAIL(x,r)
+#endif
+
+void Decode(void) /* recover */
+{
+ uint32_t tw;
+ uint8_t *src, *dst;
+ unsigned long max_src_len, src_len, dst_len;
+ unsigned long ilen = 0, olen = 0, last_m_off = 1;
+#if BITSIZE <= 32
+ uint32_t bb = 0;
+#elif BITSIZE == 64
+ uint64_t bb = 0;
+#endif
+ unsigned bc = 0;
+#if UCLPACK_COMPAT
+ if (fseek(infile, sizeof(magic) + sizeof(tw) + 1 + 1 + sizeof(tw),
+ SEEK_SET) != 0)
+
+ Error("Seek Error");
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ dst_len = ntohl(tw);
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of file */
+ max_src_len = ntohl(tw);
+#else
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ dst_len = i86ul_to_host(tw);
+ max_src_len = dst_len + (dst_len/8) + 256;
+#endif
+ if (dst_len == 0)
+ return;
+ dst = malloc(dst_len);
+ if (!dst)
+ Error("Can't malloc");
+ src = malloc(max_src_len);
+ if (!src)
+ Error("Can't malloc");
+ src_len = fread(src, 1, max_src_len, infile);
+ if (src_len <= 0)
+ Error("Can't read");
+
+ for(;;) {
+ unsigned int m_off, m_len;
+ while(GETBIT(bb, src, ilen)) {
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(olen >= dst_len, "output overrun");
+ dst[olen++] = src[ilen++];
+ }
+ m_off = 1;
+ do {
+ m_off = m_off*2 + GETBIT(bb, src, ilen);
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(m_off > 0xffffffU +3, "lookbehind overrun");
+ } while (!GETBIT(bb, src, ilen));
+ if (m_off == 2)
+ {
+ m_off = last_m_off;
+ }
+ else
+ {
+ FAIL(ilen >= src_len, "input overrun");
+ m_off = (m_off - 3)*256 + src[ilen++];
+ if (m_off == 0xffffffffU)
+ break;
+ last_m_off = ++m_off;
+ }
+ m_len = GETBIT(bb, src, ilen);
+ m_len = m_len*2 + GETBIT(bb, src, ilen);
+ if (m_len == 0)
+ {
+ m_len++;
+ do {
+ m_len = m_len*2 + GETBIT(bb, src, ilen);
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(m_len >= dst_len, "output overrun");
+ } while(!GETBIT(bb, src, ilen));
+ m_len += 2;
+ }
+ m_len += (m_off > 0xd00);
+ FAIL(olen + m_len > dst_len, "output overrun");
+ FAIL(m_off > olen, "lookbeind overrun");
+ {
+ const uint8_t *m_pos;
+ m_pos = dst + olen - m_off;
+ dst[olen++] = *m_pos++;
+ do {
+ dst[olen++] = *m_pos++;
+ } while(--m_len > 0);
+ }
+ }
+ FAIL(ilen < src_len, "input not consumed");
+ FAIL(ilen > src_len, "input overrun");
+ assert(ilen == src_len);
+ Fprintf((stderr, "%12ld\n", olen));
+ if (dst_len != olen) {
+ fprintf(stderr, "length != expected length\n");
+ }
+ if (fwrite(dst, olen, 1, outfile) != 1)
+ Error("Write error\n");
+ free(src);
+ free(dst);
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+ char *s;
+ FILE *f;
+ int c;
+
+ if (argc == 2) {
+ outfile = stdout;
+ if ((f = tmpfile()) == NULL) {
+ perror("tmpfile");
+ return EXIT_FAILURE;
+ }
+ while ((c = getchar()) != EOF)
+ fputc(c, f);
+ rewind(infile = f);
+ }
+ else if (argc != 4) {
+ Fprintf((stderr, "'nrv2b e file1 file2' encodes file1 into file2.\n"
+ "'nrv2b d file2 file1' decodes file2 into file1.\n"));
+ return EXIT_FAILURE;
+ }
+ if (argc == 4) {
+ if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+ || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
+ || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+ Fprintf((stderr, "??? %s\n", s));
+ return EXIT_FAILURE;
+ }
+ }
+ if (toupper(*argv[1]) == 'E')
+ Encode();
+ else
+ Decode();
+ fclose(infile);
+ fclose(outfile);
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/contrib/syslinux-4.02/gpxe/src/util/padimg.pl b/contrib/syslinux-4.02/gpxe/src/util/padimg.pl
new file mode 100755
index 0000000..4421aaf
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/padimg.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Fcntl;
+
+my $verbosity = 0;
+my $blksize = 512;
+my $byte = 0;
+
+my %opts = (
+ 'verbose|v+' => sub { $verbosity++; },
+ 'quiet|q+' => sub { $verbosity--; },
+ 'blksize|s=o' => sub { $blksize = $_[1]; },
+ 'byte|b=o' => sub { $byte = $_[1]; },
+);
+
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
+GetOptions ( %opts ) or die "Could not parse command-line options\n";
+
+while ( my $filename = shift ) {
+ die "$filename is not a file\n" unless -f $filename;
+ my $oldsize = -s $filename;
+ my $padsize = ( ( -$oldsize ) % $blksize );
+ my $newsize = ( $oldsize + $padsize );
+ next unless $padsize;
+ if ( $verbosity >= 1 ) {
+ printf "Padding %s from %d to %d bytes with %d x 0x%02x\n",
+ $filename, $oldsize, $newsize, $padsize, $byte;
+ }
+ if ( $byte ) {
+ sysopen ( my $fh, $filename, ( O_WRONLY | O_APPEND ) )
+ or die "Could not open $filename for appending: $!\n";
+ syswrite $fh, ( chr ( $byte ) x $padsize )
+ or die "Could not append to $filename: $!\n";
+ close ( $fh );
+ } else {
+ truncate $filename, $newsize
+ or die "Could not resize $filename: $!\n";
+ }
+ die "Failed to pad $filename\n"
+ unless ( ( ( -s $filename ) % $blksize ) == 0 );
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/util/parserom.pl b/contrib/syslinux-4.02/gpxe/src/util/parserom.pl
new file mode 100644
index 0000000..578eb1d
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/parserom.pl
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+#
+# Parse PCI_ROM and ISA_ROM entries from a source file on stdin and
+# output the relevant Makefile variable definitions to stdout
+#
+# Based upon portions of Ken Yap's genrules.pl
+
+use strict;
+use warnings;
+
+die "Syntax: $0 driver_source.c" unless @ARGV == 1;
+my $source = shift;
+open DRV, "<$source" or die "Could not open $source: $!\n";
+
+( my $family, my $driver_name ) = ( $source =~ /^(.*?([^\/]+))\..$/ )
+ or die "Could not parse source file name \"$source\"\n";
+
+my $printed_family;
+
+sub rom {
+ ( my $type, my $image, my $desc, my $vendor, my $device ) = @_;
+ my $ids = $vendor ? "$vendor,$device" : "-";
+ unless ( $printed_family ) {
+ print "\n";
+ print "# NIC\t\n";
+ print "# NIC\tfamily\t$family\n";
+ print "DRIVERS += $driver_name\n";
+ $printed_family = 1;
+ }
+ print "\n";
+ 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";
+ print "ROMS_$driver_name += $image\n";
+}
+
+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", $image, $desc, $vendor, $device );
+ rom ( "pci", lc "${vendor}${device}", $desc, $vendor, $device );
+ } 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";
+ }
+}
+
+close DRV;
diff --git a/contrib/syslinux-4.02/gpxe/src/util/sortobjdump.pl b/contrib/syslinux-4.02/gpxe/src/util/sortobjdump.pl
new file mode 100755
index 0000000..1373a7f
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/sortobjdump.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+# Sort the symbol table portion of the output of objdump -ht by
+# section, then by symbol value, then by size. Used to enhance the
+# linker maps produced by "make bin/%.map" by also showing the values
+# of all non-global symbols.
+
+my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" );
+my %lines;
+while ( <> ) {
+ if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) {
+ # It's a header line containing a section definition; extract the
+ # section index and store it. Also print the header line.
+ print;
+ ( my $index, my $section ) = ( $1, $2 );
+ $section_idx{$section} = sprintf ( "%02d", $index );
+ } elsif ( /^([0-9a-fA-F]+)\s.*?\s([\.\*]\S+)\s+([0-9a-fA-F]+)\s+(\S+)/ ) {
+ # It's a symbol line - store it in the hash, indexed by
+ # "<section_index>:<value>:<size>:<end_tag>". <end_tag> is "0" if
+ # the symbol name is of the form xxx_end, "1" otherwise; this is
+ # done so that table end markers show up before any other symbols
+ # with the same value.
+ ( my $value, my $section, my $size, my $name ) = ( $1, $2, $3, $4 );
+ die "Unrecognised section \"$section\"\n"
+ unless exists $section_idx{$section};
+ my $section_idx = $section_idx{$section};
+ my $end = ( $name =~ /_end$/ ) ? "0" : "1";
+ my $key = $section_idx.":".$value.":".$size.":".$end;
+ $lines{$key} ||= '';
+ $lines{$key} .= $_;
+ } else {
+ # It's a generic header line: just print it.
+ print;
+ }
+}
+
+print $lines{$_} foreach sort keys %lines;
diff --git a/contrib/syslinux-4.02/gpxe/src/util/swapdevids.pl b/contrib/syslinux-4.02/gpxe/src/util/swapdevids.pl
new file mode 100755
index 0000000..c6255ae
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/swapdevids.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+#
+# Program to reverse the device identifier IDs in the PCIR and PnP
+# structures in a ROM for old non-compliant BIOSes
+#
+# GPL, Ken Yap 2001
+#
+
+use bytes;
+
+use IO::Seekable;
+
+sub swaplocs ($$$)
+{
+ my ($dataref, $loc1, $loc2) = @_;
+ my ($t);
+
+ $t = substr($$dataref, $loc1, 1);
+ substr($$dataref, $loc1, 1) = substr($$dataref, $loc2, 1);
+ substr($$dataref, $loc2, 1) = $t;
+}
+
+sub printdevids ($$)
+{
+ my ($dataref, $loc) = @_;
+
+ return (sprintf "%02x %02x %02x", unpack('C3', substr($$dataref, $loc, 3)));
+}
+
+$#ARGV >= 0 or die "Usage: $0 romimage\n";
+$file = $ARGV[0];
+open(F, "+<$file") or die "$file: $!\n";
+binmode(F);
+# Handle up to 64kB ROM images
+$len = read(F, $data, 64*1024);
+defined($len) or die "$file: $!\n";
+substr($data, 0, 2) eq "\x55\xAA" or die "$file: Not a boot ROM image\n";
+($pci, $pnp) = unpack('v2', substr($data, 0x18, 4));
+($pci < $len and $pnp < $len) or die "$file: Not a PCI PnP ROM image\n";
+(substr($data, $pci, 4) eq 'PCIR' and substr($data, $pnp, 4) eq '$PnP')
+ or die "$file: No PCI and PNP structures, not a PCI PNP ROM image\n";
+&swaplocs(\$data, $pci+13, $pci+15);
+&swaplocs(\$data, $pnp+18, $pnp+20);
+seek(F, 0, SEEK_SET) or die "$file: Cannot seek to beginning\n";
+print F $data;
+close(F);
+print "PCI devids now: ", &printdevids(\$data, $pci+13), "\n";
+print "PnP devids now: ", &printdevids(\$data, $pnp+18), "\n";
+exit(0);
diff --git a/contrib/syslinux-4.02/gpxe/src/util/symcheck.pl b/contrib/syslinux-4.02/gpxe/src/util/symcheck.pl
new file mode 100755
index 0000000..8925ca6
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/symcheck.pl
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use constant WARNING_SIZE => 512;
+
+my $symtab = {};
+
+# Scan output of "objdump -w -t bin/blib.a" and build up symbol table
+#
+my $object;
+while ( <> ) {
+ chomp;
+ if ( /^In archive/ ) {
+ # Do nothing
+ } elsif ( /^$/ ) {
+ # Do nothing
+ } elsif ( /^(\S+\.o):\s+file format/ ) {
+ $object = $1;
+ } elsif ( /^SYMBOL TABLE:/ ) {
+ # Do nothing
+ } elsif ( /^([0-9a-fA-F]+)\s(l|g|\s)......\s(\S+)\s+([0-9a-fA-F]+)\s+(\S+)$/ ) {
+ my $value = $1;
+ my $scope = $2;
+ my $section = $3;
+ my $size = $4;
+ my $symbol = $5;
+ $symtab->{$object}->{$symbol} = {
+ global => ( $scope ne "l" ),
+ section => ( $section eq "*UND*" ? undef : $section ),
+ value => ( $value ? hex ( $value ) : 0 ),
+ size => ( $size ? hex ( $size ) : 0 ),
+ };
+ } else {
+ die "Unrecognized line \"$_\"";
+ }
+}
+
+# Add symbols that we know will be generated or required by the linker
+#
+foreach my $object ( keys %$symtab ) {
+ my $obj_symbol = "obj_$object";
+ $obj_symbol =~ s/\.o$//;
+ $obj_symbol =~ s/\W/_/g;
+ $symtab->{LINKER}->{$obj_symbol} = {
+ global => 1,
+ section => undef,
+ value => 0,
+ size => 0,
+ };
+}
+foreach my $link_sym qw ( __prefix _prefix _prefix_load_offset
+ _prefix_size _prefix_progbits_size _prefix_size_pgh
+ __text16 _text16 _text16_load_offset
+ _text16_size _text16_progbits_size _text16_size_pgh
+ __data16 _data16 _data16_load_offset
+ _data16_size _data16_progbits_size _data16_size_pgh
+ __text _text __data _data _textdata_load_offset
+ _textdata_size _textdata_progbits_size
+ __rodata __bss _end
+ _payload_offset _max_align
+ _load_size _load_size_pgh _load_size_sect
+ pci_vendor_id pci_device_id ) {
+ $symtab->{LINKER}->{$link_sym} = {
+ global => 1,
+ section => '*ABS*',
+ value => 0,
+ size => 0,
+ };
+}
+
+# Add symbols that we know will be used by the debug system
+#
+foreach my $debug_sym qw ( dbg_autocolourise dbg_decolourise
+ dbg_hex_dump_da ) {
+ $symtab->{DEBUG}->{$debug_sym} = {
+ global => 1,
+ section => undef,
+ value => 0,
+ size => 0,
+ };
+}
+
+# Build up requires, provides and shares symbol tables for global
+# symbols
+#
+my $globals = {};
+while ( ( my $object, my $symbols ) = each %$symtab ) {
+ while ( ( my $symbol, my $info ) = each %$symbols ) {
+ if ( $info->{global} ) {
+ my $category;
+ if ( ! defined $info->{section} ) {
+ $category = "requires";
+ } elsif ( $info->{section} eq "*COM*" ) {
+ $category = "shares";
+ } else {
+ $category = "provides";
+ }
+ $globals->{$symbol}->{$category}->{$object} = 1;
+ }
+ }
+}
+
+# Check for multiply defined, never-defined and unused global symbols
+#
+my $problems = {};
+while ( ( my $symbol, my $info ) = each %$globals ) {
+ my @provides = keys %{$info->{provides}};
+ my @requires = keys %{$info->{requires}};
+ my @shares = keys %{$info->{shares}};
+
+ if ( ( @provides == 0 ) && ( @shares == 1 ) ) {
+ # A symbol "shared" by just a single file is actually being
+ # provided by that file; it just doesn't have an initialiser.
+ @provides = @shares;
+ @shares = ();
+ }
+
+ if ( ( @requires > 0 ) && ( @provides == 0 ) && ( @shares == 0 ) ) {
+ # No object provides this symbol, but some objects require it.
+ $problems->{$_}->{nonexistent}->{$symbol} = 1 foreach @requires;
+ }
+
+ if ( ( @requires == 0 ) && ( @provides > 0 ) ) {
+ # No object requires this symbol, but some objects provide it.
+ foreach my $provide ( @provides ) {
+ if ( $provide eq "LINKER" ) {
+ # Linker-provided symbols are exempt from this check.
+ } elsif ( $symtab->{$provide}->{$symbol}->{section} =~ /^\.tbl\./ ) {
+ # Linker tables are exempt from this check.
+ } else {
+ $problems->{$provide}->{unused}->{$symbol} = 1;
+ }
+ }
+ }
+
+ if ( ( @shares > 0 ) && ( @provides > 0 ) ) {
+ # A shared symbol is being initialised by an object
+ $problems->{$_}->{shared}->{$symbol} = 1 foreach @provides;
+ }
+
+ if ( @provides > 1 ) {
+ # A non-shared symbol is defined in multiple objects
+ $problems->{$_}->{multiples}->{$symbol} = 1 foreach @provides;
+ }
+}
+
+# Check for excessively large local symbols. Text and rodata symbols
+# are exempt from this check
+#
+while ( ( my $object, my $symbols ) = each %$symtab ) {
+ while ( ( my $symbol, my $info ) = each %$symbols ) {
+ if ( ( ! $info->{global} ) &&
+ ( ( defined $info->{section} ) &&
+ ! ( $info->{section} =~ /^(\.text|\.rodata)/ ) ) &&
+ ( $info->{size} >= WARNING_SIZE ) ) {
+ $problems->{$object}->{large}->{$symbol} = 1;
+ }
+ }
+}
+
+# Print out error messages
+#
+my $errors = 0;
+my $warnings = 0;
+foreach my $object ( sort keys %$problems ) {
+ my @nonexistent = sort keys %{$problems->{$object}->{nonexistent}};
+ my @multiples = sort keys %{$problems->{$object}->{multiples}};
+ my @unused = sort keys %{$problems->{$object}->{unused}};
+ my @shared = sort keys %{$problems->{$object}->{shared}};
+ my @large = sort keys %{$problems->{$object}->{large}};
+
+ print "WARN $object provides unused symbol $_\n" foreach @unused;
+ $warnings += @unused;
+ print "WARN $object has large static symbol $_\n" foreach @large;
+ $warnings += @large;
+ print "ERR $object requires non-existent symbol $_\n" foreach @nonexistent;
+ $errors += @nonexistent;
+ foreach my $symbol ( @multiples ) {
+ my @other_objects = sort grep { $_ ne $object }
+ keys %{$globals->{$symbol}->{provides}};
+ print "ERR $object provides symbol $symbol"
+ ." (also provided by @other_objects)\n";
+ }
+ $errors += @multiples;
+ print "ERR $object misuses shared symbol $_\n" foreach @shared;
+}
+
+print "$errors error(s), $warnings warning(s)\n";
+exit ( $errors ? 1 : 0 );
diff --git a/contrib/syslinux-4.02/gpxe/src/util/zbin.c b/contrib/syslinux-4.02/gpxe/src/util/zbin.c
new file mode 100644
index 0000000..707ae99
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/util/zbin.c
@@ -0,0 +1,383 @@
+#include <stdio.h>
+#include <sys/stat.h>
+
+#define ENCODE
+#define VERBOSE
+#include "nrv2b.c"
+FILE *infile, *outfile;
+
+#define DEBUG 0
+
+struct input_file {
+ void *buf;
+ size_t len;
+};
+
+struct output_file {
+ void *buf;
+ size_t len;
+ size_t max_len;
+};
+
+struct zinfo_common {
+ char type[4];
+ char pad[12];
+};
+
+struct zinfo_copy {
+ char type[4];
+ uint32_t offset;
+ uint32_t len;
+ uint32_t align;
+};
+
+struct zinfo_pack {
+ char type[4];
+ uint32_t offset;
+ uint32_t len;
+ uint32_t align;
+};
+
+struct zinfo_add {
+ char type[4];
+ uint32_t offset;
+ uint32_t divisor;
+ uint32_t pad;
+};
+
+union zinfo_record {
+ struct zinfo_common common;
+ struct zinfo_copy copy;
+ struct zinfo_pack pack;
+ struct zinfo_add add;
+};
+
+struct zinfo_file {
+ union zinfo_record *zinfo;
+ unsigned int num_entries;
+};
+
+static unsigned long align ( unsigned long value, unsigned long align ) {
+ return ( ( value + align - 1 ) & ~( align - 1 ) );
+}
+
+static int read_file ( const char *filename, void **buf, size_t *len ) {
+ FILE *file;
+ struct stat stat;
+
+ file = fopen ( filename, "r" );
+ if ( ! file ) {
+ fprintf ( stderr, "Could not open %s: %s\n", filename,
+ strerror ( errno ) );
+ goto err;
+ }
+
+ if ( fstat ( fileno ( file ), &stat ) < 0 ) {
+ fprintf ( stderr, "Could not stat %s: %s\n", filename,
+ strerror ( errno ) );
+ goto err;
+ }
+
+ *len = stat.st_size;
+ *buf = malloc ( *len );
+ if ( ! *buf ) {
+ fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
+ *len, filename, strerror ( errno ) );
+ goto err;
+ }
+
+ if ( fread ( *buf, 1, *len, file ) != *len ) {
+ fprintf ( stderr, "Could not read %zd bytes from %s: %s\n",
+ *len, filename, strerror ( errno ) );
+ goto err;
+ }
+
+ fclose ( file );
+ return 0;
+
+ err:
+ if ( file )
+ fclose ( file );
+ return -1;
+}
+
+static int read_input_file ( const char *filename,
+ struct input_file *input ) {
+ return read_file ( filename, &input->buf, &input->len );
+}
+
+static int read_zinfo_file ( const char *filename,
+ struct zinfo_file *zinfo ) {
+ void *buf;
+ size_t len;
+
+ if ( read_file ( filename, &buf, &len ) < 0 )
+ return -1;
+
+ if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
+ fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
+ filename, len );
+ return -1;
+ }
+
+ zinfo->zinfo = buf;
+ zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
+ return 0;
+}
+
+static int alloc_output_file ( size_t max_len, struct output_file *output ) {
+ output->len = 0;
+ output->max_len = ( max_len );
+ output->buf = malloc ( max_len );
+ if ( ! output->buf ) {
+ fprintf ( stderr, "Could not allocate %zd bytes for output\n",
+ max_len );
+ return -1;
+ }
+ memset ( output->buf, 0xff, sizeof ( output->buf ) );
+ return 0;
+}
+
+static int process_zinfo_copy ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ struct zinfo_copy *copy = &zinfo->copy;
+ size_t offset = copy->offset;
+ size_t len = copy->len;
+
+ if ( ( offset + len ) > input->len ) {
+ fprintf ( stderr, "Input buffer overrun on copy\n" );
+ return -1;
+ }
+
+ output->len = align ( output->len, copy->align );
+ if ( ( output->len + len ) > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on copy\n" );
+ return -1;
+ }
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
+ offset, ( offset + len ), output->len,
+ ( output->len + len ) );
+ }
+
+ memcpy ( ( output->buf + output->len ),
+ ( input->buf + offset ), len );
+ output->len += len;
+ return 0;
+}
+
+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;
+
+ if ( ( offset + len ) > input->len ) {
+ fprintf ( stderr, "Input buffer overrun on pack\n" );
+ return -1;
+ }
+
+ output->len = align ( output->len, pack->align );
+ if ( output->len > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on pack\n" );
+ return -1;
+ }
+
+ if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
+ ( output->buf + output->len ),
+ &packed_len, 0 ) != UCL_E_OK ) {
+ fprintf ( stderr, "Compression failure\n" );
+ return -1;
+ }
+
+ 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;
+ if ( output->len > output->max_len ) {
+ fprintf ( stderr, "Output buffer overrun on pack\n" );
+ return -1;
+ }
+
+ return 0;
+}
+
+static int process_zinfo_add ( struct input_file *input,
+ struct output_file *output,
+ struct zinfo_add *add,
+ size_t datasize ) {
+ size_t offset = add->offset;
+ void *target;
+ signed long addend;
+ unsigned long size;
+ signed long val;
+ unsigned long mask;
+
+ if ( ( offset + datasize ) > output->len ) {
+ fprintf ( stderr, "Add at %#zx outside output buffer\n",
+ offset );
+ return -1;
+ }
+
+ target = ( output->buf + offset );
+ size = ( align ( output->len, add->divisor ) / add->divisor );
+
+ switch ( datasize ) {
+ case 1:
+ addend = *( ( int8_t * ) target );
+ break;
+ case 2:
+ addend = *( ( int16_t * ) target );
+ break;
+ case 4:
+ addend = *( ( int32_t * ) target );
+ break;
+ default:
+ fprintf ( stderr, "Unsupported add datasize %zd\n",
+ datasize );
+ return -1;
+ }
+
+ val = size + addend;
+
+ /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
+ mask = ( ( datasize < sizeof ( mask ) ) ?
+ ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
+
+ if ( val < 0 ) {
+ fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
+ ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
+ offset, ( ( addend < 0 ) ? "under" : "over" ) );
+ return -1;
+ }
+
+ if ( val & ~mask ) {
+ fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
+ "field (%d bytes too big)\n",
+ ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
+ offset, datasize,
+ ( int )( ( val - mask - 1 ) * add->divisor ) );
+ return -1;
+ }
+
+ switch ( datasize ) {
+ case 1:
+ *( ( uint8_t * ) target ) = val;
+ break;
+ case 2:
+ *( ( uint16_t * ) target ) = val;
+ break;
+ case 4:
+ *( ( uint32_t * ) target ) = val;
+ break;
+ }
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
+ "%#lx\n", offset, ( offset + datasize ),
+ ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
+ output->len, add->divisor, val );
+ }
+
+ return 0;
+}
+
+static int process_zinfo_addb ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ return process_zinfo_add ( input, output, &zinfo->add, 1 );
+}
+
+static int process_zinfo_addw ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ return process_zinfo_add ( input, output, &zinfo->add, 2 );
+}
+
+static int process_zinfo_addl ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ return process_zinfo_add ( input, output, &zinfo->add, 4 );
+}
+
+struct zinfo_processor {
+ char *type;
+ int ( * process ) ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo );
+};
+
+static struct zinfo_processor zinfo_processors[] = {
+ { "COPY", process_zinfo_copy },
+ { "PACK", process_zinfo_pack },
+ { "ADDB", process_zinfo_addb },
+ { "ADDW", process_zinfo_addw },
+ { "ADDL", process_zinfo_addl },
+};
+
+static int process_zinfo ( struct input_file *input,
+ struct output_file *output,
+ union zinfo_record *zinfo ) {
+ struct zinfo_common *common = &zinfo->common;
+ struct zinfo_processor *processor;
+ char type[ sizeof ( common->type ) + 1 ] = "";
+ unsigned int i;
+
+ strncat ( type, common->type, sizeof ( type ) - 1 );
+ for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
+ sizeof ( zinfo_processors[0] ) ) ; i++ ) {
+ processor = &zinfo_processors[i];
+ if ( strcmp ( processor->type, type ) == 0 )
+ return processor->process ( input, output, zinfo );
+ }
+
+ fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
+ return -1;
+}
+
+static int write_output_file ( struct output_file *output ) {
+ if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
+ fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
+ output->len, strerror ( errno ) );
+ return -1;
+ }
+ return 0;
+}
+
+int main ( int argc, char **argv ) {
+ struct input_file input;
+ struct output_file output;
+ struct zinfo_file zinfo;
+ unsigned int i;
+
+ if ( argc != 3 ) {
+ fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
+ "> file.zbin\n", argv[0] );
+ exit ( 1 );
+ }
+
+ if ( read_input_file ( argv[1], &input ) < 0 )
+ exit ( 1 );
+ if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
+ exit ( 1 );
+ if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
+ exit ( 1 );
+
+ for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
+ if ( process_zinfo ( &input, &output,
+ &zinfo.zinfo[i] ) < 0 )
+ exit ( 1 );
+ }
+
+ if ( write_output_file ( &output ) < 0 )
+ exit ( 1 );
+
+ return 0;
+}