diff options
author | Michael Brown <mcb30@etherboot.org> | 2005-03-08 18:53:11 +0000 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2005-03-08 18:53:11 +0000 |
commit | 3d6123e69ab879c72ff489afc5bf93ef0b7a94ce (patch) | |
tree | 9f3277569153a550fa8d81ebd61bd88f266eb8da /src/util | |
download | ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.zip ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.gz ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.bz2 |
Initial revision
Diffstat (limited to 'src/util')
-rwxr-xr-x | src/util/catrom.pl | 48 | ||||
-rwxr-xr-x | src/util/disrom.pl | 114 | ||||
-rwxr-xr-x | src/util/geniso | 56 | ||||
-rwxr-xr-x | src/util/genliso | 85 | ||||
-rwxr-xr-x | src/util/get-pci-ids | 135 | ||||
-rw-r--r-- | src/util/lzhuf.c | 764 | ||||
-rwxr-xr-x | src/util/makelilo.pl | 40 | ||||
-rwxr-xr-x | src/util/makerom.pl | 226 | ||||
-rwxr-xr-x | src/util/modrom.pl | 226 | ||||
-rw-r--r-- | src/util/nrv2b.c | 1501 | ||||
-rwxr-xr-x | src/util/swapdevids.pl | 49 | ||||
-rwxr-xr-x | src/util/zfilelen.pl | 8 |
12 files changed, 3252 insertions, 0 deletions
diff --git a/src/util/catrom.pl b/src/util/catrom.pl new file mode 100755 index 0000000..fe37e6b --- /dev/null +++ b/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/src/util/disrom.pl b/src/util/disrom.pl new file mode 100755 index 0000000..6412869 --- /dev/null +++ b/src/util/disrom.pl @@ -0,0 +1,114 @@ +#!/usr/bin/perl -w +# +# Program to display key information about a boot ROM +# including PCI and PnP structures +# +# GPL, Ken Yap 2001 +# + +use bytes; + +sub getid ($) +{ + my ($offset) = @_; + + return '' if ($offset == 0 or $offset > $len); + my ($string) = unpack('Z32', substr($data, $offset, 32)); + return ($string); +} + +sub dispci +{ + my ($pcidata) = substr($data, $pci, 0x18); + my ($dummy, $vendorid, $deviceid, $vpd, $pcilen, $pcirev, + $class1, $class2, $class3, $imglen, $coderev, $codetype, + $indicator) = unpack('a4v4C4v2C2', $pcidata); + $imglen *= 512; + my $vendorstr = sprintf('%#04x', $vendorid); + my $devicestr = sprintf('%#04x', $deviceid); + my $coderevstr = sprintf('%#04x', $coderev); + print <<EOF; +PCI structure: + +Vital product data: $vpd +Vendor ID: $vendorstr +Device ID: $devicestr +Device base type: $class1 +Device sub type: $class2 +Device interface type: $class3 +Image length: $imglen +Code revision: $coderevstr +Code type: $codetype +Indicator: $indicator + +EOF +} + +sub dispnp +{ + my ($pnpdata) = substr($data, $pnp, 0x20); + my ($dummy1, $pnprev, $pnplen, $nextpnp, $dummy2, + $pnpcsum, $deviceid, $mfrid, $productid, + $class1, $class2, $class3, $indicator, + $bcv, $dv, $bev, $dummy, $sri) = unpack('a4C2vC2a4v2C4v5', $pnpdata); + print <<EOF; +PnP structure: + +EOF + print 'Vendor: ', &getid($mfrid), "\n"; + print 'Device: ', &getid($productid), "\n"; + my $indicatorstr = sprintf('%#02x', $indicator); + my $bcvstr = sprintf('%#04x', $bcv); + my $dvstr = sprintf('%#04x', $dv); + my $bevstr = sprintf('%#04x', $bev); + my $sristr = sprintf('%#04x', $sri); + my $checksum = unpack('%8C*', $pnpdata); + print <<EOF; +Device base type: $class1 +Device sub type: $class2 +Device interface type: $class3 +Device indicator: $indicatorstr +Boot connection vector: $bcvstr +Disconnect vector: $dvstr +Bootstrap entry vector: $bevstr +Static resource information vector: $sristr +Checksum: $checksum + +EOF +} + +sub pcipnp +{ + ($pci, $pnp) = unpack('v2', substr($data, 0x18, 4)); + if ($pci >= $len or $pnp >= $len) { + print "$file: Not a PCI PnP ROM image\n"; + return; + } + if (substr($data, $pci, 4) ne 'PCIR' or substr($data, $pnp, 4) ne '$PnP') { + print "$file: No PCI and PNP structures, not a PCI PNP ROM image\n"; + return; + } + &dispci(); + &dispnp(); +} + +$file = $#ARGV >= 0 ? $ARGV[0] : '-'; +open(F, "$file") or die "$file: $!\n"; +binmode(F); +# Handle up to 64kB ROM images +$len = read(F, $data, 64*1024); +close(F); +defined($len) or die "$file: $!\n"; +substr($data, 0, 2) eq "\x55\xAA" or die "$file: Not a boot ROM image\n"; +my ($codelen) = unpack('C', substr($data, 2, 1)); +$codelen *= 512; +if ($codelen < $len) { + my $pad = $len - $codelen; + print "Image is $codelen bytes and has $pad bytes of padding following\n"; + $data = substr($data, 0, $codelen); +} elsif ($codelen > $len) { + print "Image should be $codelen bytes but is truncated to $len bytes\n";} +&pcipnp(); +($csum) = unpack('%8C*', $data); +print "ROM checksum: $csum \n"; +exit(0); diff --git a/src/util/geniso b/src/util/geniso new file mode 100755 index 0000000..5bd5c7b --- /dev/null +++ b/src/util/geniso @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Generate a isolinux ISO boot image +# +# geniso foo.iso foo.zlilo +# +# the ISO image is the first argument so that a list of .zlilo images +# to include can be specified +# +case $# in +0|1) + echo Usage: $0 foo.iso foo.zlilo ... + 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/config correctly + exit 1 +fi +out=$1 +shift +dir=bin/iso.dir +mkdir -p $dir +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%.zlilo} + g=${g//[^a-z0-9]}.zli + case "$first" in + "") + echo DEFAULT $g + ;; + esac + first=$g + echo LABEL $b + echo "" KERNEL $g + cp -p $f $dir/$g +done >> $cfg +mkisofs -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/src/util/genliso b/src/util/genliso new file mode 100755 index 0000000..b8d9a11 --- /dev/null +++ b/src/util/genliso @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Generate a legacy floppy emulation ISO boot image +# +# genliso foo.liso foo.zlilo +# +# the ISO image is the first argument so that a list of .zlilo images +# to include can be specified +# +case $0 in +*genliso) + ;; +*genfdimg) + genfdimg=1 + ;; +esac +case $# in +0|1) + echo Usage: $0 foo.liso foo.zlilo ... + exit 1 + ;; +esac +case "`mtools -V`" in +Mtools\ version\ 3.9.9*|Mtools\ version\ 4.*) + ;; +*) + echo Mtools version 3.9.9 or later is required + exit 1 + ;; +esac +out=$1 +shift +dir=bin/liso.dir +mkdir -p $dir +case "$genfdimg" in +1) + img=$out + ;; +*) + img=$dir/boot.img + ;; +esac +mformat -f 1440 -C -i $img :: +cfg=bin/syslinux.cfg +cat > $cfg <<EOF +# These default options can be changed in the genliso script +SAY Etherboot 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%.zlilo} + g=${g//[^a-z0-9]} + g=${g:0:8}.zli + 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 +case "$genfdimg" in +1) + ;; +*) + mkisofs -o $out -c boot.cat -b boot.img $dir + ;; +esac +rm -fr $dir diff --git a/src/util/get-pci-ids b/src/util/get-pci-ids new file mode 100755 index 0000000..6501a7f --- /dev/null +++ b/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/src/util/lzhuf.c b/src/util/lzhuf.c new file mode 100644 index 0000000..ea65b5e --- /dev/null +++ b/src/util/lzhuf.c @@ -0,0 +1,764 @@ +/* +---------------------------------------------------------------------------- + +M. LZHuf Compression + +This is the LZHuf compression algorithm as used in DPBOX and F6FBB. + +---------------------------------------------------------------------------- +*/ +/************************************************************** + 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 +**************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#ifndef VERBOSE +#define Fprintf(x) +#define wterr 0 +#else +#define Fprintf(x) fprintf x +#if defined(ENCODE) || defined(DECODE) +static char wterr[] = "Can't write."; +#ifdef ENCODE +static unsigned long int codesize = 0; +#endif +static unsigned long int printcount = 0; +#endif +#endif + +#ifndef MAIN +extern +#endif +FILE *infile, *outfile; + +#if defined(ENCODE) || defined(DECODE) +static unsigned long int textsize = 0; + +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 + +/********** LZSS compression **********/ + +#define N 4096 /* buffer size */ +/* Attention: When using this file for f6fbb-type compressed data exchange, + set N to 2048 ! (DL8HBS) */ +#define F 60 /* lookahead buffer size */ +#define THRESHOLD 2 +#define NIL N /* leaf of tree */ + +#if defined(ENCODE) || defined(DECODE) +static unsigned char + text_buf[N + F - 1]; +#endif + +#ifdef ENCODE +static int match_position, match_length, + lson[N + 1], rson[N + 257], dad[N + 1]; + +static void InitTree(void) /* initialize trees */ +{ + int i; + + for (i = N + 1; i <= N + 256; i++) + rson[i] = NIL; /* root */ + for (i = 0; i < N; i++) + dad[i] = NIL; /* node */ +} + +static void InsertNode(int r) /* insert to tree */ +{ + int i, p, cmp; + unsigned char *key; + unsigned c; + + cmp = 1; + key = &text_buf[r]; + p = N + 1 + key[0]; + rson[r] = lson[r] = NIL; + match_length = 0; + for ( ; ; ) { + if (cmp >= 0) { + if (rson[p] != NIL) + p = rson[p]; + else { + rson[p] = r; + dad[r] = p; + return; + } + } else { + if (lson[p] != NIL) + p = lson[p]; + else { + lson[p] = r; + dad[r] = p; + return; + } + } + for (i = 1; i < F; i++) + if ((cmp = key[i] - text_buf[p + i]) != 0) + break; + if (i > THRESHOLD) { + if (i > match_length) { + match_position = ((r - p) & (N - 1)) - 1; + if ((match_length = i) >= F) + break; + } + if (i == match_length) { + if ((c = ((r - p) & (N - 1)) - 1) < match_position) { + match_position = c; + } + } + } + } + dad[r] = dad[p]; + lson[r] = lson[p]; + rson[r] = rson[p]; + dad[lson[p]] = r; + dad[rson[p]] = r; + if (rson[dad[p]] == p) + rson[dad[p]] = r; + else + lson[dad[p]] = r; + dad[p] = NIL; /* remove p */ +} + +static void DeleteNode(int p) /* remove from tree */ +{ + int q; + + if (dad[p] == NIL) + return; /* not registered */ + if (rson[p] == NIL) + q = lson[p]; + else + if (lson[p] == NIL) + q = rson[p]; + else { + q = lson[p]; + if (rson[q] != NIL) { + do { + q = rson[q]; + } while (rson[q] != NIL); + rson[dad[q]] = lson[q]; + dad[lson[q]] = dad[q]; + lson[q] = lson[p]; + dad[lson[p]] = q; + } + rson[q] = rson[p]; + dad[rson[p]] = q; + } + dad[q] = dad[p]; + if (rson[dad[p]] == p) + rson[dad[p]] = q; + else + lson[dad[p]] = q; + dad[p] = NIL; +} +#endif + +/* Huffman coding */ + +#define N_CHAR (256 - THRESHOLD + F) + /* kinds of characters (character code = 0..N_CHAR-1) */ +#define T (N_CHAR * 2 - 1) /* size of table */ +#define R (T - 1) /* position of root */ +#define MAX_FREQ 0x8000 /* updates tree when the */ + /* root frequency comes to this value. */ +typedef unsigned char uchar; + +/* table for encoding and decoding the upper 6 bits of position */ + +/* for encoding */ + +#ifdef ENCODE +static uchar p_len[64] = { + 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static uchar p_code[64] = { + 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, + 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C, + 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, + 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, + 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; +#endif + +#ifdef DECODE +/* for decoding */ +static uchar d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + +static uchar d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; +#endif + +#if defined(ENCODE) || defined(DECODE) +static unsigned freq[T + 1]; /* frequency table */ + +static int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ + /* elements [T..T + N_CHAR - 1] which are used to get */ + /* the positions of leaves corresponding to the codes. */ + +static int son[T]; /* pointers to child nodes (son[], son[] + 1) */ +#endif + +#ifdef DECODE +static unsigned getbuf = 0; +static uchar getlen = 0; + +static int GetBit(void) /* get one bit */ +{ + int i; + + while (getlen <= 8) { + if ((i = getc(infile)) < 0) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 1; + getlen--; + return ((signed short)i < 0); +} + +static int GetByte(void) /* get one byte */ +{ + unsigned short i; + + while (getlen <= 8) { + if ((signed short)(i = getc(infile)) < 0) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 8; + getlen -= 8; + return i >> 8; +} +#endif + +#ifdef ENCODE +static unsigned putbuf = 0; +static uchar putlen = 0; + +static void Putcode(int l, unsigned c) /* output c bits of code */ +{ + putbuf |= c >> putlen; + if ((putlen += l) >= 8) { + if (putc(putbuf >> 8, outfile) == EOF) { + Error(wterr); + } + if ((putlen -= 8) >= 8) { + if (putc(putbuf, outfile) == EOF) { + Error(wterr); + } +#ifdef VERBOSE + codesize += 2; +#endif + putlen -= 8; + putbuf = c << (l - putlen); + } else { + putbuf <<= 8; +#ifdef VERBOSE + codesize++; +#endif + } + } +} +#endif + +/* initialization of tree */ + +#if defined(ENCODE) || defined(DECODE) +static void StartHuff(void) +{ + int i, j; + + for (i = 0; i < N_CHAR; i++) { + freq[i] = 1; + son[i] = i + T; + prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) { + freq[j] = freq[i] + freq[i + 1]; + son[j] = i; + prnt[i] = prnt[i + 1] = j; + i += 2; j++; + } + freq[T] = 0xffff; + prnt[R] = 0; +} + +/* reconstruction of tree */ + +static void reconst(void) +{ + int i, j, k; + unsigned f, l; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + j = 0; + for (i = 0; i < T; i++) { + if (son[i] >= T) { + freq[j] = (freq[i] + 1) / 2; + son[j] = son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) { + k = i + 1; + f = freq[j] = freq[i] + freq[k]; + for (k = j - 1; f < freq[k]; k--); + k++; + l = (j - k) * 2; + memmove(&freq[k + 1], &freq[k], l); + freq[k] = f; + memmove(&son[k + 1], &son[k], l); + son[k] = i; + } + /* connect prnt */ + for (i = 0; i < T; i++) { + if ((k = son[i]) >= T) { + prnt[k] = i; + } else { + prnt[k] = prnt[k + 1] = i; + } + } +} + +/* increment frequency of given code by one, and update tree */ + +static void update(int c) +{ + int i, j, k, l; + + if (freq[R] == MAX_FREQ) { + reconst(); + } + c = prnt[c + T]; + do { + k = ++freq[c]; + + /* if the order is disturbed, exchange nodes */ + if (k > freq[l = c + 1]) { + while (k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; + + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; + + j = son[l]; + son[l] = i; + + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; + + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ +} +#endif + +#ifdef ENCODE +#if 0 +static unsigned code, len; +#endif + +static void EncodeChar(unsigned c) +{ + unsigned i; + int j, k; + + i = 0; + j = 0; + k = prnt[c + T]; + + /* travel from leaf to root */ + do { + i >>= 1; + + /* if node's address is odd-numbered, choose bigger brother node */ + if (k & 1) i += 0x8000; + + j++; + } while ((k = prnt[k]) != R); + Putcode(j, i); +#if 0 + code = i; + len = j; +#endif + update(c); +} + +static void EncodePosition(unsigned c) +{ + unsigned i; + + /* output upper 6 bits by table lookup */ + i = c >> 6; + Putcode(p_len[i], (unsigned)p_code[i] << 8); + + /* output lower 6 bits verbatim */ + Putcode(6, (c & 0x3f) << 10); +} + +static void EncodeEnd(void) +{ + if (putlen) { + if (putc(putbuf >> 8, outfile) == EOF) { + Error(wterr); + } +#ifdef VERBOSE + codesize++; +#endif + } +} +#endif + +#ifdef DECODE +static int DecodeChar(void) +{ + unsigned c; + + c = son[R]; + + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) { + c += GetBit(); + c = son[c]; + } + c -= T; + update(c); + return c; +} + +static int DecodePosition(void) +{ + unsigned i, j, c; + + /* recover upper 6 bits from table */ + i = GetByte(); + c = (unsigned)d_code[i] << 6; + j = d_len[i]; + + /* read lower 6 bits verbatim */ + j -= 2; + while (j--) { + i = (i << 1) + GetBit(); + } + return c | (i & 0x3f); +} +#endif + +#ifdef ENCODE +/* compression */ + +void Encode(void) /* compression */ +{ + int i, c, len, r, s, last_match_length; + unsigned long tw; + + fseek(infile, 0L, 2); + textsize = ftell(infile); +#ifdef VERBOSE + if ((signed long)textsize < 0) + Fprintf((stderr, "Errno: %d", errno)); +#endif + tw = host_to_i86ul(textsize); + if (fwrite(&tw, sizeof tw, 1, outfile) < 1) + Error(wterr); /* output size of text */ + if (textsize == 0) + return; + rewind(infile); + textsize = 0; /* rewind and re-read */ + StartHuff(); + InitTree(); + s = 0; + r = N - F; + for (i = s; i < r; i++) + text_buf[i] = ' '; + for (len = 0; len < F && (c = getc(infile)) != EOF; len++) + text_buf[r + len] = c; + textsize = len; + for (i = 1; i <= F; i++) + InsertNode(r - i); + InsertNode(r); + do { + if (match_length > len) + match_length = len; + if (match_length <= THRESHOLD) { + match_length = 1; + EncodeChar(text_buf[r]); + } else { + EncodeChar(255 - THRESHOLD + match_length); + EncodePosition(match_position); + } + last_match_length = match_length; + for (i = 0; i < last_match_length && + (c = getc(infile)) != EOF; i++) { + DeleteNode(s); + text_buf[s] = c; + if (s < F - 1) + text_buf[s + N] = c; + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + InsertNode(r); + } + if ((textsize += i) > printcount) { +#if defined(VERBOSE) && defined(EXTRAVERBOSE) + Fprintf((stderr, "%12ld\r", textsize)); +#endif + printcount += 1024; + } + while (i++ < last_match_length) { + DeleteNode(s); + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + if (--len) InsertNode(r); + } + } while (len > 0); + EncodeEnd(); +#ifdef LONG_REPORT + Fprintf((stderr, "input size %ld bytes\n", codesize)); + Fprintf((stderr, "output size %ld bytes\n", textsize)); + Fprintf((stderr, "input/output %.3f\n", (double)codesize / textsize)); +#else + Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", codesize, textsize, + (double)codesize / textsize)); +#endif +} +#endif + +#ifdef DECODE +void Decode(void) /* recover */ +{ + int i, j, k, r, c; + unsigned long int count; + unsigned long tw; + + if (fread(&tw, sizeof tw, 1, infile) < 1) + Error("Can't read"); /* read size of text */ + textsize = i86ul_to_host(tw); + if (textsize == 0) + return; + StartHuff(); + for (i = 0; i < N - F; i++) + text_buf[i] = ' '; + r = N - F; + for (count = 0; count < textsize; ) { + c = DecodeChar(); + if (c < 256) { + if (putc(c, outfile) == EOF) { + Error(wterr); + } + text_buf[r++] = c; + r &= (N - 1); + count++; + } else { + i = (r - DecodePosition() - 1) & (N - 1); + j = c - 255 + THRESHOLD; + for (k = 0; k < j; k++) { + c = text_buf[(i + k) & (N - 1)]; + if (putc(c, outfile) == EOF) { + Error(wterr); + } + text_buf[r++] = c; + r &= (N - 1); + count++; + } + } + if (count > printcount) { +#if defined(VERBOSE) && defined(EXTRAVERBOSE) + Fprintf((stderr, "%12ld\r", count)); +#endif + printcount += 1024; + } + } + Fprintf((stderr, "%12ld\n", count)); +} +#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, "'lzhuf e file1 file2' encodes file1 into file2.\n" + "'lzhuf 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/src/util/makelilo.pl b/src/util/makelilo.pl new file mode 100755 index 0000000..8f995bc --- /dev/null +++ b/src/util/makelilo.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +use constant SYSSIZE_LOC => 500; # bytes from beginning of boot block +use constant MINSIZE => 32768; + +use strict; + +use bytes; + +$#ARGV >= 1 or die "Usage: $0 liloprefix file ...\n"; +open(L, "$ARGV[0]") or die "$ARGV[0]: $!\n"; +undef($/); +my $liloprefix = <L>; +close(L); +length($liloprefix) >= 512 or die "LILO prefix too short\n"; +shift(@ARGV); +my $totalsize = 0; +for my $file (@ARGV) { + next if (! -f $file or ! -r $file); + $totalsize += -s $file; +} +my $pad = 0; +if ($totalsize < MINSIZE) { + $pad = MINSIZE - $totalsize; + $totalsize = MINSIZE; +} +print STDERR "LILO payload is $totalsize bytes\n"; +$totalsize += 16; +$totalsize >>= 4; +substr($liloprefix, SYSSIZE_LOC, 2) = pack('v', $totalsize); +print $liloprefix; +for my $file (@ARGV) { + next unless open(I, "$file"); + undef($/); + my $data = <I>; + print $data; + close(I); +} +print "\x0" x $pad; +exit(0); diff --git a/src/util/makerom.pl b/src/util/makerom.pl new file mode 100755 index 0000000..695468c --- /dev/null +++ b/src/util/makerom.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, 5, 1) = "\x00"; + my $sum = unpack('%8C*', $$romref); + substr($$romref, 5, 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/src/util/modrom.pl b/src/util/modrom.pl new file mode 100755 index 0000000..695468c --- /dev/null +++ b/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, 5, 1) = "\x00"; + my $sum = unpack('%8C*', $$romref); + substr($$romref, 5, 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/src/util/nrv2b.c b/src/util/nrv2b.c new file mode 100644 index 0000000..6bac4cd --- /dev/null +++ b/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/src/util/swapdevids.pl b/src/util/swapdevids.pl new file mode 100755 index 0000000..c6255ae --- /dev/null +++ b/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/src/util/zfilelen.pl b/src/util/zfilelen.pl new file mode 100755 index 0000000..1f58ff9 --- /dev/null +++ b/src/util/zfilelen.pl @@ -0,0 +1,8 @@ +#!/usr/bin/perl -w + +use bytes; + +local $/; +$_ = <>; +print length($_); +exit; |