diff options
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/util')
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 ( §ion->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; +} |