Import gPXE contrib directory to create separate directory master
authorMarty Connor <mdc@etherboot.org>
Sun, 17 Jan 2010 02:16:53 +0000 (21:16 -0500)
committerMarty Connor <mdc@etherboot.org>
Sun, 17 Jan 2010 02:16:53 +0000 (21:16 -0500)
156 files changed:
3c90xutil/Makefile [new file with mode: 0644]
3c90xutil/README [new file with mode: 0644]
3c90xutil/bromutil.c [new file with mode: 0644]
3c90xutil/cromutil.c [new file with mode: 0644]
3c90xutil/ocromutil.c [new file with mode: 0644]
3c90xutil/romutil.txt [new file with mode: 0644]
Diskless-From-NT/Config.txt [new file with mode: 0644]
Diskless-From-NT/Diskless-From-NT.txt [new file with mode: 0644]
Diskless-From-NT/furtmayr.html [new file with mode: 0644]
auto-default/mail [new file with mode: 0644]
auto-default/main.c.patch [new file with mode: 0644]
award_plugin_roms/README [new file with mode: 0644]
award_plugin_roms/award_plugin_roms.pl [new file with mode: 0755]
baremetal/Makefile [new file with mode: 0644]
baremetal/main.c [new file with mode: 0644]
baremetal/marini.txt [new file with mode: 0644]
baremetal/misc.c [new file with mode: 0644]
baremetal/startmpcc.S [new file with mode: 0644]
bin2intelhex/Makefile [new file with mode: 0644]
bin2intelhex/bin2intelhex.c [new file with mode: 0644]
bin2intelhex/bin2intelhex.c.simple [new file with mode: 0644]
bochs/.gitignore [new file with mode: 0644]
bochs/Makefile [new file with mode: 0644]
bochs/README [new file with mode: 0644]
bochs/README.qemu [new file with mode: 0644]
bochs/README.windows-ris [new file with mode: 0644]
bochs/bochs-writable-ROM-patch [new file with mode: 0644]
bochs/bochsrc.txt [new file with mode: 0644]
bochs/qemu-patch [new file with mode: 0644]
bochs/serial-console [new file with mode: 0755]
bochs/serial-console.1 [new file with mode: 0644]
bochs/tunctl.c [new file with mode: 0644]
bootptodhcp/bootptodhcp.pl [new file with mode: 0755]
compressor/COPYING [new file with mode: 0644]
compressor/algorithm.doc [new file with mode: 0644]
compressor/loader.h [new file with mode: 0644]
compressor/lzhuf.c [new file with mode: 0644]
dhcpdconfeg/dhcpd.conf [new file with mode: 0644]
dhcpdconfeg/vendorclassid.txt [new file with mode: 0644]
dhcpid/dhcpid.txt [new file with mode: 0644]
eepro100notes/flash-1.txt [new file with mode: 0644]
eepro100notes/flash-2.txt [new file with mode: 0644]
eepro100notes/flash-3.txt [new file with mode: 0644]
errcode/README [new file with mode: 0644]
errcode/build_errcodedb.py [new file with mode: 0755]
errcode/errcode.php [new file with mode: 0644]
errcode/errcode.py [new file with mode: 0755]
errcode/gpxebot.py [new file with mode: 0755]
flashimg/Makefile [new file with mode: 0644]
flashimg/flashimg.asm [new file with mode: 0644]
flashimg/flashimg.img [new file with mode: 0644]
hdload/Makefile [new file with mode: 0644]
hdload/hdload.S [new file with mode: 0644]
hdload/petr.msg [new file with mode: 0644]
initrd/ChangeLog [new file with mode: 0644]
initrd/Makefile [new file with mode: 0644]
initrd/Manifest [new file with mode: 0644]
initrd/README [new file with mode: 0644]
initrd/dhcpd.conf.etherboot.include [new file with mode: 0644]
initrd/include-modules [new file with mode: 0755]
initrd/linux-wlan.cfg [new file with mode: 0644]
initrd/linuxrc [new file with mode: 0644]
initrd/mkinitrd-net [new file with mode: 0755]
initrd/mkinitrd-net.spec [new file with mode: 0644]
initrd/mknbi-set [new file with mode: 0755]
initrd/mknbi-set.conf [new file with mode: 0644]
initrd/script.c.patch [new file with mode: 0644]
initrd/udhcpc-post [new file with mode: 0644]
linux-2.0-transname.lsm [new file with mode: 0644]
linux-3c503-patch/3c503.patch [new file with mode: 0644]
linux-3c503-patch/README [new file with mode: 0644]
mini-slamd/COPYING [new file with mode: 0644]
mini-slamd/Makefile [new file with mode: 0644]
mini-slamd/mini-slamd.c [new file with mode: 0644]
mkQNXnbi/Makefile [new file with mode: 0644]
mkQNXnbi/README [new file with mode: 0644]
mkQNXnbi/examples/bootptab [new file with mode: 0644]
mkQNXnbi/examples/ws.etherboot [new file with mode: 0644]
mkQNXnbi/examples/ws.etherboot.on-the-fly [new file with mode: 0644]
mkQNXnbi/mkQNXnbi.c [new file with mode: 0644]
mkffwnb/2.0.10/linuxrc [new file with mode: 0755]
mkffwnb/Extendinitrd.pm [new file with mode: 0644]
mkffwnb/README [new file with mode: 0644]
mkffwnb/mkffwnb.pl [new file with mode: 0755]
mklrpnb/README.txt [new file with mode: 0644]
mklrpnb/extractdach.pl [new file with mode: 0644]
mklrpnb/mklrpnb [new file with mode: 0755]
mntnbi/mntnbi.pl [new file with mode: 0755]
nfs-swap/README [new file with mode: 0644]
p910nd-0.8/Makefile [new file with mode: 0644]
p910nd-0.8/banner.pl [new file with mode: 0755]
p910nd-0.8/client.pl [new file with mode: 0755]
p910nd-0.8/p910nd.8 [new file with mode: 0644]
p910nd-0.8/p910nd.c [new file with mode: 0644]
p910nd-0.8/p910nd.sh [new file with mode: 0755]
ppmtoansi/Makefile [new file with mode: 0644]
ppmtoansi/demo/dos.ansi [new file with mode: 0644]
ppmtoansi/demo/dos.ppm [new file with mode: 0644]
ppmtoansi/demo/dos.xpm [new file with mode: 0644]
ppmtoansi/demo/etherboot.ansi [new file with mode: 0644]
ppmtoansi/demo/etherboot.ppm [new file with mode: 0644]
ppmtoansi/demo/etherboot.xpm [new file with mode: 0644]
ppmtoansi/demo/flash.ansi [new file with mode: 0644]
ppmtoansi/demo/flash.ppm [new file with mode: 0644]
ppmtoansi/demo/flash.xpm [new file with mode: 0644]
ppmtoansi/demo/floppy.ansi [new file with mode: 0644]
ppmtoansi/demo/floppy.ppm [new file with mode: 0644]
ppmtoansi/demo/floppy.xpm [new file with mode: 0644]
ppmtoansi/demo/hd.ansi [new file with mode: 0644]
ppmtoansi/demo/hd.ppm [new file with mode: 0644]
ppmtoansi/demo/hd.xpm [new file with mode: 0644]
ppmtoansi/demo/ibmmap.ppm [new file with mode: 0644]
ppmtoansi/demo/ibmmap.xpm [new file with mode: 0644]
ppmtoansi/demo/linux-logo.ansi [new file with mode: 0644]
ppmtoansi/demo/linux-logo.ppm [new file with mode: 0644]
ppmtoansi/demo/linux-logo.xpm [new file with mode: 0644]
ppmtoansi/demo/make-ansi.sh [new file with mode: 0755]
ppmtoansi/demo/text.ansi [new file with mode: 0644]
ppmtoansi/demo/text.ppm [new file with mode: 0644]
ppmtoansi/demo/text.xpm [new file with mode: 0644]
ppmtoansi/demo/x.ansi [new file with mode: 0644]
ppmtoansi/demo/x.ppm [new file with mode: 0644]
ppmtoansi/demo/x.xpm [new file with mode: 0644]
ppmtoansi/ppmtoansi.c [new file with mode: 0644]
ppmtoansi/ppmtoansi.man [new file with mode: 0644]
rom-scan/Makefile [new file with mode: 0644]
rom-scan/rom-scan.c [new file with mode: 0644]
romid/pktdrv.bat [new file with mode: 0644]
romid/readme [new file with mode: 0644]
romid/romid.c [new file with mode: 0644]
romid/setenvs.c [new file with mode: 0644]
scripts/gpxelinux.gpxe [new file with mode: 0644]
scripts/static.gpxe [new file with mode: 0644]
smc9462tx-flash/Makefile [new file with mode: 0644]
smc9462tx-flash/README [new file with mode: 0644]
smc9462tx-flash/dp83820_write.c [new file with mode: 0644]
smc9462tx-flash/dp83820flash.c [new file with mode: 0644]
t2hproxy/README [new file with mode: 0644]
t2hproxy/T2hproxy.java [new file with mode: 0644]
t2hproxy/build.xml [new file with mode: 0644]
t2hproxy/runT2proxy.sh [new file with mode: 0755]
t2hproxy/t2hproxy.pl [new file with mode: 0755]
t2hproxy/t2hproxy.xinetd [new file with mode: 0644]
tftp/Makefile [new file with mode: 0644]
tftp/README [new file with mode: 0644]
tftp/arpa/tftp.h [new file with mode: 0644]
tftp/main.c [new file with mode: 0644]
tftp/tftp.1 [new file with mode: 0644]
tftp/tftp.c [new file with mode: 0644]
tftp/tftpd.8 [new file with mode: 0644]
tftp/tftpd.c [new file with mode: 0644]
tftp/tftpsubs.c [new file with mode: 0644]
tomsrtbt/tomsrtbt-net.txt [new file with mode: 0644]
wakeonlan/README [new file with mode: 0644]
wakeonlan/wol.c [new file with mode: 0644]
wakeonlan/wol.h [new file with mode: 0644]

diff --git a/3c90xutil/Makefile b/3c90xutil/Makefile
new file mode 100644 (file)
index 0000000..3d73971
--- /dev/null
@@ -0,0 +1,9 @@
+FILES = cromutil ocromutil bromutil
+
+INCLUDEDIR = /usr/include
+CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR)
+
+all: $(FILES)
+
+clean:
+       rm -f $(FILES) *~ core
diff --git a/3c90xutil/README b/3c90xutil/README
new file mode 100644 (file)
index 0000000..109f988
--- /dev/null
@@ -0,0 +1,80 @@
+This utility was apparently writen by John Finlay and came to me
+via Richard Schroeder who got it from Greg Beeley. John, if you want
+to be credited with your full address or whatever in the Etherboot
+documentation, please contact me (Etherboot maintainer).
+
+1/18/2000 Marty Connor (mdc@thinguin.org) added code for the 3C905C
+with AT49BV512 Flash memory, and created cromutil and bromutil to
+differentiate the versions.  cromutil is for 3C905C and bromutil is
+for 3C905B.
+
+8.28.2005 I am adding a new version from Jorge L. deLyra that will
+replace cromutil.c.  I will rename cromutil.c to ocromutil.c
+
+  From:                delyra@fma.if.usp.br
+  Subject:     Improved version of cromutil.c.
+  Date:                June 22, 2004 12:19:00 AM EDT
+  To:          mdc@thinguin.org
+
+  Dear Marty,
+
+       Below you will find a new version of the cronutil.c program. Since
+  the changes were quite large I am sending the program rather than a patch.
+  I added support for 3C905CX cards with a page-mode super-flash EEPROM, and
+  included several informative messages, a programming progress report and a
+  detailed help message. I did all the tests I could with it and it seems to
+  work correctly for the 3C905CX with either type of EEPROM chip.
+
+  A question: is there a similar program for Intel eepro100 cards or for the
+  Intel or 3COM Gbit cards?
+                                         Cheers,
+
+  ----------------------------------------------------------------
+         Jorge L. deLyra,  Associate Professor of Physics
+             The University of Sao Paulo,  IFUSP-DFMA
+        For more information: finger delyra@latt.if.usp.br
+  ----------------------------------------------------------------
+
+12/4/2009 The new cromutil version from Jorge L. deLyra can be found in
+cromutil.c, whereas the old version can be found in ocromutil.c.
+
+bromutil.c now supports enabling a bootrom workaround that was previously
+implemented in the old 3c90x driver. Some 3c90xB cards refuse to load gPXE
+after the ROM is burned. The gPXE banner is likely to appear, but gPXE will
+crash soon after.
+If this is the case try the following commands. It is assumed that you replace
+0x6600 with the I/O address of your card which can be acquired with:
+(look for a line like 'I/O ports at e400')
+ $ lspci -v
+
+    $ make
+    $ ./bromutil 0x6600 bootrom
+
+This command will write into the settings EEPROM of the network card. In case
+the network card shows any unexpected behavior it is possible to restore the
+EEPROM settings with a 3COm provided tool called '3c90xcfg.exe'(google it for
+mirrors).
+
+  -- Thomas Miletich
+
+Be careful. You can easily erase your Flash memory using these
+utilities.  Make *sure* to back them up first using the "read"
+command. You must "erase" before using "prog" to program the chip with
+Etherboot code.  This code comes with NO WARRANTY, and you take sole
+responsibility and liability for whatever it does.  Read the
+"romutil.txt" file for more information on commands.
+
+That being said, if you are programming a 3C905C-TXM (for example)
+you would do something like this:
+
+    $ cd etherboot-x.x.x/contrib
+    $ tar -zxvf n3c905xutil.tar.gz
+    $ cd n3c905xutil
+    $ make
+    # replace 0x6600 with whatever the IO Addr for your card is!!!!
+    $ ./cromutil 0x6600 read > 905cbackup.bin
+    $ ./cromutil 0x6600 erase
+    $ ./cromutil 0x6600 prog < 3c90x.lzrom
+
+You should now have an Etherboot-enabled 3c905C-TXM.
+
diff --git a/3c90xutil/bromutil.c b/3c90xutil/bromutil.c
new file mode 100644 (file)
index 0000000..f71ee5b
--- /dev/null
@@ -0,0 +1,254 @@
+/* 
+ * readutil.c - perform various control ops on the 3c509b bios rom
+ *
+ */
+
+#ifndef __i386__
+#  error "This program can't compile or run on non-intel computers"
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifdef __FreeBSD__
+
+#include <fcntl.h>
+#include <machine/cpufunc.h>
+
+#define OUTB(data, port)       outb(port, data)
+#define OUTW(data, port)       outw(port, data)
+#define OUTL(data, port)       outl(port, data)
+
+#else
+
+#include <sys/io.h>
+
+#define OUTB(data, port)       outb(data, port)
+#define OUTW(data, port)       outw(data, port)
+#define OUTL(data, port)       outl(data, port)
+
+#endif
+
+/*
+ * write_eeprom() and enum definitions are copied from vortex-diag.c,
+ * Copyright 1997-2004 by Donald Becker.
+ *     This software may be used and distributed according to the terms of
+ *     the GNU General Public License (GPL), incorporated herein by reference.
+ *     Contact the author for use under other terms.
+ */
+
+enum vortex_cmd {
+       TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+       RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
+       UpStall = 6<<11, UpUnstall = (6<<11)+1,
+       DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
+       RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+       FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+       SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+       SetTxThreshold = 18<<11, SetTxStart = 19<<11,
+       StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
+       StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,
+};
+
+enum Window0 {
+       Wn0EepromCmd = 10,              /* Window 0: EEPROM command register. */
+       Wn0EepromData = 12,             /* Window 0: EEPROM results register. */
+       IntrStatus=0x0E,                /* Valid in all windows. */
+};
+
+enum Win0_EEPROM_cmds {
+       EEPROM_Read = 2, EEPROM_WRITE = 1, EEPROM_ERASE = 3,
+       EEPROM_EWENB = 0xC,             /* Enable erasing/writing for 10 msec. */
+       EEPROM_EWDIS = 0x0,             /* Disable EWENB before 10 msec timeout. */
+};
+
+#define debug 1
+static void write_eeprom(long ioaddr, int addrlen, int index, int value)
+{
+       int timer;
+
+       /* Verify that the EEPROM is idle. */
+       for (timer = 1620; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
+               if (--timer < 0)
+                       goto error_return;
+       /* Enable writing: EEPROM_EWENB | 110000.... */
+       OUTW(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
+       for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
+               if (--timer < 0)
+                       goto error_return;
+       }
+       if (debug)
+               fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400 - timer);
+       OUTW((EEPROM_ERASE << addrlen) + index, ioaddr + Wn0EepromCmd);
+       for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
+               if (--timer < 0) {
+                       fprintf(stderr, "EEPROM failed to erase index %d!\n", index);
+                       return;
+               }
+       if (debug)
+               fprintf(stderr, "EEPROM erased index %d after %d ticks!\n",
+                               index, 16000-timer);
+       OUTW(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
+       for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
+               if (--timer < 0)
+                       goto error_return;
+       }
+       if (debug)
+               fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400-timer);
+       OUTW(value, ioaddr + Wn0EepromData);
+       OUTW((EEPROM_WRITE << addrlen) + index, ioaddr + Wn0EepromCmd);
+       for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
+               if (--timer < 0)
+                       goto error_return;
+       if (debug)
+               fprintf(stderr, "EEPROM wrote index %d with 0x%4.4x after %d ticks!\n",
+                               index, value, 16000-timer);
+       return;
+error_return:
+       fprintf(stderr, "Failed to write EEPROM location %d with 0x%4.4x!\n",
+                       index, value);
+}
+
+int main(int argc, char **argv)
+{
+       unsigned int i, j, n;
+       unsigned int ioaddr;
+       unsigned long recvrstat;
+       unsigned char buf[128];
+       unsigned char b;
+
+       if (argc != 3) {
+               printf
+                   ("Usage: romid ioaddr [erase|protect|unprotect|id|bootrom|read >file|prog <file]\n");
+               exit(-1);
+       }
+#ifdef __FreeBSD__
+       /* get permissions for in/out{blw} */
+       open("/dev/io", O_RDONLY, 0);
+#else
+       setuid(0);              /* if we're setuid, do it really */
+       if (iopl(3)) {
+               perror("iopl()");
+               exit(1);
+       }
+#endif
+
+       sscanf(argv[1], "%x", &ioaddr);
+       /* Set the register window to 3 for the 3c905b */
+       OUTW(0x803, ioaddr + 0xe);
+       recvrstat = inl(ioaddr);        /* save the receiver status */
+       /* set the receiver type to MII so the full bios rom address space
+          can be accessed */
+       OUTL((recvrstat & 0xf00fffff) | 0x00600000, ioaddr);
+
+       /* Set the register window to 0 for the 3c905b */
+       OUTW(0x800, ioaddr + 0xe);
+
+       if (strcmp(argv[2], "erase") == 0) {
+               /* do the funky chicken to erase the rom contents */
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0x80, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0x10, ioaddr + 0x8);
+               printf("Bios ROM at %04x has been erased\n", ioaddr);
+       } else if (strcmp(argv[2], "protect") == 0) {
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xa0, ioaddr + 0x8);
+               printf
+                   ("Software Data Protection for Bios ROM at %04x has been enabled\n",
+                    ioaddr);
+       } else if (strcmp(argv[2], "unprotect") == 0) {
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0x80, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0x20, ioaddr + 0x8);
+               printf
+                   ("Software Data Protection for Bios ROM at %04x has been disabled\n",
+                    ioaddr);
+       } else if (strcmp(argv[2], "id") == 0) {
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0x90, ioaddr + 0x8);
+               /* 10ms delay needed */
+               printf("Manufacturer ID - ");
+               /* manuf. id */
+               OUTL(0x0000, ioaddr + 0x4);
+               printf("%02x\n", inb(ioaddr + 0x8));
+               /* device id */
+               OUTL(0x0001, ioaddr + 0x4);
+               printf("Device ID - %02x\n", inb(ioaddr + 0x8));
+               /* undo the funky chicken */
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xaa, ioaddr + 0x8);
+               OUTL(0x2aaa, ioaddr + 0x4);
+               OUTB(0x55, ioaddr + 0x8);
+               OUTL(0x5555, ioaddr + 0x4);
+               OUTB(0xf0, ioaddr + 0x8);
+       } else if(strcmp(argv[2], "bootrom") == 0) {
+               printf("bootrom fix\n");
+               write_eeprom(ioaddr, 6, 19, 0x160);
+       } else if (strcmp(argv[2], "read") == 0) {
+               for (i = 0; i < 65536; i++) {
+                       OUTL(i, ioaddr + 0x4);
+                       b = inb(ioaddr + 0x8);
+                       write(1, &b, 1);
+               }
+       } else if (strcmp(argv[2], "prog") == 0) {
+               /* program the rom in 128 bute chunks */
+               for (i = 0, n = 0; i < 65536; i += n) {
+                       n = read(0, buf, 128);
+                       if (n == 0)
+                               break;
+                       if (n < 0) {
+                               perror("File Error");
+                               exit(-3);
+                       }
+                       /* disable SDP temporarily for programming a sector */
+                       OUTL(0x5555, ioaddr + 0x4);
+                       OUTB(0xaa, ioaddr + 0x8);
+                       OUTL(0x2aaa, ioaddr + 0x4);
+                       OUTB(0x55, ioaddr + 0x8);
+                       OUTL(0x5555, ioaddr + 0x4);
+                       OUTB(0xa0, ioaddr + 0x8);
+                       for (j = 0; j < n; j++) {
+                               OUTL(i + j, ioaddr + 0x4);
+                               OUTB(buf[j], ioaddr + 0x8);
+                       }
+                       /* wait for the programming of this sector to coomplete */
+                       while (inb(ioaddr + 0x8) != buf[j - 1]);
+               }
+       }
+
+       /* Set the register window to 3 for the 3c905b */
+       OUTW(0x803, ioaddr + 0xe);
+       /* restore the receiver status */
+       OUTL(recvrstat, ioaddr);
+       return 0;
+}
+
+#endif                         /* __i386__ */
diff --git a/3c90xutil/cromutil.c b/3c90xutil/cromutil.c
new file mode 100644 (file)
index 0000000..b868078
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * JLdL 21Jun04.
+ *
+ * cromutil.c
+ *
+ * Perform various control operations on the flash EEPROM of
+ * _ the 3COM models 3C905C or 3C905CX network cards, in order
+ * _ to write a boot program such as Etherboot into it.
+ *
+ * This program is meant for the Linux operating system only,
+ * _ and only for the i386 architecture.
+ *
+ * The flash EEPROM usually used in these cards is the AT49BV512
+ * _ chip, which has 512 Kbit (64 KByte). Another possible chip,
+ * _ which is equivalent to this one, is the SST39VF512.
+ *
+ * Added alternative read128 and prog128 commands for cards with
+ * _ the SST29EE020 fast page-write (super-)flash EEPROM, which
+ * _ has 2 Mbit (256 KByte), and which has to be programmed in
+ * _ a 128-byte page mode. NOTE: it seems that the card can
+ * _ address only the first half of the memory in this chip,
+ * _ so only 128 Kbytes are actually available for use.
+ *
+ * Added a few informative messages and a detailed help message.
+ *
+ */
+
+#ifndef __i386__
+#  error "This program can't compile or run on non-Intel computers"
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+  /* Counters. */
+  unsigned int i, j, n;
+  /* For ROM chips larger than 64 KB, a long integer
+     _ is needed for the global byte counter. */
+  unsigned long k;
+  /* The I/O address of the card. */
+  unsigned int ioaddr;
+  /* Storage for a byte. */
+  unsigned char b;
+  /* Storage for a page. */
+  unsigned char buf[128];
+
+  /* Initialize a few things to avoid compiler warnings. */
+  i=0; j=0; n=0; k=0;
+
+  /* Verify the command-line parameters; write
+     _ out an usage message if needed. */
+  if (argc != 3) {
+    /* Exactly 2 command line parameters are needed. */
+    printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
+    printf(" (try './cromutil 0x0000 help' for details)\n");
+    exit(-1);
+  }
+
+  /* Set the UID to root if possible. */
+  setuid(0);
+
+  /* Get port-access permissions for in{blw}/out{blw}. */
+  if (iopl(3)) {
+    perror("iopl()");
+    exit(1);
+  }
+
+  /* Pass the I/O address of the card to a variable. */
+  sscanf(argv[1],"%x",&ioaddr);
+
+  /* Set the register window to 0. */
+  outw(0x800, ioaddr+0xe);
+
+  /*
+   * Execute the requested command.
+   *
+   * "id": get and write out the ID numbers.
+   */
+  if (strcmp(argv[2], "id") == 0) {
+    /* Software ID entry command sequence. */
+    outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4); outb(0x90, ioaddr+0x8);
+    /* A 10 ms delay is needed. */
+    usleep(10000);
+    /* Get the manufacturer id. */
+    outl(0x0000, ioaddr+0x4);
+    printf("Manufacturer ID - %02x\n", inb(ioaddr+0x8));
+    /* Get the device id. */
+    outl(0x0001, ioaddr+0x4);
+    printf("Device ID - %02x\n", inb(ioaddr+0x8));
+    /* Software ID exit command sequence. */
+    outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4); outb(0xf0, ioaddr+0x8);
+  }
+  /*
+   * "read": read data from the 512 Kbit ROM.
+   */
+  else if (strcmp(argv[2], "read") == 0) {
+    /* Loop over the whole ROM. */
+    for (k = 0; k < 65536; k++) {
+      outl(k, ioaddr+0x4);
+      b = inb(ioaddr+0x8);
+      write(1, &b, 1);
+    }
+    /* Write out an informative message. */
+    perror("Read 65536 bytes from ROM");
+  }
+  /*
+   * "read128": this alternative is for the 2 Mbit ROM.
+   */
+  else if (strcmp(argv[2], "read128") == 0) {
+    /* Loop over the accessible part of the ROM. */
+    for (k = 0; k < 131072; k++) {
+      outl(k, ioaddr+0x4);
+      b = inb(ioaddr+0x8);
+      write(1, &b, 1);
+    }
+    /* Write out an informative message. */
+    perror("Read 131072 bytes from ROM");
+  }
+  /*
+   * "erase": erase the ROM contents.
+   */
+  else if (strcmp(argv[2], "erase") == 0) {
+    /* Software chip-erase command sequence. */
+    outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4); outb(0x80, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4); outb(0x10, ioaddr+0x8);
+    /* Wait a bit. */
+    sleep(1);
+    /* Write out an informative message. */
+    printf("Bios ROM at %04x has been erased: Success\n", ioaddr);
+  }
+  /*
+   * "prog": program the 512 Kbit ROM.
+   */
+  else if (strcmp(argv[2], "prog") == 0) {
+    /* Loop over the bytes in pages, to
+       _ allow for a progress report. */
+    for (j = 0; j < 512; j++) {
+      for (i = 0; i < 128; i++) {
+       /* If this program is to run on a diskless node,
+          _ must read in the byte _before_ changing the
+          _ mode of the chip, or NFS may block. */
+       n = read(0, &b, 1);
+       /* At EOF exit the inner loop. */
+       if (n == 0)
+         break;
+       if (n < 0) {
+         perror("Input File Error");
+         exit(-3);
+       }
+       /* Disable SDP temporarily for programming a byte. */
+       outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+       outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+       outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
+       /* Calculate the address of the byte. */
+       k=i+128*j;
+       /* Program this byte. */
+       outl(k, ioaddr+0x4); outb(b, ioaddr+0x8);
+       /* Wait for the programming of this byte to complete. */
+       while (inb(ioaddr+0x8) != b)
+         ;
+      }
+      /* At EOF exit the outer loop. */
+      if (n == 0)
+       break;
+      /* Write out a progress report. */
+      printf("."); fflush(NULL);
+    }
+    /* Write out an informative message. */
+    printf("\nWrote %ld bytes to ROM: Success\n", k);
+  }
+  /*
+   * "prog128": this alternative is for the 2 Mbit ROM.
+   */
+  else if (strcmp(argv[2], "prog128") == 0) {
+    /* Loop over the accessible pages; the card can
+       _ access only the first half of the chip. */
+    for (j = 0; j < 1024; j++) {
+      /* If this program is to run on a diskless node,
+        _ must read in the page _before_ changing the
+        _ mode of the chip, or NFS may block. */
+      n = read(0, buf, 128);
+      /* At EOF exit the loop. */
+      if (n == 0)
+       break;
+      if (n < 0) {
+       perror("Input File Error");
+       exit(-3);
+      }
+      /* Disable SDP temporarily for programming a page. */
+      outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
+      outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
+      outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
+      /* Loop over the bytes in a page. */
+      for (i = 0; i < n; i++) {
+       /* Calculate the address of the byte. */
+       k=i+128*j;
+       /* Program this byte. */
+       outl(k, ioaddr+0x4); outb(buf[i], ioaddr+0x8);
+      }
+      /* Wait for the programming of this page to complete. */
+      while (inb(ioaddr+0x8) != buf[i-1])
+       ;
+      /* Write out a progress report. */
+      printf("."); fflush(NULL);
+    }
+    /* Write out an informative message. */
+    printf("\nWrote %d pages to ROM: Success\n", j);
+  }
+  /*
+   * "help": write out a detailed help message.
+   */
+  else if (strcmp(argv[2], "help") == 0) {
+    printf("This utility can be used to write data, usually boot loaders\n");
+    printf("  such as Etherboot, to the flash EEPROM of the 3COM models\n");
+    printf("  3C905C and 3C905CX network cards. You use it like this:\n");
+    printf("        ./cromutil ioaddr command [(>|<) file]\n");
+    printf("Here ioaddr is the hexadecimal I/O address of the card, such\n");
+    printf("  as 0xA123, in some cases you need input/output redirection\n");
+    printf("  from/to a file, and the command can be one of these:\n");
+    printf("  id               get the ID numbers of the card;\n");
+    printf("  read > file      read the contents of the ROM into a file;\n");
+    printf("  read128 > file   read the contents of the ROM into a file;\n");
+    printf("  erase            erase the whole ROM to the 1 state;\n");
+    printf("  prog < file      write the contents of a file into the ROM;\n");
+    printf("  prog128 < file   write the contents of a file into the ROM.\n");
+    printf("You can get the I/O address of the card using the commands\n");
+    printf("  'lspci -v', 'cat /proc/pci', or 'dmesg | grep -i 3C905C'.\n");
+    printf("The read and prog commands are to be used if the card has a\n");
+    printf("  traditional 512 Kb (64 KB) flash EEPROM chip, such as:\n");
+    printf("  | AT49BV512 | SST39VF512 |\n");
+    printf("The read128 and prog128 versions are for cards with a 2 Mb\n");
+    printf("  (128 KB usable) page-write flash EEPROM chip, such as:\n");
+    printf("  | SST29EE020 |\n");
+  }
+  /*
+   * Write out the usage message if an unknown command is used.
+   */
+  else {
+    printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
+    printf("(try './cromutil 0x0000 help' for details)\n");
+    exit(-1);
+  }
+  return 0;
+}
+
+#endif /* __i386__ */
diff --git a/3c90xutil/ocromutil.c b/3c90xutil/ocromutil.c
new file mode 100644 (file)
index 0000000..77ac2e3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 3c905cutil.c - perform various control ops on the 3C905C bios rom
+ *             which we assume to be an AT49BV512
+ *
+ */
+
+#ifndef __i386__
+#  error "This program can't compile or run on non-intel computers"
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+  unsigned int ioaddr, i, n;
+  unsigned char b;
+
+  setuid(0); /* if we're setuid, do it really */
+  if (argc != 3) {
+    printf("Usage: romid ioaddr [erase|id|read >file|prog <file]\n");
+    exit(-1);
+  }
+  if (iopl(3)) {
+    perror("iopl()");
+    exit(1);
+  }
+  sscanf(argv[1],"%x",&ioaddr);
+
+  /* Set the register window to 0 for the 3C905C */
+  outw(0x800, ioaddr+0xe);
+
+  if (strcmp(argv[2], "erase") == 0) {
+    /* do the funky chicken to erase the rom contents */
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x80, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x10, ioaddr+0x8);
+    sleep (1);
+    printf("Bios ROM at %04x has been erased\n", ioaddr);
+  } else if (strcmp(argv[2], "id") == 0) {
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x90, ioaddr+0x8);
+    /* 10ms delay needed */
+    printf("Manufacturer ID - ");
+    /* manuf. id */
+    outl(0x0000, ioaddr+0x4);
+    printf("%02x\n", inb(ioaddr+0x8));
+    /* device id */
+    outl(0x0001, ioaddr+0x4);
+    printf("Device ID - %02x\n", inb(ioaddr+0x8));
+    /* undo the funky chicken */
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0xf0, ioaddr+0x8);
+  } else if (strcmp(argv[2], "read") == 0) {
+    for (i = 0; i < 65536; i++) {
+      outl(i, ioaddr+0x4);
+      b = inb(ioaddr+0x8);
+      write(1, &b, 1);
+    }
+  } else if (strcmp(argv[2], "prog") == 0) {
+    for (i = 0; i < 65536; i++) {
+      n = read(0, &b, 1);
+      if (n == 0)
+       break;
+      if (n < 0) {
+       perror("File Error");
+       exit(-3);
+      }
+      outl(0x5555, ioaddr+0x4);
+      outb(0xaa, ioaddr+0x8);
+      outl(0x2aaa, ioaddr+0x4);
+      outb(0x55, ioaddr+0x8);
+      outl(0x5555, ioaddr+0x4);
+      outb(0xA0, ioaddr+0x8);
+      outl(i, ioaddr+0x4);
+      outb(b, ioaddr+0x8);
+      while (inb(ioaddr+0x8) != b)
+       ;
+    }
+  }
+  return 0;
+}
+
+#endif /* __i386__ */
diff --git a/3c90xutil/romutil.txt b/3c90xutil/romutil.txt
new file mode 100644 (file)
index 0000000..58074b9
--- /dev/null
@@ -0,0 +1,36 @@
+I wrote the attached little util program to try out the basic approach
+and thought that you might find it useful as well as providing some
+simple testing. It isn't a final solution so the interface is rough. The
+program must be run as root on an Intel based machine.
+
+The key point is that the IO address needs to be entered - I grab it
+from the dmesg output:
+
+eth0: 3Com 3c905B Cyclone 100baseTx at 0xe400,  00:10:4b:d2:5e:0d, IRQ
+11
+
+or "cat /proc/pci" to find the "I/O at XXXXXX" for your 3Com Card.
+
+Some example commands are:
+
+romutil 0xe400 erase            - erases the ROM contents
+romutil 0xe400 protect            - enables the Software Data Protection
+on the ROM [3c905B only]
+romutil 0xe400 unprotect       - disables the Software Data Protection
+on the ROM [3c905B only]
+romutil 0xe400 id                    - displays the manufacturer and
+device IDs
+romutil 0xe400 read >file    - writes the contents of the ROM to stdout
+romutil 0xe400 prog <file    - writes the contents of the stdin into the
+ROM (<64k)
+
+I tried reading and writing the ROM while doing large ftp transfers and
+experienced no problems. I didn't spend much time worrying about the
+possible race conditions. My system has lots of resources (450MHx P2,
+128MB RAM) so it might not provide the best test candidate.
+
+Let me know what results you get if you try it out.
+
+Thanks
+
+John
diff --git a/Diskless-From-NT/Config.txt b/Diskless-From-NT/Config.txt
new file mode 100644 (file)
index 0000000..60385fb
--- /dev/null
@@ -0,0 +1,537 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_ISA=y
+# CONFIG_SBUS is not set
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Processor type and features
+#
+CONFIG_M386=y
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_M686FXSR is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_X86_CMPXCHG is not set
+CONFIG_X86_L1_CACHE_SHIFT=4
+# CONFIG_TOSHIBA is not set
+# CONFIG_MICROCODE is not set
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_MTRR=y
+# CONFIG_SMP is not set
+# CONFIG_X86_UP_IOAPIC is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+# CONFIG_VISWS is not set
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_EISA=y
+# CONFIG_MCA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PM=y
+# CONFIG_ACPI is not set
+# CONFIG_APM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_SK_G16 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+
+#
+# Game port support
+#
+
+#
+# Gameport joysticks
+#
+
+#
+# Serial port support
+#
+
+#
+# Serial port joysticks
+#
+
+#
+# Parallel port joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=m
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_I810=y
+CONFIG_AGP_VIA=y
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+CONFIG_SOUND_ES1371=m
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+CONFIG_SOUND_SB=m
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+CONFIG_SOUND_YM3812=m
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMPCI is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
diff --git a/Diskless-From-NT/Diskless-From-NT.txt b/Diskless-From-NT/Diskless-From-NT.txt
new file mode 100644 (file)
index 0000000..54c2b74
--- /dev/null
@@ -0,0 +1,565 @@
+
+
+The Diskless Terminal running from NT server Mini-HOWTO
+Pavel Tkatchouk, ptkatcho@portal.ca
+v0.1, June 19th 1999
+
+Table of Contents
+
+1. Introduction.
+
+   1.1 What is it for?
+   1.2 Do we need this HOWTO?
+   1.3 A bit of History.
+
+2. Project description.
+
+   2.1 Packaging.
+   2.2 Image.
+      2.2.1 Kernel.
+      2.2.2 MRFS.
+      2.2.3 Building MRFS.
+   2.3 Remotefs.
+   2.4 Booting sequence.
+      2.4.1 BOOTP, TFTP.
+   2.5 Bootprom.
+
+3. Resources.
+
+4. Copyright.
+
+5. Feedback and credits.
+
+
+1. Introduction.
+
+
+1.1. What is it for?
+
+This document describes how to build software distribution to run Java client on diskless 
+terminal booted from Microsoft Windows 95/98/NT workstation. Package can also be easily 
+modified to be used as Linux terminal or X Windows terminal's software. I found it also 
+convenient for setup over the Ethernet of floppyless PS's, hard disk of which for some 
+reason can not be accessed (sealed case under warranty, etc.).
+
+
+1.2. Do we need this HOWTO?
+
+To be honest, I'm not sure. There are few excellent HOWTO's (see 3. Recources) that up until 
+recently I considered quite sufficient to build what I've done two years ago. But since my 
+project uses MS Windows as a file server vs. traditional NFS there were some know-how's 
+involved which number of people wanted to see in some formal document.
+
+
+1.3. A bit of history.
+
+My project at that time (1996) was to find OS/JVM that will allow to run Java application 
+on hardware we manufacture. Hardware is practically generic x86 PC except it has no keyboard, 
+hard drive, floppy drive, mouse, but touchscreen over LCD, plus some POS specific peripherals 
+(badge reader, credit card reader, etc.). Due to cost consideration it had no any significant 
+storage, so OS and Java client along with support binaries, libraries etc. had to be loaded 
+remotely. Because our clients are exclusively Windows shops, Server had to be Windows as well. 
+During evaluation of different commercial OS'es along with JVM's available it become apparent 
+to my surprise that most promising solution was GPL one - Linux.
+
+
+2. Project description.
+
+2.1. Packaging.
+
+The whole distribution consists of remote file system (RemoteFS) residing on MS Windows
+server (NT Workstation, NT Server or Windows9x) and tagged bootable image. 
+
+
+2.2. Image.
+
+Image (~1.5MB) is generated by mknbi utility that comes with Etherboot package
+<http://etherboot.sourceforge.net>. It can include minimal root file system (MRFS) 
+like in my case (since I had to boot client from MS Windows server and Linux kernel doesn't 
+support SMBFS-Root, only NFS-Root. So I had to keep rootfs in the ramdisk). To generate 
+image the following script can be used.
+
+#!/bin/sh
+# mkrootnet: makes tagged netbootable image
+# This image includes kernel and minimal root filesystem
+# to do initial boot.
+#
+# Copyright (c) Pavel Tkatchouk 1996. All rights reserved.
+# Permission is granted for this material to be freely
+# used and distributed, provided the source is acknowledged.
+# No warranty of any kind is provided. You use this material
+# at your own risk.
+#
+DEVICEFILENAME="/tmp/file"             # temporary file to be used as device
+FSBLOCKS=4096                                  # uncompressed filesystem size in K
+BOOTDISKDIR="/usr/BOOT/ROOTFS" # root filesystem model
+MOUNT="/mnt2"                          # temporary mount point
+ROOTFS="/tmp/rootfs"                   # root filesystem image
+ROOTFSGZ="/tmp/rootfs.gz"              # compressed root filesystem image
+KERNEL="/usr/KERNELS/vmlinuz-nt"       # kernel image
+KERNELTMP="/tmp/vmlinuz"               # temporary copy of kernel image
+BOOTIMAGE="/tmp/img"                   # tagged image to be booted by client
+# if you want ramisk more than default 4096 set CMDLINE, don't forget to
+# adjust $FSBLOCKS 
+# CMDLINE="ramdisk_size=8192"          # parameters to pass to the kernel
+# 
+echo "check:"
+echo "- if tftp server's download dir mounted to /mnt"
+echo "- loopback device is built-in or loaded"
+echo "\n press Enter when done"
+read tmp 
+UPLOAD="/mnt/tmp"                              # tftp server's dir to upload bootimage
+echo -e "\nZeroing $DEVICEFILENAME of $FSBLOCKS k"
+echo "to be used as device for root filesystem model"
+dd if=/dev/zero of=$DEVICEFILENAME bs=1k count=$FSBLOCKS
+echo -e "\nMaking file system on $DEVICEFILENAME"
+mke2fs -m 0 $DEVICEFILENAME
+echo "Mounting $DEVICEFILENAME as a loopback device"
+mount -o loop -t ext2 $DEVICEFILENAME $MOUNT
+curdir=`pwd`
+cd $BOOTDISKDIR
+echo -e "Copying files from $BOOTDISKDIR to $DEVICEFILENAME, please wait"
+find . -print|cpio -pmd $MOUNT
+echo "Unmounting $MOUNT"
+umount $MOUNT
+cd $curdir
+echo "Copying $DEVICEFILENAME to $ROOTFS"
+dd if=$DEVICEFILENAME of=$ROOTFS bs=1k
+echo "Compressing $ROOTFS, it may take a while"
+echo "Please wait..."
+if [ -f $ROOTFSGZ ];then
+       rm -f $ROOTFSGZ
+fi
+gzip -c $ROOTFS>$ROOTFSGZ
+rm -f $ROOTFS
+echo -e "\nCreating netbootable image"
+cp $KERNEL $KERNELTMP
+mknbi -d ram -i rom -r $ROOTFSGZ -k $KERNELTMP -a $CMDLINE -o $BOOTIMAGE
+echo "Uploading $BOOTIMAGE to $UPLOAD"
+cp $BOOTIMAGE $UPLOAD
+echo "Cleaning after ourselves"
+rm -f $KERNELTMP $DEVICEFILENAME $BOOTIMAGE
+echo "All done"
+
+
+In the above script actual image is generated by the following comand
+
+#mknbi -d ram -i rom -r rootfs.gz -k vmlinuz-nt -o img
+
+where:
+       rootfs.gz - minimal root file system (MRFS);
+       vmlinuz-nt   - kernel;
+       img       - resulting image.
+
+
+Note:
+Default ramdisk size is 4096. It was enough for RedHat4.1 based minimal file system, but 
+apparently not enough for 5.2 based. When this happens "end request:I/O error, dev 01:00 ..." 
+error shows up. To fix that either use "mknbi -a ramdisk_size=8192" to pass parameter to the 
+kernel (doesn't require kernel recompilation), or change /usr/src/linux/drivers/block/rd.c: 
+int rd_size= from 4096 to 8192 or whatever and rebuild the kernel.                                                    
+
+
+2.2.1. Kernel.
+
+Kernels 2.0.30 and 2.0.36 have been used by author, although nothing is preventing you from
+experimenting with others. Kernel should include ramdisk support. The following 
+<link to .config> configuration has been used to build <link to binary (kernel 2.0.30)>. 
+You may find some components unnecessary, just exclude them and rebuild. 
+
+Don't forget to change root device after you built the kernel (rdev vmlinuz /dev/rd).
+
+Gotcha's: apparently smbfs is broken in 2.2.x kernels. Symptoms: remote share is mounted
+just fine but after a while fails with "smb_request: result = -32" errmsg. I've heard
+SuSe has fix for that.
+
+2.2.2. MRFS.
+
+Minimal root file system is required to get Linux up and running along with networking until 
+it can mount remote file system to run X/Java from there. After image gets loaded from the 
+server MRFS is decompressed into ramdisk. If you can afford a lot of ram on your terminal the 
+entire remote file system can be moved to rootfs.gz. That will make your terminal more 
+responsive.
+
+
+2.2.3. Building MRFS.  
+
+Some folks found it easier to start from scratch, others use known "minimal" Linux distributions
+(Linux Router, tomsrtbt, etc.), yet others prefer to start from "big" Linuces like I did. Every
+path has it's pro and contras.
+
+Pruning standard distribution (RedHat, Debian, etc.) to your needs might be very time consuming.
+To ease that painful process I have used remotely booted diskless client with NFS-Root (see 
+Etherboot's Readme, NFS-Root and NFS-Root-Client mini-HOWTO's, Diskless-HOWTO):
+
+- setup minimal RedHat4.1 install (networked workstation, X, no development, mail, etc., ~117MB);
+- find . -print|cpio -pmd /usr/NFS/ROOTFS - copy entire fs tree to NFS exported dir;
+- mknod /usr/NFS/ROOTFS/dev/nfsroot b 0 255;
+- build vmlinuz-nfs kernel according to NFS-Howto (built-in bootp,rarp,NFS,NFS root,NIC 
+  driver,RAM disk);
+- rdev vmlinuz-nfs /dev/nfsroot - to set NFS root device; 
+- build image for NFS-Root fs:
+  #mknbi -d rom -i rom -k vmlinuz-nfs -o nfsImage;
+- boot client while monitoring NFS file requests (by Solaris snoop);
+- copy files from /usr/NFS/ROOTFS to /usr/BOOT/ROOTFS (MRFS model) according to snoop's
+  filelist;
+- generate image by mkrootnet script (don't forget to point to the right kernel vmlinuz-nt).
+
+The above trick not only allows to determine the sought files set but also debug boot process 
+analyzing NFS messages. I found it convenient to put "read tmp" statements into init scripts
+for debugging. Tracking files up until issuing login gives you <link to rootfs.gz> MRFS (~1MB) 
+that can be used to boot Linux from ROM (flash, eprom, DiskOnChip, SanDisk, etc.) as well. All 
+the other files requested by client (during starting X, Java, Java client) were put into (link 
+to remotefs.zip, ~9MB).
+
+
+To restore MRFS model on your PC from the above rootfs.gz:
+- #cd /tmp
+- #gunzip rootfs.gz
+- #mount -o loop -t ext2 /tmp/rootfs /mnt
+- #cd /mnt
+- #find . -print|cpio -pmd /usr/BOOT/ROOTFS
+- #umount /mnt
+
+Note: 
+
+You will have to change attributes of some dirs, files (/etc/mtab, /etc/mtab~, /var/lock/subsys/*, 
+/var/run/*, /dev/tty*, etc.) against standard. This is because with standard attribs diskless 
+client refused to work. For example I had to change /dev/tty* ownerships to 99:99 from original 
+0:0 or 0:5, to get rid of errmsg "INIT: Id "1" respawning too fast: disabled for 5 minutes". 
+Being admin illiterate I just chmod them to 777 and chown to 99:99 to make life easier. 
+THIS IS SERIOUS SECURITY VIOLATION!!! Using keyboardless terminal with no daemons running in 
+my case reduces the risk, yet I would appreciate very much those more experienced who will help 
+to restore the right attribs while keeping the distribution working.
+
+Some "gotcha's" to watch for during MRFS building:
+- standard attributes/ownership of some files don't work;
+- rdev must be set (non-tagged image didn't work, so couldn't use config file to pass parrs 
+  to the kernel);
+- diskless client writes 99:99 ownership on generated files;
+- "password incorrect" for root, but any other OK and su OK too.
+
+
+2.3. RemoteFS.
+
+Remotefs.zip file includes everything required by the system that can be located on
+remote file system, i.e after booting has been complete and remote file system mounted.
+In my case it is X Windows System and Java binaries, libraries etc. To use that file on
+MS Windows NT:
+- unzip remotefs.zip to some directory;
+- share this directory read-only as "usr" (or share as some other name and pass this name to
+  the client through bootptab configuration file for BOOTP server;
+- create an account username=root, password=linux on NT (can be set in bootptab).
+
+Note:
+There's no symbolic links on NTFS, so UNIX links must be replaced by copies on NTFS. 
+To determine potential troublmakers one could use the following:
+- first copy required subset (according to snoop's intercept) from /usr/NFS/ROOTFS to 
+  /usr/BOOT/REMOTEFS;
+- mount some share from NTFS to /mnt;
+- /usr/BOOT/REMOTEFS#find . -print|cpio -pmd /mnt 2>links;
+In the links file you will find names to work with.
+
+
+2.4. Booting sequence.
+
+Boot occurs in the following sequence:
+- bootprom sends bootp request,
+- bootp server responds with subnet mask, client's name, client's IP, TFTP server's IP, 
+  bootfile name and some optional parameters (like NT's username/password to use it's share,
+  you could pass some other share name here as say T104="somedir");
+- bootprom downloads image from TFTP server;
+- kernel starts;
+- kernel decompresses MRFS in RAM;
+- system starts init using ramdisk root,
+- mounts remote file system from NT via SMBFS;
+- automatically logins;
+- starts xstart script located on remotefs (/usr/sbin) where you can start any of your
+  programs, change parameters, etc. without rebuilding the image.
+
+Below are some config/init sample files from <rootfs.gz>, <remotefs.zip>:
+
+<bootptab, change to link>
+t1:sm=255.255.255.0:sa=192.168.33.150:bf=img:T100="pavelnt4":T101="root":T102="linux"
+touch1:hn=touch1:tc=t1:ha=00A0F00035CD:ip=192.168.33.127
+
+</etc/fstab, change to link>:
+/dev/ram  /      ext2    defaults    1 1
+/proc     /proc  proc    defaults    0 0
+
+</etc/rc.d/rc.bootp, change to link later>:
+#!/bin/sh
+# Written to simply set the IP stuff up from the
+# bootpc data.
+# Last updated : Mon Mar 10 15:17:01 1997
+#
+# Variables
+
+BOOTPC=/sbin/bootpc
+IFCONFIG=/sbin/ifconfig
+ROUTE=/sbin/route
+BINHOST=/bin/hostname
+DEV=eth0
+ASKSERVER="255.255.255.255"
+TW="--timeoutwait 320"
+RIF="--returniffail"
+RIFMESSAGE="Bootp failed -- disabling network."
+RCONF=/etc/resolv.conf
+EHOSTS=/etc/hosts
+LHOSTS=/etc/hosts.local
+TMPFILE=/tmp/bootp
+# Functions
+# Remove the networking by taking down the interface
+netdown() {
+  ${ROUTE} del default
+  ${IFCONFIG} ${DEV} down
+}
+## End of the functions
+
+## Start of the actual work
+# Bring up minimal networking use 0.0.0.0 as our address as we don't
+# know it yet (Means "Me but I don't know my address or network")
+${IFCONFIG} ${DEV} up 0.0.0.0
+${ROUTE} add default dev ${DEV}
+
+# Perform the bootp  --  doesn't return unless it gets an answer
+if ${BOOTPC} --dev ${DEV} --server ${ASKSERVER} ${RIF} ${TW} > ${TMPFILE}
+then
+# Take down networking (use the 0.0.0.0 for as short a time as possible)
+  netdown
+# Read in the values   
+  . ${TMPFILE}
+
+# To use in mountsmb script later
+SMBSERVER=${T100}
+# And delete the temporary file
+#  rm ${TMPFILE}
+else
+# Take down networking (use the 0.0.0.0 for as short a time as possible)
+  netdown
+# give message and quit
+  echo ${RIFMESSAGE}
+  exit 1
+fi
+
+# Start the loopback interface and add a route to it
+# It's already set by standard init?
+${IFCONFIG} lo 127.0.0.1
+${ROUTE} add -net 127.0.0.0
+
+# Setup of IP stuff needs doing first
+#
+if [ -z "${NETMASK}" ] ; then
+# No netmask info, all this is guessed from the IP number
+# If this is wrong for your network FIX the bootpd to know
+# what it should send in the RFC1497 cookie!  11/02/94 JSP
+#
+  ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} 
+  ${ROUTE} -n add -net ${NETWORK} dev ${DEV}
+else
+# We will have NETMASK, BROADCAST, and NETWORK defined 
+  ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK} 
+  ${ROUTE} -n add -net ${NETWORK} dev ${DEV}
+fi
+
+# Set the hostname from what we got via bootp or reverse lookup
+
+echo "127.0.0.1        loopback localhost">${EHOSTS}
+${BINHOST} "${HOSTNAME}"
+echo "${IPADDR}        ${HOSTNAME}" >>${EHOSTS}
+echo "${SERVER} ${SMBSERVER}" >>${EHOSTS}
+
+
+</etc/rc.d/rc.local, change to link>:
+#!/bin/sh
+# This script will be executed *after* all the other init scripts.
+# You can put your own initialization stuff in here if you don't
+# want to do the full Sys V style init stuff.
+#
+# 07/02/97 Pavel Tkatchouk
+#
+echo "Start networking"
+insmod /lib/8390.o
+insmod /lib/ne.o io=0x300 irq=9
+echo "Install serial"
+insmod /lib/serial.o
+echo "Install touch"
+insmod /lib/touch.o
+echo "Install smbfs"
+insmod /lib/smbfs.o
+echo "Getting TCP/IP parameters from bootp server"
+echo "and start networking"
+/etc/rc.d/rc.bootp
+if [ -f /etc/squirrel-release ]; then
+       R=$(cat /etc/squirrel-release)
+else
+       R="release 0.02"
+fi
+echo "Mounting remote fs"
+/sbin/mountsmb
+echo "XYZ Inc. Diskless Linux $R"
+echo "Starting X and Java client without login"
+su -c /sbin/xstart root
+
+
+</usr/sbin/xstart, change to link>:
+#!/bin/bash
+#
+# Script to start X and Java client
+# 08/07/97 Pavel Tkatchouk
+#
+# Read bootps response first
+. /tmp/bootp
+# -s 0 to disable screen-saver
+/usr/X11R6/bin/X -s 0 &
+export DISPLAY=:0.0
+# /usr is share mounted from Windows workstation
+cd /usr/program/
+java SomeJavaApp 
+
+
+</sbin/mountsmb, change to link>:
+#!/bin/bash
+# mountsmb: mounts remote filesystems from NT workstation 
+# using Microsoft's SMB protocol 
+# 
+# Copyright (c) Pavel Tkatchouk 1997. All rights reserved.
+# Permission is granted for this material to be freely
+# used and distributed, provided the source is acknowledged.
+# No warranty of any kind is provided. You use this material
+# at your own risk.
+#
+# Last edit June 29 8:30 1997
+#
+MOUNTDIR="usr"
+SHRDIR="usr"
+BOOTPRES="/tmp/bootp"
+# Read botpc response
+. ${BOOTPRES}
+# Sharename from NT server, uncomment if you want to use 
+# non-hardcoded "usr" but from bootptab
+#SHRDIR=${T104} 
+SMBSRV="//${T100}"
+CLIENT="${HOSTNAME}"
+USER="${T101}"
+PASSWORD="${T102}"
+echo -e "\nMounting $SMBSRV/$SHRDIR to /$MOUNTDIR"
+smbmount $SMBSRV/$SHRDIR $MOUNTDIR -c $CLIENT -U $USER -P $PASSWORD
+echo -e "\nDone"
+
+Gotcha's:
+Looks like smbmount client from smbfs package used to mount remote Windows shares to local 
+Linux dirs in pre 2.2.x era isn't maintained anymore so you should use one coming with 
+Samba package. Also binary smbmount won't work with 2.2.x, so you have to recompile with 
+2.2.x headers following Samba's readme. Yet even that won't guarantee reliable work until
+somebody fixes kernel's smbfs module.
+
+2.4.1. BOOTP, TFTP.
+
+There are number of BOOTP, TFTP servers for Windows on the market. You could find them
+here:
+
+- www.walusoft.co.uk (Walusoft's tftp);
+- ftp.coast.net/simtel/nt/internet/tftpds12.zip (Millwood AB's tftp);
+- ftp.cabletron.com/pub/snmp/bootftp/boottft2.zip (Cabletron's bootp/tftp combo);
+- www.tellurian.au.com (Tellurian's bootp, tftp, dhcp servers).
+- www.metainfo.com (Metainfo's DHCP server)
+- www.nts.com (Network Telesystems's DHCP server in IPserver package)
+
+My choice was Tellurian's products - very reliable, simple to install, attractively priced
+(fully capable evaluation versions are available).
+
+2.5. Bootprom.
+
+Ken Yap's Etherboot <etherboot.sourceforge.net> will tell you everything about bootprom. 
+Here I just want to mention that normally you would have to put bootprom's code into network
+adapter's PROM. But if your hardware like mine has BIOS programmed in flash you could 
+re-program it to add bootprom (some BIOS requires special programmer to do that, others don't)
+as BIOS extension.
+
+This is what I did to add ne.rom (bootprom generated by Etherboot's makerom for NE2000 clone) 
+to AMI BIOS on my flash:
+
+- read flash content by programmer into bios.bin binary file;
+- use one of available binary editors (say www.simtel.net/Win95/editors/hxp3005.zip to add
+  ne.rom to bios.bin (and to edit ne.rom if necessary);
+- write new bios.bin back to flash.
+
+Notes:
+- makerom generates bootprom for standard EPROM sizes (8k, 16k, 32k, etc.), so if you tight on 
+  space use -s flag to adjust size (or cut it manually to multiple of 512 bytes blocks, just
+  don't forget to adjust extension's length which is coded in Byte 2 and checksum to 8 bits 
+  of zero;
+- valid absolute addresses for BIOS extensions are from 0xC8000 to 0xF4000 (check with 
+  motherboard's manufacturer how flash is mapped onto system memory space);
+- Byte 0 must be 0x55, Byte 1 must be 0xAA, Byte 2 must be extension's length in 512 bytes 
+  blocks;
+- extension BIOS has to start at a 2k boundary;
+
+
+3. Resources.
+
+FAQ's:
+- tomsrtbt.FAQ (www.toms.net);
+
+HOWTO's:
+- Paul Moody's miniHOWTO (www.linuxembedded.com/pmhowto.html)
+- Diskless;
+- Diskless-HOWTO;
+- NFS-Root;
+- NFS-Root-Client;
+- Bootdisk-HOWTO;
+- BootPrompt-HOWTO;
+- NCD-X-Terminal;
+- Remote-Boot;
+- Remote-X-Apps;
+
+Web:
+- etherboot.sourceforge.net/
+- www.waste.org/~zanshin
+- www.tellurian.com.au.
+- www.toms.net
+- www.trinux.org
+- www.linux.org.uk/ELKS-Home
+- www.embedded.com
+- www.linuxembedded.com
+- www.thinlinux.org
+- www.linuxrouter.org
+- linux-mandrake.com
+- www.disklessworkstations.com
+
+Newsgroups:
+- comp.arch.embedded
+
+Lists:
+- netboot-owner@baghira.han.de
+- linux-embedded@waste.org
+
+Magazines:
+- Circuit Cellar #100 - 105
+
+
+4. Copyright.
+
+Copyright (c) Pavel Tkatchouk 1999.
+Permission is granted for this material to be freely used and distributed, provided the source 
+is acknowledged. Copyright policy is GPL as published by the Free Software Foundation.
+
+No warranty of any kind is provided. You use this material at your own risk.
+
+
+5. Feedback and credits.
+
+Since I am neither have a lot of Linux experience nor native English speaker, there would be 
+errors in this document. I would accept any help with gratitude whether in form of proof-reading, 
+techical corrections or otherwise. Please send your comments, suggestions and questions to Pavel 
+Tkatchouk (ptkatcho@portal.ca)
+
+I wish to thank Pierre Mondie who convinced me to start this document. I'm also very much in 
+debt to all those who's work made this project possible:
+
+Ken Yap                <ken_yap@users.sourceforge.net> (Etherboot)
+David Newall   <www.tellurian.com.au>  (Bootpdnt/Ftpdnt)
+(to be continued)
+
diff --git a/Diskless-From-NT/furtmayr.html b/Diskless-From-NT/furtmayr.html
new file mode 100644 (file)
index 0000000..224632d
--- /dev/null
@@ -0,0 +1,82 @@
+<html>
+
+<head>
+<title>Free TFTP / Syslog / NFS Servers for Windows</title>
+</head>
+
+<body>
+
+<h3 align="center">Free TFTP / Syslog / NFS Servers for Windows</h3>
+<div align="center"><center>
+
+<address>
+  Stefan Furtmayr (<a href="mailto:sf@paf.net">sf@paf.net</a>) 
+</address>
+</center></div>
+
+<p>Feel free to send me your comments about these programs or some additions.</p>
+
+<p>Also have a look at the <a
+href="http://www.ltsp.org/contrib/diskless-windows-howto.htm">&quot;Diskless Windows
+Cookbook &quot;</a> in the <a href="http://www.ltsp.org/contrib/">LTSP Contrib Area</a>.</p>
+
+<p><small>From this list I have only used the W2K-TFTP once for a customer with the <a
+href="http://support.3com.com/infodeli/tools/nic/mba.htm">3Com MBA Utility Disk</a>, while
+it can be used as well with <a href="http://etherboot.sourceforge.net">Etherboot</a>
+tagged images for other NIC brands.</small><br>
+<small>The solution used a netbooted DOS with MS Client 3.0 to easily restore disk images
+with <a href="http://www.ghost.com/">Symantec Ghost</a> (see <a
+href="http://appdeploy.com/tools/imaging.shtml">appdeploy.com</a> for similar tools).</small><br>
+<small>Sure there are several possibilities to do this with Linux but for cloning NT4/W2K
+the NTFS support is rather experimental and automatically changing the SID is another
+issue.</small></p>
+
+<h4>TFTP Servers:</h4>
+
+<p>In Autumn 2000 i tested some different TFTP servers and found out that most of them do
+not install/run as a service, especially under W2K. 
+
+<ul>
+  <li>TFTP server included with Windows 2000 (remote installation services need to be
+    installed)<br>
+    The path for the images has to be specified via registry:<br>
+    Q232115 - Changing the Drive or Volume on Which Remote Installation Images Reside:<br>
+    <a href="http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP">http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP</a></li>
+  <li>3CDaemon version 2.0 revision 10. Freeware. Integrated TFTP/FTP/Syslog Daemon for
+    Windows 95/98/NT<br>
+    <a href="ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip">ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip</a><br>
+    - Windows 2000 Server: does not run as service!<br>
+    - Windows NT Server 4.0: not tested</li>
+  <li>The TFTP Server portion of 3CServer, altered to run as a system Service under Windows NT<br>
+    <a href="ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip">ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip</a><br>
+    - Windows 2000 Server: only working in debug mode, does not run as service!<br>
+    - Windows NT Server 4.0: not tested</li>
+  <li>Cisco TFTP Server v.1.1<br>
+    <a href="http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp">http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp</a><br>
+    Does not provide an option itself to install as service.</li>
+  <li><a href="http://solarwinds.net/Tools/Free_Tools/TFTP_Server/">http://solarwinds.net/Tools/Free_Tools/TFTP_Server/</a><br>
+    Does not provide an option itself to install as service.</li>
+</ul>
+
+<p><em>Untested:</em></p>
+
+<p>found on <a href="http://www.nonags.com/nonags/servd32.html">http://www.nonags.com/nonags/servd32.html</a><br>
+- <a href="http://www.klever.net/kin/pumpkin.html">http://www.klever.net/kin/pumpkin.html</a><br>
+- <a href="http://membres.tripod.fr/phjounin//P_tftpd32.htm">http://membres.tripod.fr/phjounin//P_tftpd32.htm</a></p>
+
+<h4>Syslog Servers:</h4>
+
+<ul>
+  <li>3Com Software Library - Utilities for 32 bit Windows<br>
+    <a href="http://support.3com.com/software/utilities_for_windows_32_bit.htm">http://support.3com.com/software/utilities_for_windows_32_bit.htm</a></li>
+  <li><a href="http://www.netal.com/download.htm#SL4NT03">http://www.netal.com/download.htm#SL4NT03</a>
+    (works as service) </li>
+</ul>
+
+<h4>NFS Servers:</h4>
+
+<ul>
+  <li>War NFS Daemon: <a href="http://www.jgaa.com">http://www.jgaa.com</a> (untested)</li>
+</ul>
+</body>
+</html>
diff --git a/auto-default/mail b/auto-default/mail
new file mode 100644 (file)
index 0000000..015c789
--- /dev/null
@@ -0,0 +1,40 @@
+Date:        11/9/2001 3:56 PM
+Received:    11/9/2001 4:05 PM
+From:        Steve Tilden, stilden@sicom-sys.com
+
+...
+
+2)  I have added conditional code to main.c from Etherboot 5.0.4 to add
+a new default boot option and I have included the modified main.c as an
+attachment to this message.
+
+As I received Etherboot 5.0.4, in the Config file, if you select
+ASK_BOOT with a non zero time-out option, then you also get to set
+ANS_DEFAULT = ANS_NETWORK or ANS_DEFAULT = ANS_LOCAL to determine what
+will happen if the operator does not respond to the prompt.   I have now
+added conditional code in main.c such that if you set ANS_DEFAULT =
+ANS_AUTO, the default answer will be set according to whether or not
+there is a hard disk in the system (as detected by the BIOS).  If a hard
+disk is present, then if the operator does nothing, the system will boot
+from it.  If a hard disk does not exist, then again if the operator does
+nothing, the system will boot via the network.  Either way, for our
+particular environment, the operator has to do nothing to get it to boot
+correctly.  Yet the operator can still override the default selection
+to, for example, allow a unit without a hard disk, to boot directly from
+a floppy rather than the network, or to allow a unit with a hard disk,
+to boot from the network.
+
+I don't know it the code I have added might be correct for a future
+production version of Etherboot, but I thought I'd send it to you and
+let you get it into the system if you feel it might be appropriate.
+
+Thanks,
+
+Steve Tilden
+Sicom Systems Inc.
+stilden@sicom-sys.com
+
+[Ed: On a compliant BIOS, it will actually boot the next device in the
+BIOS list if local is selected, either explicitly or by timeout, which
+may or may not be the hard disk, which is why it's less than general and
+not included in the distribution by default.]
diff --git a/auto-default/main.c.patch b/auto-default/main.c.patch
new file mode 100644 (file)
index 0000000..e707b63
--- /dev/null
@@ -0,0 +1,55 @@
+--- main.c     Mon Nov  5 18:58:30 2001
++++ main.c.new Thu Nov 15 01:45:12 2001
+@@ -149,21 +151,49 @@
+ static unsigned short ipchksum(unsigned short *ip, int len);
+ static unsigned short udpchksum(struct iphdr *packet);
++
++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO)
++/*
++ * Read Installed Hard Disk Count from BIOS memory at 0:0475
++ */
++static int hdsk_cnt(void)
++{
++      int retv;
++      __asm__ __volatile__(
++       "xorw %%ax,%%ax\n\t"
++       "movb 0x475,%%al\n"
++       : "=a" (retv)
++       : /* no inputs */
++       : "ax", "cc", "memory"
++      );
++      return(retv);
++}
++#endif /* ASK_BOOT && ANS_AUTO */
++
++
+ static inline void ask_boot(void)
+ {
+ #if defined(ASK_BOOT) && ASK_BOOT > 0
+       while(1) {
+-              int c;
++              int c, deflt;
+               unsigned long time;
++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO)
++              if (hdsk_cnt() != 0)
++                      deflt = ANS_LOCAL;
++              else
++                      deflt = ANS_NETWORK;
++#else
++              deflt = ANS_DEFAULT;
++#endif
+               printf(ASK_PROMPT);
+               for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); )
+                       if (currticks() > time) {
+-                              c = ANS_DEFAULT;
++                              c = deflt;
+                               goto done;
+                       }
+               c = getchar();
+               if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
+-              if (c == '\n') c = ANS_DEFAULT;
++              if (c == '\n') c = deflt;
+ done:
+               if ((c >= ' ') && (c <= '~')) putchar(c);
+               putchar('\n');
diff --git a/award_plugin_roms/README b/award_plugin_roms/README
new file mode 100644 (file)
index 0000000..5f657cf
--- /dev/null
@@ -0,0 +1,2 @@
+An Award BIOS ROM lister in Perl contributed by Eric W. Biederman
+<ebiederman@lnxi.com>.
diff --git a/award_plugin_roms/award_plugin_roms.pl b/award_plugin_roms/award_plugin_roms.pl
new file mode 100755 (executable)
index 0000000..2b95eed
--- /dev/null
@@ -0,0 +1,341 @@
+#!/usr/bin/perl -w
+use strict;
+use FileHandle;
+use integer;
+
+sub unsigned_little_endian_to_value
+{
+       # Assumes the data is initially little endian
+       my ($buffer) = @_;
+       my $bytes = length($buffer);
+       my $value = 0;
+       my $i;
+       for($i = $bytes -1; $i >= 0; $i--) {
+               my $byte = unpack('C', substr($buffer, $i, 1));
+               $value = ($value * 256) + $byte;
+       }
+       return $value;
+}
+
+sub decode_fixed_string
+{
+       my ($data, $bytes) = @_;
+       return $data;
+}
+
+sub decode_pstring
+{
+       my ($buf_ref, $offset_ref) = @_;
+       # Decode a pascal string
+       my $offset = ${$offset_ref};
+       my $len = unpack('C',substr(${$buf_ref}, $offset, 1));
+       my $data = substr(${$buf_ref}, $offset +1,  $len);
+       ${$offset_ref} = $offset + $len +1;
+       return $data;
+}
+
+sub decode_cstring
+{
+       # Decode a c string
+       my ($buf_ref, $offset_ref) = @_;
+       my ($data, $byte);
+       my $index = ${$offset_ref};
+       while(1) {
+               $byte = substr(${$buf_ref}, $index, 1);
+               if (!defined($byte) || ($byte eq "\0")) {
+                       last;
+               }
+               $data .= $byte;
+               $index++;
+       }
+       ${$offset_ref} = $index;
+       return $data;
+}
+
+sub type_size
+{
+       my ($entry) = @_;
+       my %type_length = (
+               byte => 1,
+               half => 2,
+               word => 4,
+               xword => 8,
+               'fixed-string' => $entry->[2],
+               pstring => 0,
+               cstring => 0,
+       );
+       my $type = $entry->[0];
+       if (!exists($type_length{$type})) {
+                die "unknown type $type";
+        }
+       my $length = $type_length{$type};
+       return $length;
+}
+
+sub decode_fixed_type
+{
+       my ($type, $data, $bytes) = @_;
+       my %decoders = (
+               'byte' => \&unsigned_little_endian_to_value,
+               'half' => \&unsigned_little_endian_to_value,
+               'word' => \&unsigned_little_endian_to_value,
+               'xword' => \&unsigned_little_endian_to_value,
+               'fixed-string' => \&decode_fixed_string,
+       );
+       my $decoder = $decoders{$type} or die "unknow fixed type $type";
+       return $decoder->($data, $bytes);
+}
+
+sub decode_variable_type
+{
+       my ($type, $buf_ref, $offset_ref) = @_;
+       my %decoders = (
+               'pstring' => \&decode_pstring,
+               'cstring' => \&decode_cstring,
+       );
+       my $decoder = $decoders{$type} or die "unknow variable type $type";
+       return $decoder->($buf_ref, $offset_ref);
+}
+
+sub decode_struct
+{
+       my ($buf_ref, $offset, $layout) = @_;
+       my $initial_offset = $offset;
+       my ($entry, %results);
+       foreach $entry (@$layout) {
+               my ($type, $name) = @$entry;
+               my $bytes = type_size($entry);
+               if ($bytes > 0) {
+                       my $data = substr(${$buf_ref}, $offset, $bytes);
+                       $results{$name} = decode_fixed_type($type, $data, $bytes);
+                       $offset += $bytes;
+               } else {
+                       $results{$name} = decode_variable_type($type, $buf_ref, \$offset);
+               }
+       }
+       return (\%results, $offset - $initial_offset);
+}
+
+sub print_big_hex
+{
+       my ($min_digits, $value) = @_;
+       my @digits;
+       while($min_digits > 0 || ($value > 0)) {
+               my $digit = $value%16;
+               $value /= 16;
+               unshift(@digits, $digit);
+               $min_digits--;
+       }
+       my $digit;
+       foreach $digit (@digits) {
+               printf("%01x", $digit);
+       }
+}
+
+
+
+my %lha_signatures = (
+       '-com-' => 1,   
+       '-lhd-' => 1,
+       '-lh0-' => 1,
+       '-lh1-' => 1,
+       '-lh2-' => 1,
+       '-lh3-' => 1,
+       '-lh4-' => 1,
+       '-lh5-' => 1,
+       '-lzs-' => 1,
+       '-lz4-' => 1,
+       '-lz5-' => 1,
+       '-afx-' => 1,
+       '-lzf-' => 1,
+);
+
+my %lha_os = (
+       'M' => 'MS-DOS',
+       '2' => 'OS/2',
+       '9' => 'OS9',
+       'K' => 'OS/68K',
+       '3' => 'OS/386',
+       'H' => 'HUMAN',
+       'U' => 'UNIX',
+       'C' => 'CP/M',
+       'F' => 'FLEX',
+       'm' => 'Mac',
+       'R' => 'Runser',
+       'T' => 'TownOS',
+       'X' => 'XOSK',
+       'A' => 'Amiga',
+       'a' => 'atari',
+       ' ' => 'Award ROM',
+);
+
+
+my @lha_level_1_header = (
+       [ 'byte',         'header_size' ],    # 1
+       [ 'byte',         'header_sum', ],    # 2
+       [ 'fixed-string', 'method_id', 5 ],   # 7
+       [ 'word',         'skip_size', ],     # 11
+       [ 'word',         'original_size' ],  # 15
+       [ 'half',         'dos_time' ],       # 17
+       [ 'half',         'dos_date' ],       # 19
+       [ 'byte',         'fixed'   ],        # 20
+       [ 'byte',         'level'   ],        # 21
+       [ 'pstring',      'filename' ],       # 22
+       [ 'half',         'crc' ],
+       [ 'fixed-string', 'os_id', 1 ],
+       [ 'half',         'ext_size' ],           
+);
+
+# General lha_header
+my @lha_header = (
+       [ 'byte',         'header_size' ],
+       [ 'byte',         'header_sum', ],
+       [ 'fixed-string', 'method_id', 5 ],
+       [ 'word',         'skip_size', ],
+       [ 'word',         'original_size' ],
+       [ 'half',         'dos_time' ],
+       [ 'half',         'dos_date' ],
+       [ 'half',         'rom_addr' ],
+       [ 'half',         'rom_flags' ],
+       [ 'byte',         'fixed'   ],
+       [ 'byte',         'level'   ],
+       [ 'pstring',      'filename' ],
+       [ 'half',         'crc' ],
+       [ 'lha_os',       'os_id', 1 ],
+       [ 'half',         'ext_size' ],
+       [ 'byte',         'zero' ],
+       [ 'byte',         'total_checksum' ],
+       [ 'half',         'total_size' ],
+);
+
+sub print_struct
+{
+       my ($layout, $self) = @_;
+       my $entry;
+       my $width = 0;
+       foreach $entry(@$layout) {
+               my ($type, $name) = @$entry;
+               if (length($name) > $width) {
+                       $width = length($name);
+               }
+       }
+       foreach $entry (@$layout) {
+               my ($type, $name) = @$entry;
+               printf("%*s = ", $width, $name);
+               my $value = $self->{$name};
+               if (!defined($value)) {
+                       print "undefined";
+               }
+               elsif ($type eq "lha_os") {
+                       print "$lha_os{$value}";
+               }
+               elsif ($type =~ m/string/) {
+                       print "$value";
+               } 
+               else {
+                       my $len = type_size($entry);
+                       print "0x";
+                       print_big_hex($len *2, $value);
+               }
+               print "\n";
+       }
+}
+
+sub checksum
+{
+       my ($buf_ref, $offset, $length) = @_;
+       my ($i, $sum);
+       $sum = 0;
+       for($i = 0; $i < $length; $i++) {
+               my $byte = unpack('C', substr($$buf_ref, $offset + $i, 1));
+               $sum = ($sum + $byte) %256;
+       }
+       return $sum;
+}
+
+sub decode_lha_header
+{
+       my ($buf_ref, $offset) = @_;
+       my $level = unpack('C',substr(${$buf_ref}, $offset + 20, 1));
+
+       my %self;
+       my ($struct, $bytes);
+       if ($level == 1) {
+               ($struct, $bytes) 
+                       = decode_struct($buf_ref, $offset, \@lha_level_1_header);
+               %self = %$struct;
+               if ($self{fixed} != 0x20) {
+                        die "bad fixed value";
+               }
+               $self{total_size} = $self{header_size} + 2 + $self{skip_size};
+               if ($bytes != $self{header_size} +2) {
+                       die "$bytes != $self{header_size} +2";
+               }
+               my $checksum = checksum($buf_ref, $offset +2, $self{header_size});
+               if ($checksum != $self{header_sum}) {
+                       printf("WARN: Header bytes checksum to %02lx\n", 
+                                    $checksum);
+               }
+               # If we are an award rom...
+               if ($self{os_id} eq ' ') {
+                       @self{qw(zero total_checksum)} = 
+                           unpack('CC', substr($$buf_ref, 
+                               $offset + $self{total_size}, 2));
+                       if ($self{zero} != 0) {
+                               warn "Award ROM without trailing zero";
+                       }
+                       else {
+                               $self{total_size}++;
+                       }
+                       my $checksum = 
+                               checksum($buf_ref, $offset, $self{total_size});
+                       if ($self{total_checksum} != $checksum) {
+                               printf("WARN: Image bytes checksum to %02lx\n", 
+                                       $checksum);
+                       }
+                       else {
+                               $self{total_size}++;
+                       }
+                       $self{rom_addr} = $self{dos_time};
+                       $self{rom_flags} = $self{dos_date};
+                       delete @self{qw(dos_time dos_date)};
+               }
+       }
+       else {
+               die "Unknown header type";
+       }
+       return \%self;
+}
+
+sub main
+{
+       my ($filename, $rom_length) = @_;
+       my $fd = new FileHandle;
+       if (!defined($rom_length)) {
+               my ($dev, $ino, $mode, $nlink, $uid, $gid,$rdev,$size,
+                       $atime, $mtime, $ctime, $blksize, $blocks)
+                       = stat($filename);
+               $rom_length = $size;
+       }
+       $fd->open("<$filename") or die "Cannot ope $filename";
+       my $data;
+       $fd->read($data, $rom_length);
+       $fd->close();
+       
+       my $i;
+       for($i = 0; $i < $rom_length; $i++) {
+               my $sig = substr($data, $i, 5);
+               if (exists($lha_signatures{$sig})) {
+                       my $start = $i -2;
+                       my $header = decode_lha_header(\$data, $start);
+                       
+                       my $length = $header->{total_size};
+                       print "AT:  $start - @{[$start + $length -1]},  $length bytes\n";
+                       print_struct(\@lha_header, $header);
+                       print "\n";
+
+               }
+       }
+}
+
+main(@ARGV);
diff --git a/baremetal/Makefile b/baremetal/Makefile
new file mode 100644 (file)
index 0000000..df4de76
--- /dev/null
@@ -0,0 +1,475 @@
+#
+# Makefile for Etherboot
+#
+# Most of the time you should edit Config
+#
+# Common options:
+#      VERSION=v       - Set the version string
+#
+# NS8390 options:
+#      -DINCLUDE_NE    - Include NE1000/NE2000 support
+#      -DNE_SCAN=list  - Probe for NE base address using list of
+#                        comma separated hex addresses
+#      -DINCLUDE_3C503 - Include 3c503 support
+#        -DT503_SHMEM  - Use 3c503 shared memory mode (off by default)
+#      -DINCLUDE_WD    - Include Western Digital/SMC support
+#      -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
+#      -DCOMPEX_RL2000_FIX
+#
+#      If you have a Compex RL2000 PCI 32-bit (11F6:1401),
+#      and the bootrom hangs in "Probing...[NE*000/PCI]",
+#      try enabling this fix... it worked for me :).
+#      In the first packet write somehow it somehow doesn't
+#      get back the expected data so it is stuck in a loop.
+#      I didn't bother to investigate what or why because it works
+#      when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES.
+#      The code will notify if it does a abort.
+#      SomniOne - somnione@gmx.net
+#
+# 3C509 option:
+#      -DINCLUDE_3C509 - Include 3c509 support
+#
+# 3C90X options:
+#      -DINCLUDE_3C90X - Include 3c90x support
+#      -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it
+#                        had initially just before the loaded code is started.
+#      -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses.
+#      -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM
+#                        interface, setting this option might "fix" it.  Use
+#                        with caution and read the docs in 3c90x.txt!
+#
+#      See the documentation file 3c90x.txt for more details.
+#
+# CS89X0 (optional) options:
+#      -DINCLUDE_CS89X0- Include CS89x0 support
+#      -DCS_SCAN=list  - Probe for CS89x0 base address using list of
+#                        comma separated hex addresses; increasing the
+#                        address by one (0x300 -> 0x301) will force a
+#                        more aggressive probing algorithm. This might
+#                        be neccessary after a soft-reset of the NIC.
+#
+# LANCE options:
+#      -DINCLUDE_NE2100- Include NE2100 support
+#      -DINCLUDE_NI6510- Include NI6510 support
+#
+# SK_G16 options:
+#      -DINCLUDE_SK_G16- Include SK_G16 support
+#
+# I82586 options:
+#      -DINCLUDE_3C507 - Include 3c507 support
+#      -DINCLUDE_NI5210- Include NI5210 support
+#      -DINCLUDE_EXOS205-Include EXOS205 support
+#
+# SMC9000 options:
+#       -DINCLUDE_SMC9000   - Include SMC9000 driver
+#       -DSMC9000_SCAN=list - List of I/O addresses to probe
+#
+# TIARA (Fujitsu Etherstar) options:
+#      -DINCLUDE_TIARA - Include Tiara support
+#
+# NI5010 options:
+#      -DINCLUDE_NI5010 - Include NI5010 support
+#
+# TULIP options:
+#      -DINCLUDE_TULIP - Include Tulip support
+#      -DUSE_INTERNAL_BUFFER - receuve and transmit buffers within program
+#              space, not below 0x10000, in case that region is used
+#
+# RTL8139 options:
+#      -DINCLUDE_RTL8139 - Include RTL8139 support
+#      -DUSE_INTERNAL_BUFFER - 8 kB receive buffer within program space,
+#              not at 0x10000 - 8kB, in case that region is used
+#
+
+include Config
+
+GCC=           gcc
+CPP=           gcc -E
+VERSION=       4.6.12
+CFLAGS16+=     -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR)
+CFLAGS32+=     -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR) $(OLDGAS)
+LCONFIG+=      -DRELOC=$(RELOCADDR)
+
+IDENT16=               'Etherboot/16 $(VERSION) (GPL) $(@F)'
+IDENT32=               'Etherboot/32 $(VERSION) (GPL) $(@F)'
+
+# Find out if we're using binutils 2.9.1 which uses a different syntax in some
+# places (most prominently in the opcode prefix area).
+OLDGAS:=       $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291)
+
+# Check the requested type of build (32, 16 or both families)
+ifeq ($(ETHERBOOT),16)
+BUILD_LIBS=    $(BLIB16)
+BUILD_BINS=    $(BINS16)
+endif
+ifeq ($(ETHERBOOT),32)
+BUILD_LIBS=    $(BLIB32)
+BUILD_BINS=    $(BINS32)
+endif
+ifeq ($(ETHERBOOT),both)
+BUILD_LIBS=    $(BLIB16) $(BLIB32)
+BUILD_BINS=    $(BINS16) $(BINS32)
+endif
+
+3C503FLAGS=    -DINCLUDE_3C503 # -DT503_SHMEM
+# Note that the suffix to MAKEROM_ is the (mixed case) basename of the ROM file
+MAKEROM_3c503= -3
+3C507FLAGS=    -DINCLUDE_3C507
+3C509FLAGS=    -DINCLUDE_3C509
+3C529FLAGS=    -DINCLUDE_3C529
+3C595FLAGS=    -DINCLUDE_3C595
+3C90XFLAGS=    -DINCLUDE_3C90X
+CS89X0FLAGS=   -DINCLUDE_CS89X0
+EEPROFLAGS=    -DINCLUDE_EEPRO
+EEPRO100FLAGS= -DINCLUDE_EEPRO100
+EPIC100FLAGS=  -DINCLUDE_EPIC100
+EXOS205FLAGS=  -DINCLUDE_EXOS205
+LANCEFLAGS=    -DINCLUDE_LANCE         # Lance/PCI!
+NE2100FLAGS=   -DINCLUDE_NE2100
+NEFLAGS=       -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380
+NS8390FLAGS=   -DINCLUDE_NS8390        # NE2000/PCI!
+NI5010FLAGS=   -DINCLUDE_NI5010
+NI5210FLAGS=   -DINCLUDE_NI5210
+NI6510FLAGS=   -DINCLUDE_NI6510
+RTL8139FLAGS=  -DINCLUDE_RTL8139
+SK_G16FLAGS=   -DINCLUDE_SK_G16
+SMC9000FLAGS=   -DINCLUDE_SMC9000
+TIARAFLAGS=    -DINCLUDE_TIARA
+DEPCAFLAGS=    -DINCLUDE_DEPCA # -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000
+TULIPFLAGS=    -DINCLUDE_TULIP
+OTULIPFLAGS=   -DINCLUDE_OTULIP
+VIA_RHINEFLAGS=        -DINCLUDE_VIA_RHINE
+WDFLAGS=       -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000
+W89C840FLAGS=  -DINCLUDE_W89C840
+
+# If you have not made any changes to the *.S files, AS86 need not be set.
+# (most people)
+# If you have made changes to the *.S files and you want to rebuild *loader.bin
+# and {floppy,com}load.bin and you have as86 from the ELKS Dev86 package (not
+# the one that normally comes with Linux) (not most people)
+#AS86=         as86
+# If you have made changes to the *.S files and you want to rebuild *loader.bin
+# and {floppy,com}load.bin and you have nasm (not most people)
+#AS86=         nasm
+
+# if your as has trouble with the data32 directive, uncomment this
+# but note that the premade start*.o will be larger than necessary because it
+# contains some routines which may not be used
+#AS_PSEUDOS=   n
+
+SRCS=  floppyload.S comload.S liloprefix.S loader.S start16.S start32.S serial.S startmpcc.S
+SRCS+= main.c pci.c osloader.c nfs.c misc.c ansiesc.c bootmenu.c config.c
+SRCS+= md5.c floppy.c
+
+# ROM loaders: LZ version (prefix Z), PCI header version (prefix P)
+ifndef AS86
+RLOADER=       rloader.bin.pre
+PRLOADER=      prloader.bin.pre
+RZLOADER=      rzloader.bin.pre
+PRZLOADER=     przloader.bin.pre
+FLOPPYLOAD=    floppyload.bin.pre
+COMLOAD=       comload.bin.pre
+LILOPREFIX=    liloprefix.bin.pre
+else
+RLOADER=       bin/rloader.bin
+PRLOADER=      bin/prloader.bin
+RZLOADER=      bin/rzloader.bin
+PRZLOADER=     bin/przloader.bin
+FLOPPYLOAD=    bin/floppyload.bin
+COMLOAD=       bin/comload.bin
+LILOPREFIX=    bin/liloprefix.bin
+endif
+
+ifeq ($(AS86),as86)
+LCPPFLAGS+=    -DUSE_AS86
+LASFLAGS+=     $(AS86FLAGS) -0
+LASBINARY:=    -b
+endif
+ifeq ($(AS86),nasm)
+LCPPFLAGS+=    -DUSE_NASM
+LASFLAGS+=     $(NASMFLAGS) -fbin
+LASBINARY:=    -o
+endif
+
+ifeq ($(AS_PSEUDOS),n)
+START16=       start16.o.pre
+START32=       start32.o.pre
+else
+START16=       bin16/start16.o
+START32=       bin32/startmpcc.o
+endif
+
+BOBJS16=       bin16/main.o bin16/osloader.o bin16/misc.o bin16/bootmenu.o
+BOBJS16+=      bin16/floppy.o bin16/timer.o
+BOBJS32=       bin32/main.o bin32/osloader.o bin32/nfs.o bin32/misc.o
+BOBJS32+=      bin32/ansiesc.o bin32/bootmenu.o bin32/md5.o bin32/floppy.o
+BOBJS32+=      bin32/serial.o bin32/timer.o
+BLIB16=        bin16/bootlib.a
+BLIB32=        bin32/bootlib.a
+LIBS16=        $(BLIB16) $(LIBC16)
+LIBS32=        $(BLIB32) $(LIBC32) /usr/lib/gcc-lib/i386-redhat-linux/2.96/libgcc.a
+UTIL_LZHUF:= $(shell if [ -d ../contrib/compressor ]; then echo bin/lzhuf; fi)
+UTILS+=        bin/makerom $(UTIL_LZHUF) bin/organon
+STDDEPS16=     $(START16) $(BLIB16) $(UTILS)
+STDDEPS32=     $(START32) $(BLIB32) $(UTILS)
+MAKEDEPS=      Makefile Config Roms
+
+CHECKSIZE=     { read d1; read d1 d2 d3 size d4; [ $$size -gt $(ROMLIMIT) ] &&\
+       { $(RM) $@; echo "ERROR: code size exceeds limit!"; exit 1; }; exit 0; }
+
+# Make sure that the relocation address is acceptable for all ROM sizes.
+# Setting it to 0x98000 leaves about 29kB of space for the Etherboot program.
+# The check is done based running 'size' on the binary, not ROM size, but
+# roughly this means a ROM of 16kB or a partially used ROM of 32kB,
+# remembering to compressed ROM images into account.
+# You may also set RELOCADDR to 0x88000 to avoid using 0x98000
+# because of other drivers (e.g. Disk On Chip). In that case, you may
+# only load 512kB of OS, or load in memory above 1MB.
+# Don't forget to choose an assembler because the loaders have to be rebuilt.
+ifndef RELOCADDR
+RELOCADDR=0x98000
+#RELOCADDR=0xe0000
+endif
+
+# Evaluate ROMLIMIT only once - it is constant during the make run.
+# Note that the 3K safety margin below is for the 1K extended BIOS data area
+# and for the Etherboot runtime stack.  Under normal situations, 2K of stack
+# are rarely needed.  If you experience strange behaviour in functions that use
+# many local variables or that call functions that do, check for stack overrun!
+# Make sure that the normal case needs no perl interpreter - if someone uses a
+# different RELOCADDR, then he has perl installed anyways (the shell cannot
+# deal with hex numbers, as test/eval don't support non-decimal integers).
+ifeq ($(RELOCADDR),0x98000)
+ROMLIMIT=29696
+else
+ROMLIMIT:=$(shell perl -e 'print 0x10000 - 3072 - ($(RELOCADDR) & 0xFFFF), "\n";')
+endif
+
+# Start of targets
+
+all:   $(UTILS) $(BUILD_LIBS) allbins
+
+include Roms
+
+# We need allbins because $(BINS16) and $(BINS32) are not defined until
+# the Makefile fragment "Roms" is read.
+
+allbins:       $(BUILD_BINS)
+
+# Common files
+
+$(BLIB16):     $(BOBJS16)
+       $(AR16) rv $@ $(BOBJS16)
+       $(RANLIB16) $@
+
+$(BLIB32):     $(BOBJS32)
+       $(AR32) rv $@ $(BOBJS32)
+       $(RANLIB32) $@
+
+bin16/main.o:          main.c etherboot.h osdep.h nic.h
+bin32/main.o:          main.c etherboot.h osdep.h nic.h
+
+bin16/osloader.o:      osloader.c etherboot.h osdep.h
+bin32/osloader.o:      osloader.c etherboot.h osdep.h
+
+# NFS currently makes no sense for Etherboot/16
+bin32/nfs.o:           nfs.c etherboot.h osdep.h nic.h
+
+bin16/misc.o:          misc.c etherboot.h osdep.h
+bin32/misc.o:          misc.c etherboot.h osdep.h
+
+# ANSIESC is not supported for Etherboot/16
+bin32/ansiesc.o:       ansiesc.c etherboot.h osdep.h
+
+bin16/bootmenu.o:      bootmenu.c etherboot.h osdep.h
+bin32/bootmenu.o:      bootmenu.c etherboot.h osdep.h
+
+# Password support is not available for Etherboot/16
+bin32/md5.o:           md5.c etherboot.h osdep.h
+
+bin16/floppy.o:                floppy.c etherboot.h osdep.h
+bin32/floppy.o:                floppy.c etherboot.h osdep.h
+
+bin16/timer.o:         timer.c timer.h etherboot.h osdep.h
+bin32/timer.o:         timer.c timer.h etherboot.h osdep.h
+
+bin32/inthw.o:         inthw.c
+
+# PCI support code (common to all PCI drivers)
+
+bin32/pci.o:   pci.c pci.h
+
+# Do not add driver specific dependencies here unless it's something the
+# genrules.pl script *can't* deal with, i.e. if it is not C code.
+
+# Prepended loaders
+
+#ifndef AS86
+#$(RLOADER) $(RZLOADER) $(PRLOADER) $(PRZLOADER):      $(MAKEDEPS)
+#      @if [ $(RELOCADDR) != 0x98000 ]; then echo Non-standard RELOCADDR, must assemble $@; exit 1; fi
+#      $(TOUCH) $@
+#else
+#bin/rloader.s:        loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -o $@ $<
+#
+#bin/rzloader.s:       loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DZLOADER -o $@ $<
+#
+#bin/prloader.s:       loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -o $@ $<
+#
+#bin/przloader.s:      loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -DZLOADER -o $@ $<
+#endif
+
+# Floppy loader
+
+ifdef AS86
+bin/floppyload.s:      floppyload.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# COM loader
+
+ifdef AS86
+bin/comload.s: comload.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# LILO prefix:
+
+ifdef AS86
+bin/liloprefix.s:      liloprefix.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# Utilities
+
+bin/makerom: makerom.c
+       $(GCC) -O2 -o $@ makerom.c
+
+bin/organon: organon.c
+       $(GCC) -o $@ organon.c
+
+bin/lzhuf:     ../contrib/compressor/lzhuf.c
+       $(GCC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -o $@ $<
+
+# Roms file
+
+Roms:  NIC genrules.pl
+       @chmod +x genrules.pl
+       ./genrules.pl NIC > $@
+
+# Pattern Rules
+
+# general rules for compiling/assembling source files
+bin16/%.o:     %.c $(MAKEDEPS)
+       $(CC16) $(CFLAGS16) -o $@ -c $<
+
+bin32/%.o:     %.c $(MAKEDEPS)
+       $(CC32) $(CFLAGS32) -o $@ -c $<
+
+bin16/%.o:     %.S $(MAKEDEPS)
+       $(CC16) $(CFLAGS16) $(ASFLAGS16) -c -o $@ $<
+
+bin32/%.o:     %.S $(MAKEDEPS)
+       $(CPP) $(CFLAGS32) $< | $(AS) $(ASFLAGS32) -o $@
+
+# general rule for .bin (plain binary loader code), may be overridden
+ifdef AS86
+bin/%.bin:     bin/%.s
+       $(AS86) $(LASFLAGS) $(LASBINARY) $@ $<
+endif
+
+# general rule for .huf (compressed binary code), may be overridden
+%.huf: %.img
+       bin/lzhuf e $< $@
+
+# general rules for normal/compressed ROM images, may be overridden
+bin16/%.rom:   bin16/%.img $(RLOADER)
+       cat $(RLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@
+
+bin32/%.rom:   bin32/%.img $(RLOADER)
+       cat $(RLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@
+
+bin16/%.lzrom: bin16/%.huf $(RZLOADER)
+       cat $(RZLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@
+
+bin32/%.lzrom: bin32/%.huf $(RZLOADER)
+       cat $(RZLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@
+
+# rules to write the .rom/.lzrom image onto a blank floppy
+# You must give the directory name, e.g. use bin32/rtl8139.lzfd0 as the target.
+%.fd0: %.rom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > /dev/fd0
+
+%.lzfd0:       %.lzrom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > /dev/fd0
+
+# rules to generate a .com executable
+# You must give the directory name, e.g. use bin32/rtl8139.com as the target.
+%.com: %.lzrom $(COMLOAD)
+       cat $(COMLOAD) $< > $@
+
+# rules to make a floppy image (padding to fill an even number of cylinders).
+# VMware reports floppy image read errors if it cannot read ahead 36 sectors,
+# probably because the floppyload.S code reads up to that number of sectors in
+# a single request.  Not that 18k matters much these days...
+# You must give the directory name, e.g. use bin32/rtl8139.fdimg as the target.
+%.fdimg:       %.rom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > $@.x
+       dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null
+       $(RM) $@.x
+
+%.lzfdimg:     %.lzrom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > $@.x
+       dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null
+       $(RM) $@.x
+
+# rules to make a LILO-bootable image
+%.lilo:                %.rom $(LILOPREFIX)
+       cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@
+
+%.lzlilo:      %.lzrom $(LILOPREFIX)
+       cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@
+
+# Housekeeping
+
+# To make sure that this actually builds a start32.o.pre with all options set,
+# you have to make sure that -DFLOPPY -DANSIESC -DCONSOLE_DUAL are in CFLAGS32.
+precompiled:   bin/rloader.bin bin/rzloader.bin bin/prloader.bin bin/przloader.bin bin/floppyload.bin bin/comload.bin bin16/start16.o bin32/start32.o bin/liloprefix.bin
+       cp -p bin/rloader.bin rloader.bin.pre
+       cp -p bin/rzloader.bin rzloader.bin.pre
+       cp -p bin/prloader.bin prloader.bin.pre
+       cp -p bin/przloader.bin przloader.bin.pre
+       cp -p bin/floppyload.bin floppyload.bin.pre
+       cp -p bin/comload.bin comload.bin.pre
+       cp -p bin16/start16.o start16.o.pre
+       cp -p bin32/start32.o start32.o.pre
+       cp -p bin/liloprefix.bin liloprefix.bin.pre
+
+clean:
+       $(RM) $(UTILS) bin/*.s bin/*.bin
+       $(RM) $(BLIB16) $(BLIB32)
+       $(RM) bin16/*.o bin32/*.o bin16/*.tmp bin32/*.tmp
+       $(RM) bin16/*.img bin32/*.img bin16/*.huf bin32/*.huf
+       $(RM) bin16/*.rom bin32/*.rom bin16/*.lzrom bin32/*.lzrom
+       $(RM) bin16/*.com bin32/*.com
+       $(RM) bin16/*.fdimg bin32/*.fdimg bin16/*.lzfdimg bin32/*.lzfdimg
+       $(RM) bin16/*.lilo bin32/*.lilo bin16/*.lzlilo bin32/*.lzlilo
+       $(RM) bin32/*.hex
+       $(RM) bin32/*.asm
+       $(RM) bin32/*.map
+
+tarball:
+       (echo -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION
+       (cd ..; tar cf /tmp/mpccboot-$(VERSION).tar --exclude CVS mpccboot)
+       bzip2 -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.bz2
+       gzip -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.gz
+
+version:
+       @echo $(VERSION)
diff --git a/baremetal/main.c b/baremetal/main.c
new file mode 100644 (file)
index 0000000..7b0de44
--- /dev/null
@@ -0,0 +1,1119 @@
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: Dec/93
+
+Literature dealing with the network protocols:
+       ARP - RFC826
+       RARP - RFC903
+       UDP - RFC768
+       BOOTP - RFC951, RFC2132 (vendor extensions)
+       DHCP - RFC2131, RFC2132 (options)
+       TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
+       RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
+       NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
+
+**************************************************************************/
+
+/* #define MDEBUG */
+
+#include "etherboot.h"
+#include "nic.h"
+
+int    jmp_bootmenu[10];
+
+struct arptable_t arptable[MAX_ARP];
+
+const char *kernel;
+char kernel_buf[128];
+struct rom_info rom;
+
+#ifdef IMAGE_MENU
+static char *imagelist[RFC1533_VENDOR_NUMOFIMG];
+static int useimagemenu;
+int    menutmo,menudefault;
+unsigned char *defparams = NULL;
+int defparams_max = 0;
+#endif
+#ifdef MOTD
+char   *motd[RFC1533_VENDOR_NUMOFMOTD];
+#endif
+#ifdef IMAGE_FREEBSD
+int freebsd_howto = 0;
+#endif
+int     vendorext_isvalid;
+char   config_buffer[TFTP_MAX_PACKET+1];       /* +1 for null byte */
+unsigned long  netmask;
+char *hostname = "";
+int hostnamelen = 0;
+#if    defined(ETHERBOOT16) || defined(INTERNAL_BOOTP_DATA)
+struct bootpd_t bootp_data;
+#endif
+unsigned long xid;
+unsigned char   *end_of_rfc1533 = NULL;
+#ifndef        NO_DHCP_SUPPORT
+int dhcp_reply;
+in_addr dhcp_server = { 0L };
+in_addr dhcp_addr = { 0L };
+#endif /* NO_DHCP_SUPPORT */
+
+unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */
+#ifdef NO_DHCP_SUPPORT
+char    rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END };
+#else
+char    rfc1533_cookie[] = { RFC1533_COOKIE};
+char    rfc1533_end[]={RFC1533_END };
+static const char dhcpdiscover[]={
+               RFC2132_MSG_TYPE,1,DHCPDISCOVER,
+               RFC2132_MAX_SIZE,2,     /* request as much as we can */
+               sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256,
+               RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY,
+               RFC1533_HOSTNAME
+       };
+static const char dhcprequest []={
+               RFC2132_MSG_TYPE,1,DHCPREQUEST,
+               RFC2132_SRV_ID,4,0,0,0,0,
+               RFC2132_REQ_ADDR,4,0,0,0,0,
+               RFC2132_MAX_SIZE,2,     /* request as much as we can */
+               sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256,
+               /* request parameters */
+               RFC2132_PARAM_LIST,
+#ifdef IMAGE_FREEBSD
+               /* 4 standard + 6 vendortags + 8 motd + 16 menu items */
+               4 + 6 + 8 + 16,
+#else
+               /* 4 standard + 5 vendortags + 8 motd + 16 menu items */
+               4 + 5 + 8 + 16,
+#endif
+               /* Standard parameters */
+               RFC1533_NETMASK, RFC1533_GATEWAY,
+               RFC1533_HOSTNAME,
+               RFC1533_ROOTPATH,       /* only passed to the booted image */
+               /* Etherboot vendortags */
+               RFC1533_VENDOR_MAGIC,
+                RFC1533_VENDOR_ADDPARM,
+                RFC1533_VENDOR_ETHDEV,
+#ifdef IMAGE_FREEBSD
+               RFC1533_VENDOR_HOWTO,
+#endif
+               RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
+               /* 8 MOTD entries */
+               RFC1533_VENDOR_MOTD,
+               RFC1533_VENDOR_MOTD+1,
+               RFC1533_VENDOR_MOTD+2,
+               RFC1533_VENDOR_MOTD+3,
+               RFC1533_VENDOR_MOTD+4,
+               RFC1533_VENDOR_MOTD+5,
+               RFC1533_VENDOR_MOTD+6,
+               RFC1533_VENDOR_MOTD+7,
+               /* 16 image entries */
+               RFC1533_VENDOR_IMG,
+               RFC1533_VENDOR_IMG+1,
+               RFC1533_VENDOR_IMG+2,
+               RFC1533_VENDOR_IMG+3,
+               RFC1533_VENDOR_IMG+4,
+               RFC1533_VENDOR_IMG+5,
+               RFC1533_VENDOR_IMG+6,
+               RFC1533_VENDOR_IMG+7,
+               RFC1533_VENDOR_IMG+8,
+               RFC1533_VENDOR_IMG+9,
+               RFC1533_VENDOR_IMG+10,
+               RFC1533_VENDOR_IMG+11,
+               RFC1533_VENDOR_IMG+12,
+               RFC1533_VENDOR_IMG+13,
+               RFC1533_VENDOR_IMG+14,
+               RFC1533_VENDOR_IMG+15,
+       };
+
+#endif /* NO_DHCP_SUPPORT */
+static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/**************************************************************************
+MAIN - Kick off routine
+**************************************************************************/
+int main(void)
+{
+       char *p;
+       static int card_retries = 0;
+       int i;
+
+       for (p=_edata; p<_end; p++)
+               *p = 0; /* Zero BSS */
+
+#ifdef CONSOLE_SERIAL
+       (void)serial_init();
+#endif
+
+#ifdef DELIMITERLINES
+       for (i=0; i<80; i++) putchar('=');
+#endif
+
+#ifdef ETHERBOOT32
+       rom = *(struct rom_info *)ROM_INFO_LOCATION;
+       printf("ROM segment %#x length %#x reloc %#x\n", rom.rom_segment,
+               rom.rom_length << 1, ((unsigned long)_start) >> 4);
+#endif
+#ifdef ETHERBOOT16
+       fmemcpy(&rom, (Address)ROM_INFO_LOCATION, sizeof(rom));
+       printf("ROM segment %#x length %#x\n", rom.rom_segment,
+               rom.rom_length << 1);
+#endif
+#ifdef ASK_BOOT
+       while (1) {
+               int c;
+               unsigned long time;
+               printf(ASK_PROMPT);
+#if    ASK_BOOT > 0
+               for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); )
+                       if (currticks() > time) {
+                               c = ANS_DEFAULT;
+                               goto done;
+                       }
+#endif
+               c = getchar();
+               if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
+               if (c == '\n') c = ANS_DEFAULT;
+done:
+               if ((c >= ' ') && (c <= '~')) putchar(c);
+               putchar('\n');
+               if (c == ANS_LOCAL)
+                       exit(0);
+               if (c == ANS_NETWORK)
+                       break;
+       }
+#endif
+#if    (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY)
+       disk_init();
+       printf("Trying floppy");
+       for (i = TRY_FLOPPY_FIRST; i-- > 0; ) {
+               putchar('.');
+               if (disk_read(0, 0, 0, 0, ((char *) FLOPPY_BOOT_LOCATION)) != 0x8000) {
+                       printf("using floppy\n");
+                       exit(0);
+               }
+       }
+       printf("no floppy\n");
+#endif /* TRY_FLOPPY_FIRST && FLOPPY */
+       print_config();
+       gateA20_set();
+#ifdef EMERGENCYDISKBOOT
+       if (!eth_probe()) {
+               printf("No adapter found\n");
+               exit(0);
+       }
+#else
+       while (!eth_probe()) {
+               printf("No adapter found");
+               if (!setjmp(jmp_bootmenu))
+                       rfc951_sleep(++card_retries);
+       }
+#endif
+       kernel = DEFAULT_BOOTFILE;
+       while (1) {
+               if ((i = setjmp(jmp_bootmenu)) != 0) {
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+                       ansi_reset();
+#endif
+                       bootmenu(--i);
+               } else {
+                       load();
+               }
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+               ansi_reset();
+#endif
+       }
+}
+
+/**************************************************************************
+LOADKERNEL - Try to load kernel image
+**************************************************************************/
+#ifndef        FLOPPY
+#define loadkernel(s) download((s),downloadkernel)
+#else
+static int loadkernel(const char *fname)
+{
+       if (!memcmp(fname,"/dev/",5) && fname[6] == 'd') {
+               int dev, part = 0;
+               if (fname[5] == 'f') {
+                       if ((dev = fname[7] - '0') < 0 || dev > 3)
+                               goto nodisk; }
+               else if (fname[5] == 'h' || fname[5] == 's') {
+                       if ((dev = 0x80 + fname[7] - 'a') < 0x80 || dev > 0x83)
+                               goto nodisk;
+                       if (fname[8]) {
+                               part = fname[8] - '0';
+                               if (fname[9])
+                                       part = 10*part + fname[9] - '0'; }
+                       /* bootdisk cannot cope with more than eight partitions */
+                       if (part < 0 || part > 8)
+                               goto nodisk; }
+               else
+                       goto nodisk;
+               return(bootdisk(dev,part)); }
+nodisk:
+       return download(fname, downloadkernel);
+}
+#endif
+
+/**************************************************************************
+LOAD - Try to get booted
+**************************************************************************/
+void load()
+{
+       static int bootp_completed = 0;
+
+       /* Find a server to get BOOTP reply from */
+       if (!bootp_completed ||
+           !arptable[ARP_CLIENT].ipaddr.s_addr || !arptable[ARP_SERVER].ipaddr.s_addr) {
+retry:
+               bootp_completed = 0;
+#ifdef RARP_NOT_BOOTP
+               printf("Searching for server (RARP)...\n");
+#else
+#ifndef        NO_DHCP_SUPPORT
+               printf("Searching for server (DHCP)...\n");
+#else
+               printf("Searching for server (BOOTP)...\n");
+#endif
+#endif
+
+#ifdef RARP_NOT_BOOTP
+               if (!rarp()) {
+#else
+               if (!bootp()) {
+#endif
+                       printf("No Server found\n");
+#ifdef EMERGENCYDISKBOOT
+                       exit(0);
+#else
+                       goto retry;
+#endif
+               }
+               bootp_completed++;
+       }
+       printf("Me: %I, Server: %I",
+               arptable[ARP_CLIENT].ipaddr.s_addr,
+               arptable[ARP_SERVER].ipaddr.s_addr);
+       if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
+               printf(", Relay: %I",
+                       BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
+       if (arptable[ARP_GATEWAY].ipaddr.s_addr)
+               printf(", Gateway %I", arptable[ARP_GATEWAY].ipaddr.s_addr);
+       putchar('\n');
+
+#ifdef MDEBUG
+       printf("\n=>>"); getchar();
+#endif
+
+#ifdef MOTD
+       if (vendorext_isvalid)
+               show_motd();
+#endif
+       /* Now use TFTP to load file */
+#ifdef IMAGE_MENU
+       if (vendorext_isvalid && useimagemenu) {
+               selectImage(imagelist);
+               bootp_completed = 0;
+       }
+#endif
+#ifdef DOWNLOAD_PROTO_NFS
+       rpc_init();
+#endif
+       for (;;) {
+               printf("Loading %s ",kernel);
+               while (!loadkernel(kernel)) {
+                       printf("Unable to load file.\n");
+                       sleep(2);       /* lay off server for a while */
+               }
+       }
+}
+
+/**************************************************************************
+DEFAULT_NETMASK - Return default netmask for IP address
+**************************************************************************/
+static inline unsigned long default_netmask(void)
+{
+       int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
+       if (net <= 127)
+               return(htonl(0xff000000));
+       else if (net < 192)
+               return(htonl(0xffff0000));
+       else
+               return(htonl(0xffffff00));
+}
+
+/**************************************************************************
+UDP_TRANSMIT - Send a UDP datagram
+**************************************************************************/
+int udp_transmit(unsigned long destip, unsigned int srcsock,
+       unsigned int destsock, int len, const void *buf)
+{
+       struct iphdr *ip;
+       struct udphdr *udp;
+       struct arprequest arpreq;
+       int arpentry, i;
+       int retry;
+
+       ip = (struct iphdr *)buf;
+       udp = (struct udphdr *)((long)buf + sizeof(struct iphdr));
+       ip->verhdrlen = 0x45;
+       ip->service = 0;
+       ip->len = htons(len);
+       ip->ident = 0;
+       ip->frags = 0;
+       ip->ttl = 60;
+       ip->protocol = IP_UDP;
+       ip->chksum = 0;
+       ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
+       ip->dest.s_addr = destip;
+       ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr));
+       udp->src = htons(srcsock);
+       udp->dest = htons(destsock);
+       udp->len = htons(len - sizeof(struct iphdr));
+       udp->chksum = 0;
+       if (destip == IP_BROADCAST) {
+               eth_transmit(broadcast, IP, len, buf);
+       } else {
+               if (((destip & netmask) !=
+                       (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
+                       arptable[ARP_GATEWAY].ipaddr.s_addr)
+                               destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
+               for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
+                       if (arptable[arpentry].ipaddr.s_addr == destip) break;
+               if (arpentry == MAX_ARP) {
+                       printf("%I is not in my arp table!\n", destip);
+                       return(0);
+               }
+               for (i = 0; i<ETHER_ADDR_SIZE; i++)
+                       if (arptable[arpentry].node[i]) break;
+               if (i == ETHER_ADDR_SIZE) {     /* Need to do arp request */
+                       arpreq.hwtype = htons(1);
+                       arpreq.protocol = htons(IP);
+                       arpreq.hwlen = ETHER_ADDR_SIZE;
+                       arpreq.protolen = 4;
+                       arpreq.opcode = htons(ARP_REQUEST);
+                       memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                       memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                       memset(arpreq.thwaddr, 0, ETHER_ADDR_SIZE);
+                       memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
+                       for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
+                               eth_transmit(broadcast, ARP, sizeof(arpreq),
+                                       &arpreq);
+                               if (await_reply(AWAIT_ARP, arpentry,
+                                       arpreq.tipaddr, TIMEOUT)) goto xmit;
+                               rfc951_sleep(retry);
+                               /* We have slept for a while - the packet may
+                                * have arrived by now.  If not, we have at
+                                * least some room in the Rx buffer for the
+                                * next reply.  */
+                               if (await_reply(AWAIT_ARP, arpentry,
+                                       arpreq.tipaddr, 0)) goto xmit;
+                       }
+                       return(0);
+               }
+xmit:
+               eth_transmit(arptable[arpentry].node, IP, len, buf);
+       }
+       return(1);
+}
+
+/**************************************************************************
+DOWNLOADKERNEL - Try to load file
+**************************************************************************/
+int downloadkernel(data, block, len, eof)
+       unsigned char   *data;
+       int             block, len, eof;
+{
+#ifdef SIZEINDICATOR
+       static int rlen = 0;
+
+       if (!(block % 4) || eof) {
+               int size;
+               size = ((block-1) * rlen + len) / 1024;
+
+               putchar('\b');
+               putchar('\b');
+               putchar('\b');
+               putchar('\b');
+
+               putchar('0' + (size/1000)%10);
+               putchar('0' + (size/100)%10);
+               putchar('0' + (size/10)%10);
+               putchar('0' + (size/1)%10);
+       }
+#endif
+       if (block == 1)
+       {
+#ifdef SIZEINDICATOR
+               rlen=len;
+#endif
+               if (!eof && (
+#ifdef TAGGED_IMAGE
+                   *((unsigned long *)data) == 0x1B031336L ||
+#endif
+#ifdef ELF_IMAGE
+                   *((unsigned long *)data) == 0x464C457FL ||
+#endif
+#ifdef AOUT_IMAGE
+                   *((unsigned short *)data) == 0x010BL ||
+#endif
+                   ((unsigned short *)data)[255] == 0xAA55))
+               {
+                       ;
+               }
+               else if (eof)
+               {
+                       memcpy(config_buffer, data, len);
+                       config_buffer[len] = 0;
+                       return (1); /* done */
+               }
+               else
+               {
+                       printf("error: not a tagged image\n");
+                       return(0); /* error */
+               }
+       }
+       if (len != 0) {
+               if (!os_download(block, data, len))
+                       return(0); /* error */
+       }
+       if (eof) {
+               os_download(block+1, data, 0); /* does not return */
+               return(0); /* error */
+       }
+       return(-1); /* there is more data */
+}
+
+#ifdef DOWNLOAD_PROTO_TFTP
+/**************************************************************************
+TFTP - Download extended BOOTP data, or kernel image
+**************************************************************************/
+int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int))
+{
+       int             retry = 0;
+       static unsigned short iport = 2000;
+       unsigned short  oport;
+       unsigned short  len, block = 0, prevblock = 0;
+       int             bcounter = 0;
+       struct tftp_t  *tr;
+       struct tftp_t   tp;
+       int             rc;
+       int             packetsize = TFTP_DEFAULTSIZE_PACKET;
+
+       /* Clear out the Rx queue first.  It contains nothing of interest,
+        * except possibly ARP requests from the DHCP/TFTP server.  We use
+        * polling throughout Etherboot, so some time may have passed since we
+        * last polled the receive queue, which may now be filled with
+        * broadcast packets.  This will cause the reply to the packets we are
+        * about to send to be lost immediately.  Not very clever.  */
+       await_reply(AWAIT_QDRAIN, 0, NULL, 0);
+
+       tp.opcode = htons(TFTP_RRQ);
+       len = (sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
+                      name, 0, 0, 0, TFTP_MAX_PACKET) - ((char *)&tp)) + 1;
+       if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
+               TFTP_PORT, len, &tp))
+               return (0);
+       for (;;)
+       {
+#ifdef CONGESTED
+               if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
+#else
+               if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
+#endif
+               {
+                       if (!block && retry++ < MAX_TFTP_RETRIES)
+                       {       /* maybe initial request was lost */
+                               rfc951_sleep(retry);
+                               if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                       ++iport, TFTP_PORT, len, &tp))
+                                       return (0);
+                               continue;
+                       }
+#ifdef CONGESTED
+                       if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
+                       {       /* we resend our last ack */
+#ifdef MDEBUG
+                               printf("<REXMT>\n");
+#endif
+                               udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                       iport, oport,
+                                       TFTP_MIN_PACKET, &tp);
+                               continue;
+                       }
+#endif
+                       break;  /* timeout */
+               }
+               tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE];
+               if (tr->opcode == ntohs(TFTP_ERROR))
+               {
+                       printf("TFTP error %d (%s)\n",
+                              ntohs(tr->u.err.errcode),
+                              tr->u.err.errmsg);
+                       break;
+               }
+
+               if (tr->opcode == ntohs(TFTP_OACK)) {
+                       char *p = tr->u.oack.data, *e;
+
+                       if (prevblock)          /* shouldn't happen */
+                               continue;       /* ignore it */
+                       len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
+                       if (len > TFTP_MAX_PACKET)
+                               goto noak;
+                       e = p + len;
+                       while (*p != '\000' && p < e) {
+                               if (!strcasecmp("blksize", p)) {
+                                       p += 8;
+                                       if ((packetsize = getdec(&p)) <
+                                           TFTP_DEFAULTSIZE_PACKET)
+                                               goto noak;
+                                       while (p < e && *p) p++;
+                                       if (p < e)
+                                               p++;
+                               }
+                               else {
+                               noak:
+                                       tp.opcode = htons(TFTP_ERROR);
+                                       tp.u.err.errcode = 8;
+                                       len = (sprintf((char *)tp.u.err.errmsg,
+                                                      "RFC1782 error")
+                                              - ((char *)&tp)) + 1;
+                                       udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                                    iport, ntohs(tr->udp.src),
+                                                    len, &tp);
+                                       return (0);
+                               }
+                       }
+                       if (p > e)
+                               goto noak;
+                       block = tp.u.ack.block = 0; /* this ensures, that */
+                                               /* the packet does not get */
+                                               /* processed as data! */
+               }
+               else if (tr->opcode == ntohs(TFTP_DATA)) {
+                       len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
+                       if (len > packetsize)   /* shouldn't happen */
+                               continue;       /* ignore it */
+                       block = ntohs(tp.u.ack.block = tr->u.data.block); }
+               else /* neither TFTP_OACK nor TFTP_DATA */
+                       break;
+
+               if ((block || bcounter) && (block != prevblock+1)) {
+                       /* Block order should be continuous */
+                       tp.u.ack.block = htons(block = prevblock);
+               }
+               tp.opcode = htons(TFTP_ACK);
+               oport = ntohs(tr->udp.src);
+               udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
+                       oport, TFTP_MIN_PACKET, &tp);   /* ack */
+               if ((unsigned short)(block-prevblock) != 1) {
+                       /* Retransmission or OACK, don't process via callback
+                        * and don't change the value of prevblock.  */
+                       continue;
+               }
+               prevblock = block;
+               retry = 0;      /* It's the right place to zero the timer? */
+               if ((rc = fnc(tr->u.data.download,
+                             ++bcounter, len, len < packetsize)) >= 0)
+                       return(rc);
+               if (len < packetsize)           /* End of data */
+                       return (1);
+       }
+       return (0);
+}
+#endif /* DOWNLOAD_PROTO_TFTP */
+
+#ifdef RARP_NOT_BOOTP
+/**************************************************************************
+RARP - Get my IP address and load information
+**************************************************************************/
+int rarp()
+{
+       int retry;
+
+       /* arp and rarp requests share the same packet structure. */
+       struct arprequest rarpreq;
+
+       memset(&rarpreq, 0, sizeof(rarpreq));
+
+       rarpreq.hwtype = htons(1);
+       rarpreq.protocol = htons(IP);
+       rarpreq.hwlen = ETHER_ADDR_SIZE;
+       rarpreq.protolen = 4;
+       rarpreq.opcode = htons(RARP_REQUEST);
+       memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+       /* sipaddr is already zeroed out */
+       memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+       /* tipaddr is already zeroed out */
+
+       for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) {
+               eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
+
+               if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT))
+                       break;
+       }
+
+       if (retry < MAX_ARP_RETRIES) {
+               sprintf(kernel = kernel_buf, "/tftpboot/kernel.%I", arptable[ARP_CLIENT].ipaddr);
+
+               return (1);
+       }
+       return (0);
+}
+
+#else
+
+/**************************************************************************
+BOOTP - Get my IP address and load information
+**************************************************************************/
+int bootp()
+{
+       int retry;
+#ifndef        NO_DHCP_SUPPORT
+       int retry1;
+#endif /* NO_DHCP_SUPPORT */
+       struct bootp_t bp;
+       unsigned long  starttime;
+#ifdef T509HACK
+       int flag;
+
+       flag = 1;
+#endif
+       memset(&bp, 0, sizeof(struct bootp_t));
+       bp.bp_op = BOOTP_REQUEST;
+       bp.bp_htype = 1;
+       bp.bp_hlen = ETHER_ADDR_SIZE;
+       bp.bp_xid = xid = starttime = currticks();
+       memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+#ifdef NO_DHCP_SUPPORT
+       memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */
+#else
+       memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
+       memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover);
+       memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end);
+#endif /* NO_DHCP_SUPPORT */
+
+       for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
+
+               /* Clear out the Rx queue first.  It contains nothing of
+                * interest, except possibly ARP requests from the DHCP/TFTP
+                * server.  We use polling throughout Etherboot, so some time
+                * may have passed since we last polled the receive queue,
+                * which may now be filled with broadcast packets.  This will
+                * cause the reply to the packets we are about to send to be
+                * lost immediately.  Not very clever.  */
+               await_reply(AWAIT_QDRAIN, 0, NULL, 0);
+
+               udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
+                       sizeof(struct bootp_t), &bp);
+#ifdef T509HACK
+               if (flag) {
+                       flag--;
+               } else {
+                       if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+                               return(1);
+                       rfc951_sleep(++retry);
+
+               }
+#else
+#ifdef NO_DHCP_SUPPORT
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+#else
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){
+                       if (dhcp_reply==DHCPOFFER){
+               dhcp_reply=0;
+               memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
+               memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
+               memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
+               memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
+               memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
+                       for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
+                       udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
+                               sizeof(struct bootp_t), &bp);
+                               dhcp_reply=0;
+                               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+                                       if (dhcp_reply==DHCPACK)
+                                               return(1);
+                                       rfc951_sleep(++retry1);
+                               }
+                       } else
+#endif /* NO_DHCP_SUPPORT */
+                               return(1);
+#ifndef        NO_DHCP_SUPPORT
+               }
+               rfc951_sleep(++retry);
+
+#endif /* NO_DHCP_SUPPORT */
+#endif
+               bp.bp_secs = htons((currticks()-starttime)/20);
+       }
+       return(0);
+}
+#endif /* RARP_NOT_BOOTP */
+
+/**************************************************************************
+AWAIT_REPLY - Wait until we get a response for our request
+**************************************************************************/
+int await_reply(int type, int ival, void *ptr, int timeout)
+{
+       unsigned long time;
+       struct  iphdr *ip;
+       struct  udphdr *udp;
+       struct  arprequest *arpreply;
+       struct  bootp_t *bootpreply;
+       struct  rpc_t *rpc;
+       unsigned short ptype;
+
+       unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
+                               sizeof(struct udphdr);
+       time = timeout + currticks();
+       /* The timeout check is done below.  The timeout is only checked if
+        * there is no packet in the Rx queue.  This assumes that eth_poll()
+        * needs a negligible amount of time.  */
+       for (;;) {
+               if (eth_poll()) {       /* We have something! */
+                                       /* Check for ARP - No IP hdr */
+                       if (nic.packetlen >= ETHER_HDR_SIZE) {
+                               ptype = ((unsigned short) nic.packet[12]) << 8
+                                       | ((unsigned short) nic.packet[13]);
+                       } else continue; /* what else could we do with it? */
+                       if ((nic.packetlen >= ETHER_HDR_SIZE +
+                               sizeof(struct arprequest)) &&
+                          (ptype == ARP) ) {
+                               unsigned long tmp;
+
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
+                                  !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
+                                  (type == AWAIT_ARP)) {
+                                       memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       return(1);
+                               }
+                               memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                               if ((arpreply->opcode == ntohs(ARP_REQUEST)) &&
+                                       (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
+                                       arpreply->opcode = htons(ARP_REPLY);
+                                       memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                                       eth_transmit(arpreply->thwaddr, ARP,
+                                               sizeof(struct  arprequest),
+                                               arpreply);
+#ifdef MDEBUG
+                                       memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                                       printf("Sent ARP reply to: %I\n",tmp);
+#endif MDEBUG
+                               }
+                               continue;
+                       }
+
+                       if (type == AWAIT_QDRAIN) {
+                               continue;
+                       }
+
+                                       /* Check for RARP - No IP hdr */
+                       if ((type == AWAIT_RARP) &&
+                          (nic.packetlen >= ETHER_HDR_SIZE +
+                               sizeof(struct arprequest)) &&
+                          (ptype == RARP)) {
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(RARP_REPLY)) &&
+                                  !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
+                                       memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
+                                       return(1);
+                               }
+                               continue;
+                       }
+
+                                       /* Anything else has IP header */
+                       if ((nic.packetlen < protohdrlen) ||
+                          (ptype != IP) ) continue;
+                       ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((ip->verhdrlen != 0x45) ||
+                               ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
+                               (ip->protocol != IP_UDP)) continue;
+                       udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE +
+                               sizeof(struct iphdr)];
+
+                                       /* BOOTP ? */
+                       bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_BOOTP) &&
+                          (nic.packetlen >= (ETHER_HDR_SIZE +
+#ifdef NO_DHCP_SUPPORT
+                            sizeof(struct bootp_t))) &&
+#else
+                            sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
+#endif /* NO_DHCP_SUPPORT */
+                          (ntohs(udp->dest) == BOOTP_CLIENT) &&
+                          (bootpreply->bp_op == BOOTP_REPLY) &&
+                          (bootpreply->bp_xid == xid)) {
+                               arptable[ARP_CLIENT].ipaddr.s_addr =
+                                       bootpreply->bp_yiaddr.s_addr;
+#ifndef        NO_DHCP_SUPPORT
+                               dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
+#endif /* NO_DHCP_SUPPORT */
+                               netmask = default_netmask();
+                               arptable[ARP_SERVER].ipaddr.s_addr =
+                                       bootpreply->bp_siaddr.s_addr;
+                               memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               arptable[ARP_GATEWAY].ipaddr.s_addr =
+                                       bootpreply->bp_giaddr.s_addr;
+                               memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               if (bootpreply->bp_file[0]) {
+                                       memcpy(kernel_buf, bootpreply->bp_file, 128);
+                                       kernel = kernel_buf;
+                               }
+                               memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
+                               decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
+#ifdef NO_DHCP_SUPPORT
+                                              0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1);
+#else
+                                              0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1);
+#endif /* NO_DHCP_SUPPORT */
+                               return(1);
+                       }
+
+#ifdef DOWNLOAD_PROTO_TFTP
+                                       /* TFTP ? */
+                       if ((type == AWAIT_TFTP) &&
+                               (ntohs(udp->dest) == ival)) return(1);
+#endif /* DOWNLOAD_PROTO_TFTP */
+
+#ifdef DOWNLOAD_PROTO_NFS
+                                       /* RPC ? */
+                       rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_RPC) &&
+                           (ntohs(udp->dest) == ival) &&
+                           (*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) &&
+                           (ntohl(rpc->u.reply.type) == MSG_REPLY)) {
+                               return (1);
+                       }
+#endif /* DOWNLOAD_PROTO_NFS */
+
+               } else {
+                       /* Check for abort key only if the Rx queue is empty -
+                        * as long as we have something to process, don't
+                        * assume that something failed.  It is unlikely that
+                        * we have no processing time left between packets.  */
+                       if (iskey() && (getchar() == ESC))
+#ifdef EMERGENCYDISKBOOT
+                               exit(0);
+#else
+                               longjmp(jmp_bootmenu,1);
+#endif
+                       /* Do the timeout after at least a full queue walk.  */
+                       if ((timeout == 0) || (currticks() > time)) {
+                               break;
+                       }
+               }
+       }
+       return(0);
+}
+
+/**************************************************************************
+DECODE_RFC1533 - Decodes RFC1533 header
+**************************************************************************/
+int decode_rfc1533(p, block, len, eof)
+       register unsigned char *p;
+       int block, len, eof;
+{
+       static unsigned char *extdata = NULL, *extend = NULL;
+       unsigned char        *extpath = NULL;
+       unsigned char        *endp;
+
+       if (block == 0) {
+#ifdef IMAGE_MENU
+               memset(imagelist, 0, sizeof(imagelist));
+               menudefault = useimagemenu = 0;
+               menutmo = -1;
+#endif
+#ifdef MOTD
+               memset(motd, 0, sizeof(motd));
+#endif
+               end_of_rfc1533 = NULL;
+               vendorext_isvalid = 0;
+               if (memcmp(p, rfc1533_cookie, 4))
+                       return(0); /* no RFC 1533 header found */
+               p += 4;
+               endp = p + len; }
+       else {
+               if (block == 1) {
+                       if (memcmp(p, rfc1533_cookie, 4))
+                               return(0); /* no RFC 1533 header found */
+                       p += 4;
+                       len -= 4; }
+               if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) {
+                       memcpy(extend, p, len);
+                       extend += len;
+               } else {
+                       printf("Overflow in vendor data buffer! Aborting...\n");
+                       *extdata = RFC1533_END;
+                       return(0);
+               }
+               p = extdata; endp = extend;
+       }
+       if (eof) {
+               while(p < endp) {
+                       unsigned char c = *p;
+                       if (c == RFC1533_PAD) {p++; continue;}
+                       else if (c == RFC1533_END) {
+                               end_of_rfc1533 = endp = p; continue; }
+                       else if (c == RFC1533_NETMASK) {memcpy(&netmask, p+2, sizeof(in_addr));}
+
+                       else if (c == RFC1533_GATEWAY) {
+                               /* This is a little simplistic, but it will
+                                  usually be sufficient.
+                                  Take only the first entry */
+                               if (TAG_LEN(p) >= sizeof(in_addr))
+                                       memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
+                       }
+                       else if (c == RFC1533_EXTENSIONPATH)
+                               extpath = p;
+#ifndef        NO_DHCP_SUPPORT
+                       else if (c == RFC2132_MSG_TYPE)
+                               { dhcp_reply=*(p+2);
+                               }
+                       else if (c == RFC2132_SRV_ID)
+                               {
+                               memcpy(&dhcp_server, p+2, sizeof(in_addr));
+                               }
+#endif /* NO_DHCP_SUPPORT */
+                       else if (c == RFC1533_HOSTNAME)
+                               {
+                               hostname = p + 2;
+                               hostnamelen = *(p + 1);
+                               }
+                       else if (c == RFC1533_VENDOR_MAGIC
+#ifndef        IMAGE_FREEBSD   /* since FreeBSD uses tag 128 for swap definition */
+                                && TAG_LEN(p) >= 6 &&
+                                 !memcmp(p+2,vendorext_magic,4) &&
+                                 p[6] == RFC1533_VENDOR_MAJOR
+#endif
+                               )
+                               vendorext_isvalid++;
+#ifdef IMAGE_FREEBSD
+                       else if (c == RFC1533_VENDOR_HOWTO) {
+                               freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5];
+                       }
+#endif
+#ifdef IMAGE_MENU
+                       else if (c == RFC1533_VENDOR_MNUOPTS) {
+                               parse_menuopts(p+2, TAG_LEN(p));
+                       }
+                       else if (c >= RFC1533_VENDOR_IMG &&
+                                c<RFC1533_VENDOR_IMG+RFC1533_VENDOR_NUMOFIMG){
+                               imagelist[c - RFC1533_VENDOR_IMG] = p;
+                               useimagemenu++;
+                       }
+#endif
+#ifdef MOTD
+                       else if (c >= RFC1533_VENDOR_MOTD &&
+                                c < RFC1533_VENDOR_MOTD +
+                                RFC1533_VENDOR_NUMOFMOTD)
+                               motd[c - RFC1533_VENDOR_MOTD] = p;
+#endif
+                       else {
+#if    0
+                               unsigned char *q;
+                               printf("Unknown RFC1533-tag ");
+                               for(q=p;q<p+2+TAG_LEN(p);q++)
+                                       printf("%x ",*q);
+                               putchar('\n');
+#endif
+                       }
+                       p += TAG_LEN(p) + 2;
+               }
+               extdata = extend = endp;
+               if (block == 0 && extpath != NULL) {
+                       char fname[64];
+                       memcpy(fname, extpath+2, TAG_LEN(extpath));
+                       fname[(int)TAG_LEN(extpath)] = '\000';
+                       printf("Loading BOOTP-extension file: %s\n",fname);
+                       download(fname,decode_rfc1533);
+               }
+       }
+       return(-1); /* proceed with next block */
+}
+
+/**************************************************************************
+IPCHKSUM - Checksum IP Header
+**************************************************************************/
+unsigned short ipchksum(ip, len)
+       register unsigned short *ip;
+       register int len;
+{
+       unsigned long sum = 0;
+       len >>= 1;
+       while (len--) {
+               sum += *(ip++);
+               if (sum > 0xFFFF)
+                       sum -= 0xFFFF;
+       }
+       return((~sum) & 0x0000FFFF);
+}
+
+/**************************************************************************
+RFC951_SLEEP - sleep for expotentially longer times
+**************************************************************************/
+void rfc951_sleep(exp)
+       int exp;
+{
+       static long seed = 0;
+       long q;
+       unsigned long tmo;
+
+#ifdef BACKOFF_LIMIT
+       if (exp > BACKOFF_LIMIT)
+               exp = BACKOFF_LIMIT;
+#endif
+       if (!seed) /* Initialize linear congruential generator */
+               seed = currticks() + *(long *)&arptable[ARP_CLIENT].node
+                      + ((short *)arptable[ARP_CLIENT].node)[2];
+       /* simplified version of the LCG given in Bruce Scheier's
+          "Applied Cryptography" */
+       q = seed/53668;
+       if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l;
+       /* compute mask */
+       for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1);
+       /* sleep */
+       printf("<sleep>\n");
+
+       for (tmo = (tmo&seed)+currticks(); currticks() < tmo; )
+               if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
+       return;
+}
+
+/**************************************************************************
+CLEANUP_NET - shut down networking
+**************************************************************************/
+void cleanup_net(void)
+{
+#ifdef DOWNLOAD_PROTO_NFS
+       nfs_umountall(ARP_SERVER);
+#endif
+       eth_disable();
+       eth_reset();
+}
+
+/**************************************************************************
+CLEANUP - shut down etherboot so that the OS may be called right away
+**************************************************************************/
+void cleanup(void)
+{
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+       ansi_reset();
+#endif
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/baremetal/marini.txt b/baremetal/marini.txt
new file mode 100644 (file)
index 0000000..464f148
--- /dev/null
@@ -0,0 +1,52 @@
+From: "Paolo Marini" <paolom@prisma-eng.it>
+Subject: Etherboot on bare metal
+Date: Tue, 10 Apr 2001 23:19:19 +0200
+Organization: Prisma Engineering srl
+
+Hi Ken,
+I have ported Etherboot on an embedded, biosless platform and would like
+to contribute the code.
+
+Essentially, the hardware I was running Etherboot is a Pentium based
+embedded system, with an Intel Chipset, *but* without serial, VGA,
+keyboard etc., only an 82559 Intel (custom) Ethernet controller (I debug
+it with the etheral Ethernet packet analyser and an emulator).
+
+What I did was:
+
+  a.. integrate the init.s file within the firmware, with GDT
+(re)initialisation (a simple and single entry point taking control of
+the boot process)
+  b.. provide some stupid BIOS stubs in order to let the OS boot and
+still belive that an INT10 call goes to the BIOS
+  c.. provide some basic functions to Etherboot, like timer (I used the
+Pentium TSC internal counter)
+  d.. hardwire in the code information about the RAM size
+The BIOS stubs are enough to boot Linux, pSOS and QNX with bootp. QNX is
+somewhat difficult to load, because the i82559 driver tries to find the
+component using the BIOS32 calls, so I had to patch it.
+
+what i I got from the original firmware is the PCI initialisation and
+resource (I/O, interrupts, memory) allocation.
+
+I send you what I changed, that is, the initialisation code and the
+misc.c file containing the timer, and the makefile (I don't remember
+exactly the options I used to compile all).
+
+Of course, it is only a good starting point for anyone wanting to
+implement a bootp client on a biosless platform; some integration work
+still needs to be done.
+
+Ciao
+Paolo
+
+And in a subsequent email:
+
+I worked with version 4.6.12, but the real modifications involve the
+init.S file, which I think is quite sstable between releases.  I forgot
+to say that my entry point (symbol _start in init.s) assumes the
+processor is already in protected mode.
+
+[The only difference between main.c and misc.c from those in Etherboot
+4.6.12 seems to be the deletion of eth_reset(). This may be of use to
+others trying to make these changes work on more recent releases. Ken]
diff --git a/baremetal/misc.c b/baremetal/misc.c
new file mode 100644 (file)
index 0000000..924ccd6
--- /dev/null
@@ -0,0 +1,351 @@
+/**************************************************************************
+MISC Support Routines
+**************************************************************************/
+
+#include "etherboot.h"
+
+/**************************************************************************
+SLEEP
+**************************************************************************/
+void sleep(int secs)
+{
+       unsigned long tmo;
+
+       for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; )
+               /* Nothing */;
+}
+
+/**************************************************************************
+TWIDDLE
+**************************************************************************/
+void twiddle()
+{
+       static unsigned long lastticks = 0;
+       static int count=0;
+       static const char tiddles[]="-\\|/";
+       unsigned long ticks;
+       if ((ticks = currticks()) == lastticks)
+               return;
+       lastticks = ticks;
+       putchar(tiddles[(count++)&3]);
+       putchar('\b');
+}
+
+/**************************************************************************
+STRCASECMP (not entirely correct, but this will do for our purposes)
+**************************************************************************/
+int strcasecmp(a,b)
+       char *a, *b;
+{
+       while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
+       return((*a & ~0x20) - (*b & ~0x20));
+}
+
+/**************************************************************************
+PRINTF and friends
+
+       Formats:
+               %[#]X   - 4 bytes long (8 hex digits)
+               %[#]x   - 2 bytes int (4 hex digits)
+                       - optional # prefixes 0x
+               %b      - 1 byte int (2 hex digits)
+               %d      - decimal int
+               %c      - char
+               %s      - string
+               %I      - Internet address in x.x.x.x notation
+       Note: width specification not supported
+**************************************************************************/
+static char *do_printf(char *buf, const char *fmt, const int *dp)
+{
+       register char *p;
+       int alt;
+       char tmp[16];
+       static const char hex[]="0123456789ABCDEF";
+
+       while (*fmt) {
+               if (*fmt == '%') {      /* switch() uses more space */
+                       alt = 0;
+                       fmt++;
+                       if (*fmt == '#') {
+                               alt = 1;
+                               fmt++;
+                       }
+                       if (*fmt == 'X') {
+                               const long *lp = (const long *)dp;
+                               register long h = *lp++;
+                               dp = (const int *)lp;
+                               if (alt) {
+                                       *buf++ = '0';
+                                       *buf++ = 'x';
+                               }
+                               *(buf++) = hex[(h>>28)& 0x0F];
+                               *(buf++) = hex[(h>>24)& 0x0F];
+                               *(buf++) = hex[(h>>20)& 0x0F];
+                               *(buf++) = hex[(h>>16)& 0x0F];
+                               *(buf++) = hex[(h>>12)& 0x0F];
+                               *(buf++) = hex[(h>>8)& 0x0F];
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'x') {
+                               register int h = *(dp++);
+                               if (alt) {
+                                       *buf++ = '0';
+                                       *buf++ = 'x';
+                               }
+                               *(buf++) = hex[(h>>12)& 0x0F];
+                               *(buf++) = hex[(h>>8)& 0x0F];
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'b') {
+                               register int h = *(dp++);
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'd') {
+                               register int dec = *(dp++);
+                               p = tmp;
+                               if (dec < 0) {
+                                       *(buf++) = '-';
+                                       dec = -dec;
+                               }
+                               do {
+                                       *(p++) = '0' + (dec%10);
+                                       dec = dec/10;
+                               } while(dec);
+                               while ((--p) >= tmp) *(buf++) = *p;
+                       }
+                       if (*fmt == 'I') {
+                               union {
+                                       long            l;
+                                       unsigned char   c[4];
+                               } u;
+                               const long *lp = (const long *)dp;
+                               u.l = *lp++;
+                               dp = (const int *)lp;
+                               buf = sprintf(buf,"%d.%d.%d.%d",
+                                       u.c[0], u.c[1], u.c[2], u.c[3]);
+                       }
+                       if (*fmt == 'c')
+                               *(buf++) = *(dp++);
+                       if (*fmt == 's') {
+                               p = (char *)*dp++;
+                               while (*p) *(buf++) = *p++;
+                       }
+               } else *(buf++) = *fmt;
+               fmt++;
+       }
+       *buf = '\0';
+       return(buf);
+}
+
+char *sprintf(char *buf, const char *fmt, ...)
+{
+       return do_printf(buf, fmt, ((const int *)&fmt)+1);
+}
+
+void printf(const char *fmt, ...)
+{
+       char buf[120], *p;
+
+       p = buf;
+       do_printf(buf, fmt, ((const int *)&fmt)+1);
+       while (*p) putchar(*p++);
+}
+
+#ifdef IMAGE_MENU
+/**************************************************************************
+INET_ATON - Convert an ascii x.x.x.x to binary form
+**************************************************************************/
+int inet_aton(char *p, in_addr *i)
+{
+       unsigned long ip = 0;
+       int val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = (ip << 8) | val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = (ip << 8) | val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       i->s_addr = htonl((ip << 8) | val);
+       return(1);
+}
+
+#endif /* IMAGE_MENU */
+
+int getdec(char **ptr)
+{
+       char *p = *ptr;
+       int ret=0;
+       if ((*p < '0') || (*p > '9')) return(-1);
+       while ((*p >= '0') && (*p <= '9')) {
+               ret = ret*10 + (*p - '0');
+               p++;
+       }
+       *ptr = p;
+       return(ret);
+}
+
+#define K_RDWR         0x60            /* keyboard data & cmds (read/write) */
+#define K_STATUS       0x64            /* keyboard status */
+#define K_CMD          0x64            /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL     0x01            /* output buffer full */
+#define K_IBUF_FUL     0x02            /* input buffer full */
+
+#define KC_CMD_WIN     0xd0            /* read  output port */
+#define KC_CMD_WOUT    0xd1            /* write output port */
+#define KB_SET_A20     0xdf            /* enable A20,
+                                          enable output buffer full interrupt
+                                          enable data line
+                                          disable clock line */
+#define KB_UNSET_A20   0xdd            /* enable A20,
+                                          enable output buffer full interrupt
+                                          enable data line
+                                          disable clock line */
+#ifndef        IBM_L40
+static void empty_8042(void)
+{
+       unsigned long time;
+       char st;
+
+       time = currticks() + TICKS_PER_SEC;     /* max wait of 1 second */
+       while ((((st = inb(K_CMD)) & K_OBUF_FUL) ||
+              (st & K_IBUF_FUL)) &&
+              currticks() < time)
+               inb(K_RDWR);
+}
+#endif IBM_L40
+
+/*
+ * Gate A20 for high memory
+ */
+void gateA20_set(void)
+{
+#ifdef IBM_L40
+       outb(0x2, 0x92);
+#else  /* IBM_L40 */
+       empty_8042();
+       outb(KC_CMD_WOUT, K_CMD);
+       empty_8042();
+       outb(KB_SET_A20, K_RDWR);
+       empty_8042();
+#endif /* IBM_L40 */
+}
+
+#ifdef TAGGED_IMAGE
+/*
+ * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit
+ * ones) don't expect it to be set by the boot loader.
+ */
+void gateA20_unset(void)
+{
+#ifdef IBM_L40
+       outb(0x0, 0x92);
+#else  /* IBM_L40 */
+       empty_8042();
+       outb(KC_CMD_WOUT, K_CMD);
+       empty_8042();
+       outb(KB_UNSET_A20, K_RDWR);
+       empty_8042();
+#endif /* IBM_L40 */
+}
+#endif
+
+#ifdef ETHERBOOT32
+/* Serial console is only implemented in ETHERBOOT32 for now */
+void
+putchar(int c)
+{
+#ifndef        ANSIESC
+       if (c == '\n')
+               putchar('\r');
+#endif
+
+#ifdef CONSOLE_CRT
+#ifdef ANSIESC
+       handleansi(c);
+#else
+       putc(c);
+#endif
+#endif
+#ifdef CONSOLE_SERIAL
+#ifdef ANSIESC
+       if (c == '\n')
+               serial_putc('\r');
+#endif
+       serial_putc(c);
+#endif
+}
+
+/**************************************************************************
+GETCHAR - Read the next character from the console WITHOUT ECHO
+**************************************************************************/
+int
+getchar(void)
+{
+       int c = 256;
+
+#if defined CONSOLE_CRT || defined CONSOLE_SERIAL
+       do {
+#ifdef CONSOLE_CRT
+               if (ischar())
+                       c = getc();
+#endif
+#ifdef CONSOLE_SERIAL
+               if (serial_ischar())
+                       c = serial_getc();
+#endif
+       } while (c==256);
+       if (c == '\r')
+               c = '\n';
+#endif         
+       return c;
+}
+
+int
+iskey(void)
+{
+#ifdef CONSOLE_CRT
+       if (ischar())
+               return 1;
+#endif
+#ifdef CONSOLE_SERIAL
+       if (serial_ischar())
+               return 1;
+#endif
+       return 0;
+}
+#endif /* ETHERBOOT32 */
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+#include <asm/msr.h>
+
+#define CPUCLOCK 166
+
+unsigned long currticks(void)
+{
+    register unsigned long l, h;
+    long long unsigned p;
+    long long unsigned hh,ll;
+    
+    rdtsc(l, h);
+    ll = l, hh = h;
+
+    p = (ll + hh * 0x100000000LL) * 182 / (CPUCLOCK * 100000LL);
+    return (unsigned)p;
+}
+
diff --git a/baremetal/startmpcc.S b/baremetal/startmpcc.S
new file mode 100644 (file)
index 0000000..07486ce
--- /dev/null
@@ -0,0 +1,756 @@
+/* #defines because ljmp wants a number, probably gas bug */
+/*     .equ    KERN_CODE_SEG,_pmcs-_gdt        */
+#define        KERN_CODE_SEG   0x08
+       .equ    KERN_DATA_SEG,_pmds-_gdt
+/*     .equ    REAL_CODE_SEG,_rmcs-_gdt        */
+#define        REAL_CODE_SEG   0x18
+       .equ    REAL_DATA_SEG,_rmds-_gdt
+       .equ    CR0_PE,1
+
+#ifdef GAS291
+#define DATA32 data32;
+#define ADDR32 addr32;
+#define        LJMPI(x)        ljmp    x
+#else
+#define DATA32 data32
+#define ADDR32 addr32
+/* newer GAS295 require #define        LJMPI(x)        ljmp    *x */
+#define        LJMPI(x)        ljmp    x
+#endif
+
+#define PIC1_VBS  0x08      /* PIC1 interrupts start at vector 64  */
+#define PIC2_VBS  0x70      /* PIC1 interrupts start at vector 112  */
+
+/*
+ * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
+ * then you only have to take care of %ebx, %esi, %edi and %ebp.  These
+ * registers must not be altered under any circumstance.  All other registers
+ * may be clobbered without any negative side effects.  If you don't follow
+ * this rule then you'll run into strange effects that only occur on some
+ * gcc versions (because the register allocator may use different registers).
+ *
+ * All the data32 prefixes for the ljmp instructions are necessary, because
+ * the assembler emits code with a relocation address of 0.  This means that
+ * all destinations are initially negative, which the assembler doesn't grok,
+ * because for some reason negative numbers don't fit into 16 bits. The addr32
+ * prefixes are there for the same reasons, because otherwise the memory
+ * references are only 16 bit wide.  Theoretically they are all superfluous.
+ * One last note about prefixes: the data32 prefixes on all call _real_to_prot
+ * instructions could be removed if the _real_to_prot function is changed to
+ * deal correctly with 16 bit return addresses.  I tried it, but failed.
+ */
+
+/**************************************************************************
+START - Where all the fun begins....
+**************************************************************************/
+/* this must be the first thing in the file because we enter from the top */
+       .global _start
+       .code32
+_start:
+       cli
+       
+       /* load new IDT and GDT */
+       lgdt    gdtarg
+       lidt    Idt_Reg
+       /* flush prefetch queue, and reload %cs:%eip */
+       ljmp    $KERN_CODE_SEG,$1f
+1:
+       
+       /* reload other segment registers */
+       movl    $KERN_DATA_SEG,%eax
+       movl    %eax,%ds
+       movl    %eax,%es
+       movl    %eax,%ss
+        movl    $stktop,%esp
+
+       /* program the PITs in order to stop them */
+        mov    $0x30,%al
+       out     %al,$0x43
+       out     %al,$0x40
+        mov    $0x70,%al
+       out     %al,$0x43
+       out     %al,$0x41
+        mov    $0xf0,%al
+       out     %al,$0x43
+       out     %al,$0x42       
+
+       call    main
+       /* fall through */
+
+       .globl  exit
+exit:
+2:
+        ljmp $KERN_CODE_SEG,$2b
+
+/**************************************************************************
+MEMSIZE - Determine size of extended memory
+**************************************************************************/
+       .globl  memsize
+memsize:
+#if 0
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       call    _prot_to_real
+       .code16
+       movw    $0xe801,%ax
+       stc
+       int     $0x15
+       jc      1f
+       andl    $0xffff,%eax
+       andl    $0xffff,%ebx
+       shll    $6,%ebx
+       addl    %ebx,%eax
+       jmp     2f
+1:
+       movw    $0x8800,%ax
+       int     $0x15
+       andl    $0xffff,%eax
+2:
+       movl    %eax,%esi
+       DATA32 call     _real_to_prot
+       .code32
+       movl    %esi,%eax
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+#else
+       mov     $32768,%eax
+#endif
+       ret
+
+/**************************************************************************
+XSTART - Transfer control to the kernel just loaded
+**************************************************************************/
+       .code16
+
+       .globl _int08_handler
+_int08_handler:
+       movb    $0x20, %al
+       outb    %al, $0x20
+       iret
+
+       .globl _int10_handler
+_int10_handler:
+       cmp     $0x3, %ah
+       jnz     _int10_04
+       mov     $0x0, %dx
+       mov     $0x0, %cx
+       iret
+_int10_04:
+       cmp     $0x4, %ah
+       jnz     _int10_05
+       mov     $0x0, %ah
+       iret
+_int10_05:
+       cmp     $0x5, %ah
+       jnz     _int10_08
+       mov     $0x0, %al
+       iret
+_int10_08:
+       cmp     $0x8, %ah
+       jnz     _int10_0D
+       mov     $0x20, %al
+       mov     $0x7,  %ah
+       iret
+_int10_0D:
+       cmp     $0xD, %ah
+       jnz     _int10_0F
+       mov     $0x0, %al
+       iret
+_int10_0F:
+       cmp     $0xF, %ah
+       jnz     _int10_XX
+       mov     $0xb, %al
+       mov     $80, %ah
+       mov     $0, %bh
+_int10_XX:
+       iret
+       
+       .globl _int11_handler
+_int11_handler:
+       mov     $0x22, %ax
+       iret
+       
+       .globl _int12_handler
+_int12_handler:
+       mov     $640, %ax
+       iret
+       
+       .globl _int13_handler
+_int13_handler:
+       clc
+       mov     $0, %ah
+       iret
+
+       .globl _int14_handler
+_int14_handler:
+       iret
+
+       .globl _int15_handler
+_int15_handler:
+       cmp     $0xe801,%ax
+       jz      _int15_008
+       cmp     $0x0, %ah
+       jz      _int15_000
+       cmp     $0x1, %ah
+       jz      _int15_000
+       cmp     $0x2, %ah
+       jz      _int15_000
+       cmp     $0x3, %ah
+       jz      _int15_000
+       cmp     $0xf, %ah
+       jz      _int15_000
+       cmp     $0x21, %ah
+       jz      _int15_000
+       cmp     $0x40, %ah
+       jz      _int15_000
+       cmp     $0x41, %ah
+       jz      _int15_000
+       cmp     $0x42, %ah
+       jz      _int15_000
+       cmp     $0x43, %ah
+       jz      _int15_000
+       cmp     $0x44, %ah
+       jz      _int15_000
+       cmp     $0x80, %ah
+       jz      _int15_001
+       cmp     $0x81, %ah
+       jz      _int15_001
+       cmp     $0x82, %ah
+       jz      _int15_002
+       cmp     $0x83, %ah
+       jz      _int15_003
+       cmp     $0x84, %ah
+       jz      _int15_000
+       cmp     $0x85, %ah
+       jz      _int15_004
+       cmp     $0x86, %ah
+       jz      _int15_003
+       cmp     $0x87, %ah
+       jz      _int15_005
+       cmp     $0x88, %ah
+       jz      _int15_006
+       cmp     $0x89, %ah
+       jz      _int15_005
+       cmp     $0x90, %ah
+       jz      _int15_007
+       cmp     $0xc0, %ah
+       jz      _int15_000
+       cmp     $0xc1, %ah
+       jz      _int15_000
+       cmp     $0xc2, %ah
+       jz      _int15_000
+       cmp     $0xc3, %ah
+       jz      _int15_000
+       cmp     $0xc4, %ah
+       jz      _int15_000
+       iret
+
+_int15_000:
+       mov     $0x86, %ah
+       stc
+       iret
+
+_int15_001:
+       mov     $0, %bx
+       mov     $0, %cx
+       iret
+
+_int15_002:
+       mov     $0, %bx
+       iret
+
+_int15_003:
+       clc
+       iret
+
+_int15_004:
+       mov     $0, %al
+       iret
+
+_int15_005:
+       mov     $0, %ah
+       clc
+       cmp     $0, %ah
+       iret
+
+_int15_006:
+       mov     $0xf000, %ax
+       iret
+
+_int15_007:
+       stc
+       iret
+
+_int15_008:
+       clc
+       mov     $1024, %dx      /* dx -> extended memory size (in 64K chuncks) */
+       mov     $640, %cx       /* cx -> conventional memory size (in 1 Kbytes chuncks) */
+       iret
+
+       .globl _int16_handler
+_int16_handler:
+       cmp     $0x0, %ah
+       jnz     _int16_01
+       mov     $0x20, %al
+       mov     $0x39, %ah
+       iret
+_int16_01:
+       cmp     $0x1, %ah
+       jnz     _int16_02
+       iret
+_int16_02:
+       cmp     $0x2, %ah
+       jnz     _int16_05
+       mov     $0, %al
+       iret
+_int16_05:
+       cmp     $0x5, %ah
+       jnz     _int16_10
+       mov     $0, %al
+       iret
+_int16_10:
+       cmp     $0x10, %ah
+       jnz     _int16_11
+       mov     $0x20, %al
+       mov     $0x39, %ah
+       iret
+_int16_11:
+       cmp     $0x11, %ah
+       jnz     _int16_12
+       iret
+_int16_12:
+       cmp     $0x12, %ah
+       jnz     _int16_XX
+       mov $0, %ax
+       iret
+_int16_XX:
+       iret
+
+       .globl _int17_handler
+_int17_handler:
+       mov $0xd0, %ah
+       iret
+
+       .globl _int19_handler
+_int19_handler:
+       hlt
+       iret
+
+       .globl _int1A_handler
+_int1A_handler:
+       stc
+       iret
+
+       .code32
+       .globl  xstart
+xstart:
+       /* reprogram the PICs so that interrupt are masked */
+        movb    $0x11,%al      /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+       outb    %al,$0x20
+        movb    $PIC1_VBS, %al
+       outb    %al,$0x21
+        movb    $0x4,%al
+       outb    %al,$0x21
+        movb    $0x1,%al
+       outb    %al,$0x21
+        movb    $0xff,%al
+       outb    %al,$0x21
+       
+        movb    $0x11,%al      /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+       outb    %al,$0xa0
+        movb    $PIC2_VBS, %al
+       outb    %al,$0xa1
+        movb    $0x2,%al
+       outb    %al,$0xa1
+        movb    $0x1,%al
+       outb    %al,$0xa1
+        movb    $0xff,%al
+       outb    %al,$0xa1
+
+       pushl   %ebp
+       movl    %esp,%ebp
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       movl    8(%ebp),%eax
+       movl    %eax,_execaddr
+       movl    12(%ebp),%ebx
+       movl    16(%ebp),%ecx   /* bootp record (32bit pointer) */
+       addl    $28,%ecx        /* ip, udp header */
+       shll    $12,%ecx
+       shrw    $12,%cx
+       call    _prot_to_real
+       .code16
+/* MP: add int10 handler */
+       push    %eax
+       push    %ebx
+       push    %es
+       mov     $0,%ax
+       mov     %ax,%es
+       mov     %cs,%ax
+       shl     $16,%eax
+
+       ADDR32 mov      $(_int08_handler-_start),%ax
+       mov     $0x20,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int10_handler-_start),%ax
+       mov     $0x40,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int11_handler-_start),%ax
+       mov     $0x44,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int12_handler-_start),%ax
+       mov     $0x48,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int13_handler-_start),%ax
+       mov     $0x4c,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int14_handler-_start),%ax
+       mov     $0x50,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int15_handler-_start),%ax
+       mov     $0x54,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int16_handler-_start),%ax
+       mov     $0x58,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int17_handler-_start),%ax
+       mov     $0x5c,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int19_handler-_start),%ax
+       mov     $0x64,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int1A_handler-_start),%ax
+       mov     $0x68,%ebx
+       mov     %eax,%es:(%bx)
+
+       pop     %es
+       pop     %ebx
+       pop     %eax
+/* */
+       pushl   %ecx            /* bootp record */
+       pushl   %ebx            /* file header */
+       movl    $((RELOC<<12)+(1f-RELOC)),%eax
+       pushl   %eax
+       ADDR32  LJMPI(_execaddr-_start)
+1:
+       addw    $8,%sp          /* XXX or is this 10 in case of a 16bit "ret" */
+       DATA32 call     _real_to_prot
+       .code32
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+       popl    %ebp
+       ret
+
+_execaddr:
+       .long   0
+
+#ifdef IMAGE_MULTIBOOT
+/**************************************************************************
+XEND - Restart Etherboot from the beginning (from protected mode)
+**************************************************************************/
+
+       .globl  xend
+xend:
+       cs
+       lidt    idtarg_realmode-_start+RELOC
+       cs
+       lgdt    gdtarg-_start+RELOC
+#ifdef GAS291
+       ljmp    $REAL_CODE_SEG,$1f-RELOC        /* jump to a 16 bit segment */
+#else
+       ljmp    $REAL_CODE_SEG,$1f-_start       /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+       .code16
+       movw    $REAL_DATA_SEG,%ax
+       movw    %ax,%ds
+       movw    %ax,%ss
+       movw    %ax,%es
+
+       /* clear the PE bit of CR0 */
+       movl    %cr0,%eax
+       andl    $0!CR0_PE,%eax
+       movl    %eax,%cr0
+
+       /* make intersegment jmp to flush the processor pipeline
+        * and reload %cs:%eip (to clear upper 16 bits of %eip).
+        */
+       DATA32 ljmp     $(RELOC)>>4,$2f-_start
+2:
+       /* we are in real mode now
+        * set up the real mode segment registers : %ds, %ss, %es
+        */
+       movw    %cs,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+       xorl    %esp,%esp
+       ADDR32 movw     initsp-RELOC,%sp
+
+       movw    $0,%ax
+       movw    %ax,%fs
+       movw    %ax,%gs
+
+       sti
+       jmp     _start
+
+       .code32
+#endif /* IMAGE_MULTIBOOT */
+
+.global get_cs
+get_cs:
+       xorl    %eax,%eax
+       movw    %cs,%ax
+       ret
+
+.global get_ds
+get_ds:
+       xorl    %eax,%eax
+       movw    %ds,%ax
+       ret
+
+.global getsp
+getsp:
+       movl    %esp,%eax       /* GET STACK POINTER */
+       subl    $4, %eax        /* ACCOUNT FOR RETURN ADDRESS ON */
+       ret
+
+.global get_gdtbase
+get_gdtbase:
+       sub     $8,%esp                 /* ALLOCATE ROOM ON THE STACK */
+       sgdt    (%esp,1)                /*STORE IGDT REGISTER ON STACK */
+       mov     2(%esp),%eax            /* READ GDT BASE ADDRESS */
+       mov     $KERN_DATA_SEG,%dx      /* ASSUME UNIVERSAL DS. */
+       add     $8,%esp                 /* RESTORE STACK */
+       ret                             /* DONE */
+
+.global get_gdtsize
+get_gdtsize:
+       sub     $8,%esp /* ALLOCATE ROOM ON THE STACK */
+       sgdt    (%esp,1)        /*STORE IGDT REGISTER ON STACK */
+       xor     %eax,%eax
+       mov     2(%esp),%eax    /* READ GDT BASE ADDRESS */
+       mov     (%ESP),%ax
+       shr     $3,%ax
+       add     $8,%esp /* RESTORE STACK */
+       ret                     /* DONE */
+
+.global get_idtbase
+get_idtbase:
+       sub     $8,%esp
+       sidt   (%esp,1)         /* STORE IIDT REGISTER ON STACK */
+       mov     2(%esp),%eax
+       mov     $KERN_DATA_SEG,%dx
+       add     $8,%esp
+       ret
+
+.global get_lw
+get_lw:
+       xor     %edx,%edx
+       mov     8(%esp),%eax
+       mov     4(%esp),%dx
+       ret
+        
+/**************************************************************************
+SETJMP - Save stack context for non-local goto
+**************************************************************************/
+       .globl  setjmp
+setjmp:
+       mov     4(%esp),%ecx
+       mov     0(%esp),%edx
+       mov     %edx,0(%ecx)
+       mov     %ebx,4(%ecx)
+       mov     %esp,8(%ecx)
+       mov     %ebp,12(%ecx)
+       mov     %esi,16(%ecx)
+       mov     %edi,20(%ecx)
+       mov     %eax,24(%ecx)
+       mov     $0,%eax
+       ret
+
+/**************************************************************************
+LONGJMP - Non-local jump to a saved stack context
+**************************************************************************/
+       .globl  longjmp
+longjmp:
+       mov     4(%esp),%edx
+       mov     8(%esp),%eax
+       mov     0(%edx),%ecx
+       mov     4(%edx),%ebx
+       mov     8(%edx),%esp
+       mov     12(%edx),%ebp
+       mov     16(%edx),%esi
+       mov     20(%edx),%edi
+       cmp     $0,%eax
+       jne     1f
+       mov     $1,%eax
+1:     mov     %ecx,0(%esp)
+       ret
+
+/**************************************************************************
+_REAL_TO_PROT - Go from REAL mode to Protected Mode
+**************************************************************************/
+       .globl  _real_to_prot
+_real_to_prot:
+       .code16
+       cli
+       cs
+       ADDR32 lgdt     gdtarg-_start
+       movl    %cr0,%eax
+       orl     $CR0_PE,%eax
+       movl    %eax,%cr0               /* turn on protected mode */
+
+       /* flush prefetch queue, and reload %cs:%eip */
+       DATA32 ljmp     $KERN_CODE_SEG,$1f
+1:
+       .code32
+       /* reload other segment registers */
+       movl    $KERN_DATA_SEG,%eax
+       movl    %eax,%ds
+       movl    %eax,%es
+       movl    %eax,%ss
+       addl    $RELOC,%esp             /* Fix up stack pointer */
+       xorl    %eax,%eax
+       movl    %eax,%fs
+       movl    %eax,%gs
+       popl    %eax                    /* Fix up return address */
+       addl    $RELOC,%eax
+       pushl   %eax
+       ret
+
+/**************************************************************************
+_PROT_TO_REAL - Go from Protected Mode to REAL Mode
+**************************************************************************/
+       .globl  _prot_to_real
+_prot_to_real:
+       .code32
+       popl    %eax
+       subl    $RELOC,%eax             /* Adjust return address */
+       pushl   %eax
+       subl    $RELOC,%esp             /* Adjust stack pointer */
+#ifdef GAS291
+       ljmp    $REAL_CODE_SEG,$1f-RELOC        /* jump to a 16 bit segment */
+#else
+       ljmp    $REAL_CODE_SEG,$1f-_start       /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+       .code16
+       movw    $REAL_DATA_SEG,%ax
+       movw    %ax,%ds
+       movw    %ax,%ss
+       movw    %ax,%es
+       movw    %ax,%fs
+       movw    %ax,%gs
+       cli
+
+       /* clear the PE bit of CR0 */
+       movl    %cr0,%eax
+       andl    $0!CR0_PE,%eax
+       movl    %eax,%cr0
+
+       /* make intersegment jmp to flush the processor pipeline
+        * and reload %cs:%eip (to clear upper 16 bits of %eip).
+        */
+       DATA32 ljmp     $(RELOC)>>4,$2f-_start
+2:
+       /* we are in real mode now
+        * set up the real mode segment registers : %ds, $ss, %es
+        */
+       movw    %cs,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+#if 0
+       sti
+#endif
+       DATA32 ret      /* There is a 32 bit return address on the stack */
+       .code32
+
+/**************************************************************************
+GLOBAL DESCRIPTOR TABLE
+**************************************************************************/
+       .align  4
+Idt_Reg:
+       .word 0x3ff
+       .long 0
+
+       .align  4
+_gdt:
+gdtarg:
+Gdt_Table:
+       .word   0x27                    /* limit */
+       .long   _gdt                    /* addr */
+       .word   0
+_pmcs:
+       /* 32 bit protected mode code segment */
+       .word   0xffff,0
+       .byte   0,0x9f,0xcf,0
+
+_pmds:
+       /* 32 bit protected mode data segment */
+       .word   0xffff,0
+       .byte   0,0x93,0xcf,0
+
+_rmcs:
+       /* 16 bit real mode code segment */
+       .word   0xffff,(RELOC&0xffff)
+       .byte   (RELOC>>16),0x9b,0x00,(RELOC>>24)
+
+_rmds:
+       /* 16 bit real mode data segment */
+       .word   0xffff,(RELOC&0xffff)
+       .byte   (RELOC>>16),0x93,0x00,(RELOC>>24)
+
+       .align  4
+RUN_GDT:                       /* POINTER TO GDT IN RAM */
+        .byte   0x7f,0         /* [BSP_GDT_NUM*8]-1 */
+        .long   Gdt_Table
+
+       .align  4
+
+       .section ".rodata"
+err_not386:
+       .ascii  "Etherboot/32 requires 386+"
+       .byte   0x0d, 0x0a
+err_not386_end:
+
+days:  .long   0
+irq_num: .long
+
+        .data
+       .align  4
+        .org 2048
+.global stktop
+stktop:
+       .long
+
+.section ".armando"
+/*                 1:::::::::2:::::::::3:::::::3 */
+/*        12345678901234567890123456789012345678 */
+/*       v----+----v----+----v----+----v----+--- */
+
+.global EtherbootString
+EtherbootString:
+.ascii "EtherBoot MPCC  "      /* fw identifier */
+
+.byte  0, 0            /* mandatory hole */
+
+.long  _start          /* entry point */
+.word  0
+.byte  'E'             /* type */
+.byte  0               /* selector */
+.word  0               /* CRC */
diff --git a/bin2intelhex/Makefile b/bin2intelhex/Makefile
new file mode 100644 (file)
index 0000000..7406968
--- /dev/null
@@ -0,0 +1,9 @@
+
+CC=gcc
+CFLAGS=-Wall -O2
+
+bin2intelhex:
+
+
+clean:
+       rm -f bin2intelhex core *.o
diff --git a/bin2intelhex/bin2intelhex.c b/bin2intelhex/bin2intelhex.c
new file mode 100644 (file)
index 0000000..75b88c1
--- /dev/null
@@ -0,0 +1,148 @@
+/* name : bin2intelhex.c
+ * from : Jean Marc Lacroix <jeanmarc.lacroix@free.fr>
+ * date : 06/12/1997.
+ * abstract : Y have rewrite this program from ????? with some modifications
+ * to add :
+ * - the Intel specification.
+ * - correct a bug because my prom programmer don't understand the
+ * initial format. Y suspect a bug in the calcul of the lrc
+ * in the original program.
+ * - correct the format of printf . In the original program, it was
+ *   %x, and it is in fact %X, because in the Intel Format, all the
+ * char are in upper case.
+ * - correct the lrc calculation.
+ * usage:
+ *-------
+ * this program read the standard input and put to the standard output
+ * the result of the conversion.
+ * an example of use :
+ * cat my_bin | bin2intelhex > my_bin.hex or.....
+ * bin2intelhex < my_bin > my_bin.hex
+ */
+
+
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2005/05/17 16:45:06  mcb30
+ * Initial revision
+ *
+ * Revision 1.9  1997/12/14 05:14:54  install
+ * - some documentation....
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Intel Hex format specifications
+
+The 8-bit Intel Hex File Format is a printable ASCII format consisting of one
+ or more data records followed by an end of file record. Each
+record consists of one line of information. Data records may appear in any
+ order. Address and data values are represented as 2 or 4 hexadecimal
+digit values. 
+
+Record Format 
+:LLAAAARRDDDD......DDDDCC 
+
+
+LL
+AAAA
+RR
+DD
+CC
+Length field. Number of data bytes.
+Address field. Address of first byte.
+Record type field. 00 for data and 01 for end of record.
+Data field.
+Checksum field. One's complement of length, address, record type and data
+ fields modulo 256. 
+CC = LL + AAAA + RR + all DD = 0
+
+Example: 
+:06010000010203040506E4 
+:00000001FF 
+
+The first line in the above example Intel Hex file is a data record addressed
+ at location 100H with data values 1 to 6. The second line is the end
+of file record, so that the LL field is 0
+
+*/
+
+
+typedef unsigned char t_u8;
+typedef unsigned short t_u16;
+/*
+ * the choice for the total length (16) of a line, but the specification
+ * can support an another value
+ */
+#define LL_MAX_LINE 16
+typedef struct 
+{ 
+  t_u8 intel_lg_data;
+  t_u16 intel_adr;
+  t_u8 intel_type;
+  t_u8 intel_data [LL_MAX_LINE];
+  t_u8 intel_lrc;
+} t_one_line;
+#define INTEL_DATA_TYPE 0
+#define EXIT_OK 0
+int main (const int argc, const char ** const argv)
+{
+  t_one_line line;
+  /*
+   * init for the adress, please note that it is assume that the program begin at 0
+   */
+  line.intel_adr = 0;
+  line.intel_type = INTEL_DATA_TYPE;
+  /*
+   * read the data on the standard input
+   */
+  while ((line.intel_lg_data = read (0, &line.intel_data [0] ,LL_MAX_LINE )) > 0) 
+    {
+      t_u8 i; 
+      /*
+       * and now for this line, calculate the lrc.
+       */
+      line.intel_lrc = line.intel_lg_data;
+      line.intel_lrc += ((line.intel_adr >> 8) & 0xff);
+      line.intel_lrc += (line.intel_adr &0xff);
+      line.intel_lrc += line.intel_type;
+      /*
+       * the structure is ready, print it to stdout in the
+       * right format
+       */
+      (void) printf (":%02X%04X%02X",
+                    line.intel_lg_data,
+                    line.intel_adr,
+                    line.intel_type);
+      /*
+       * edit all the data read
+       */
+      for (i=0; i<line.intel_lg_data; i++)
+       {
+         (void) printf ("%02X",
+                        (line.intel_data [i] & 0xff));   
+         /*
+          * add to the lrc the data print
+          */
+         line.intel_lrc +=line.intel_data [i];
+       }
+      /*
+       * edit the value of the lrc and new line for the next
+       */
+      (void) printf ("%02X\n",
+                        (0x100 - line.intel_lrc) & 0xff);
+      /* 
+       * prepare the new adress for the next line
+       */
+      line.intel_adr+=line.intel_lg_data;     
+    }
+  /*
+   * print the last line with a length of 0 data, so that the lrc is easy to
+   * calculate (ff+01 =0)
+   */
+  printf (":00000001FF\n");
+  exit (EXIT_OK); 
+}
diff --git a/bin2intelhex/bin2intelhex.c.simple b/bin2intelhex/bin2intelhex.c.simple
new file mode 100644 (file)
index 0000000..3cb279a
--- /dev/null
@@ -0,0 +1,74 @@
+/* 
+
+  Quick and dirty program to make intel-hex from a binary.
+
+  Written by R.E.Wolff@BitWizard.nl
+  This file is in the public domain
+
+  Typing started:
+
+  Mon Jun 16 00:24:15 MET DST 1997
+
+  programming stopped:
+
+  Mon Jun 16 00:31:27 MET DST 1997
+
+  debugging finished (2 bugs found):
+  Mon Jun 16 00:32:52 MET DST 1997
+
+--------------------------------------------------------- 
+
+  Doc written in timeout. Everything else in this file was done while
+  the timer was running.
+
+  I promised "Mark Kopecki" that writing the bin-to-intel-hex
+  converter would cost less than 15 minutes, and that it would be more
+  trouble to find a converter on the net than to write the converter
+  myself.  I ended up spending over half an hour searching for
+  spec/converter/docs because of unreachable hosts on the internet. I
+  got a file with docs, after that it was 8 minutes.....
+
+--------------------------------------------------------- 
+
+*/
+
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Intel Hex format:
+   
+   ll aaaa tt dd....dd cc
+   ll = length
+   aaaa = address
+   tt = type
+   dd....dd = data
+   cc = checksum.
+*/
+
+
+int main (int argc, char **argv)
+{
+  unsigned char buf[32];
+  int addr = 0;
+  int n,i;
+
+  while ((n = read (0, buf+4, 16)) > 0) {
+    buf[0] = n;
+    buf[1] = addr >> 8;
+    buf[2] = addr & 0xff;
+    buf[3] = 0x00;
+    buf[4+n] = 0x00;
+
+    for (i=0;i<4+n;i++)
+      buf[4+n] -= buf[i];
+    printf (":");
+    for (i=0;i<= 4+n;i++)
+      printf ("%02x", buf[i]);
+    printf ("\n");
+    addr += n;
+  }
+  printf (":0000000001ff\n");
+  exit (0);
+}
diff --git a/bochs/.gitignore b/bochs/.gitignore
new file mode 100644 (file)
index 0000000..4e8f81a
--- /dev/null
@@ -0,0 +1,7 @@
+bochsout.txt
+parport.out
+ne2k-tx.log
+ne2k-txdump.txt
+tunctl
+bochs
+qemu
diff --git a/bochs/Makefile b/bochs/Makefile
new file mode 100644 (file)
index 0000000..4a5b14c
--- /dev/null
@@ -0,0 +1,10 @@
+all : tunctl serial-console.1
+
+%.1 : %
+       pod2man $< > $@
+
+tunctl : tunctl.c
+       $(CC) -o $@ $<
+
+clean :
+       rm -f serial-console.1 tunctl
diff --git a/bochs/README b/bochs/README
new file mode 100644 (file)
index 0000000..e0e8803
--- /dev/null
@@ -0,0 +1,95 @@
+Running Etherboot within Bochs
+==============================
+
+Michael Brown <mbrown@fensystems.co.uk>
+Based on an idea suggested by H. Peter Anvin <hpa@zytor.com>.
+
+$Id$
+
+Bochs is a program that simulates a complete Intel x86 computer,
+including hardware.  It can be used to test Etherboot.  There is a
+special pseudo NIC ("pnic") implemented in Bochs, with a corresponding
+driver in Etherboot.  (There is also an NE2000 ISA driver in Bochs,
+but it doesn't seem to quite work.)
+
+To get bochs running is fairly simple:
+
+1.  Build the utilities in this directory:
+      make
+
+2.  Get the bochs source code:
+      cvs -d:pserver:anonymous@bochs.cvs.sourceforge.net:/cvsroot/bochs \
+           login
+      cvs -d:pserver:anonymous@bochs.cvs.sourceforge.net:/cvsroot/bochs \
+           co bochs
+
+3.  Configure bochs with
+      pushd bochs
+      ./configure --enable-all-optimisations --enable-show-ips \
+                 --enable-cpu-level=6 \
+                 --enable-pci --enable-pnic --enable-ne2000 \
+                  --enable-debugger --enable-disasm
+      popd
+
+4.  Build bochs:
+      make -C bochs
+
+5.  As root, set up a TAP virtual network device:
+      /sbin/modprobe tun
+      chmod o+rw /dev/net/tun
+      ./tunctl -u <username> -t tap0
+      /sbin/ifconfig tap0 up 10.254.254.2 netmask 255.255.255.0
+
+6.  As root, add the following fragment to /etc/dhcpd.conf:
+      subnet 10.254.254.0 netmask 255.255.255.252 {
+        range dynamic-bootp 10.254.254.1 10.254.254.1;
+      }
+    You will also need to add in any of your usual declarations for
+    Etherboot, e.g. 'filename "vmlinuz.ltsp";'.  Note that this setup
+    assumes that your DHCP server, TFTP server etc. all live on the
+    machine you are using for running Bochs.  If not, then you're on
+    your own.
+
+7.  As root, restart dhcpd
+      /etc/init.d/dhcpd restart
+
+8.  Build Etherboot images
+      pushd ../../src
+      make bin/pnic.dsk
+      popd
+
+9.  Start Bochs
+      ./bochs/bochs -q
+    You should get to the debugger prompt "<bochs:1>".  Type "c" to
+    start running Bochs.
+
+You should see Bochs start up, load up Etherboot and attempt to boot
+from the network.
+
+
+
+Serial console
+==============
+
+You can use the program "serial-console" to obtain a virtual serial
+console for Etherboot running within Bochs.  Simply run
+"./serial-console" on a spare tty (e.g. a separate xterm window)
+before starting Bochs, and ensure that you have enabled CONSOLE_SERIAL
+in config.h.
+
+There is a manual page for "serial-console"; use
+"man ./serial-console.1" to view it.
+
+
+
+TODO
+====
+
+Packet forwarding/masquerading - document what must be set up.
+
+Mention possibility of using RFB as the display device - in
+conjunction with the serial console, gives you a test facility that
+can be accessed remotely.
+
+Mention use of BOCHSBP instruction (xchgw %bx,%bx) to avoid need to
+calculate breakpoints.
diff --git a/bochs/README.qemu b/bochs/README.qemu
new file mode 100644 (file)
index 0000000..0c38897
--- /dev/null
@@ -0,0 +1,79 @@
+Running gPXE within qemu
+========================
+
+Michael Brown <mbrown@fensystems.co.uk>
+
+To get qemu running is fairly simple:
+
+1.  Build the utilities in this directory:
+      make
+
+2.  Get the qemu source code:
+      svn co svn://svn.savannah.nongnu.org/qemu/trunk qemu
+
+2a. Patch the qemu code.  There is currently a bug that causes qemu to
+    execute gPXE incredibly slowly.  The bug seems to be related
+    to the relative prioritisation of CPU and I/O operations within
+    qemu.  This patch (which I found via Google) isn't a proper fix,
+    but it does work around the problem:
+      patch -p0 < qemu-patch
+
+3.  Configure qemu with
+      pushd qemu
+      ./configure --target-list=i386-softmmu,x86_64-softmmu
+      popd
+
+4.  Build qemu:
+      make -C qemu
+
+5.  As root, set up a TAP virtual network device:
+      /sbin/modprobe tun
+      chmod o+rw /dev/net/tun
+      ./tunctl -u <username> -t tap0
+      /sbin/ifconfig tap0 up 10.254.254.2 netmask 255.255.255.0
+
+6.  As root, add the following fragment to /etc/dhcpd.conf:
+      subnet 10.254.254.0 netmask 255.255.255.252 {
+        range dynamic-bootp 10.254.254.1 10.254.254.1;
+      }
+    You will also need to add in any of your usual declarations for
+    gPXE, e.g. 'filename "vmlinuz.ltsp";'.  Note that this setup
+    assumes that your DHCP server, TFTP server etc. all live on the
+    machine you are using for running qemu.  If not, then you're on
+    your own.
+
+7.  As root, restart dhcpd
+      /etc/init.d/dhcpd restart
+
+8.  Build gPXE floppy disk images and pad to 1.44MB
+      pushd ../../src
+      make bin/rtl8139.dsk
+      popd
+
+9.  Start qemu
+      ./qemu/i386-softmmu/qemu -L qemu/pc-bios \
+                              -net nic,model=rtl8139 -net tap,ifname=tap0 \
+                              -boot a -fda ../../src/bin/rtl8139.dsk
+
+You should see qemu start up, load up gPXE and attempt to boot from
+the network.
+
+
+
+Serial console
+==============
+
+You can use the program "serial-console" to obtain a virtual serial
+console for gPXE running within qemu.  Run "./serial-console" on a
+spare tty (e.g. a separate xterm window) before starting qemu, and
+ensure that you have enabled CONSOLE_SERIAL in config.h.
+
+When serial-console starts, it will print out the message "Slave pty
+is /dev/pts/XX", where XX is a number.  You need to append the option
+
+   -serial /dev/pts/XX
+
+to the qemu command line.
+
+There is a manual page for "serial-console"; use "man
+./serial-console.1" to view it.
diff --git a/bochs/README.windows-ris b/bochs/README.windows-ris
new file mode 100644 (file)
index 0000000..830db6a
--- /dev/null
@@ -0,0 +1,31 @@
+Debugging Windows Remote Installation Services (RIS) can be
+problematic.  Here are some assorted notes on the process:
+
+
+Getting hold of the files
+=========================
+
+Add/Remove Windows Components -> Remote Installation Services
+
+Files will be placed in \windows\system32\reminst.  Copy them out to a
+TFTP server.  Configure DHCP to hand out startrom.com.
+
+
+Getting past the "Press F12" message
+====================================
+
+Passing F12 through to the guest machine is difficult.  It's easier to
+patch the startrom.com binary to accept a different key.  Open
+startrom.com in a hex editor, search for the hex string
+6681fb00860000, and replace it with 6681fb66210000.  startrom.com will
+now accept the "F" key instead of "F12".
+
+
+
+DHCP filename
+=============
+
+Must use Windows backslash separator e.g. 'filename
+"OSChooser\\i386\\startrom.com";', otherwise startrom.com fails to
+correctly identify the path to NTLDR.
+
diff --git a/bochs/bochs-writable-ROM-patch b/bochs/bochs-writable-ROM-patch
new file mode 100644 (file)
index 0000000..1ab9a27
--- /dev/null
@@ -0,0 +1,20 @@
+Index: memory/memory.cc
+===================================================================
+RCS file: /cvsroot/bochs/bochs/memory/memory.cc,v
+retrieving revision 1.71
+diff -u -r1.71 memory.cc
+--- memory/memory.cc   18 Oct 2008 18:10:14 -0000      1.71
++++ memory/memory.cc   21 Oct 2008 19:47:07 -0000
+@@ -172,7 +172,11 @@
+             break;
+           case 0x0:   // Writes to ROM, Inhibit
+-            BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
++            if ((a20addr & 0xfffe0000) == 0x000e0000) {
++            BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
++          } else {
++            BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ] = *data_ptr;
++            }
+             break;
+           default:
diff --git a/bochs/bochsrc.txt b/bochs/bochsrc.txt
new file mode 100644 (file)
index 0000000..bf99f4c
--- /dev/null
@@ -0,0 +1,750 @@
+# You may now use double quotes around pathnames, in case
+# your pathname includes spaces.
+
+#=======================================================================
+# CONFIG_INTERFACE
+#
+# The configuration interface is a series of menus or dialog boxes that
+# allows you to change all the settings that control Bochs's behavior.
+# There are two choices of configuration interface: a text mode version
+# called "textconfig" and a graphical version called "wx".  The text
+# mode version uses stdin/stdout and is always compiled in.  The graphical
+# version is only available when you use "--with-wx" on the configure 
+# command.  If you do not write a config_interface line, Bochs will 
+# choose a default for you.
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#=======================================================================
+#config_interface: textconfig
+#config_interface: wx
+
+#=======================================================================
+# DISPLAY_LIBRARY
+#
+# The display library is the code that displays the Bochs VGA screen.  Bochs 
+# has a selection of about 10 different display library implementations for 
+# different platforms.  If you run configure with multiple --with-* options, 
+# the display_library command lets you choose which one you want to run with.
+# If you do not write a display_library line, Bochs will choose a default for
+# you.
+#
+# The choices are: 
+#   x              use X windows interface, cross platform
+#   win32          use native win32 libraries
+#   carbon         use Carbon library (for MacOS X)
+#   beos           use native BeOS libraries
+#   macintosh      use MacOS pre-10
+#   amigaos        use native AmigaOS libraries
+#   sdl            use SDL library, cross platform
+#   svga           use SVGALIB library for Linux, allows graphics without X11
+#   term           text only, uses curses/ncurses library, cross platform
+#   rfb            provides an interface to AT&T's VNC viewer, cross platform
+#   wx             use wxWidgets library, cross platform
+#   nogui          no display at all
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#
+# Specific options:
+# Some display libraries now support specific option to control their
+# behaviour. See the examples below for currently supported options.
+#=======================================================================
+#display_library: amigaos
+#display_library: beos
+#display_library: carbon
+#display_library: macintosh
+#display_library: nogui
+#display_library: rfb, options="timeout=60" # time to wait for client
+#display_library: sdl, options="fullscreen" # startup in fullscreen mode
+#display_library: term
+#display_library: win32, options="legacyF12" # use F12 to toggle mouse
+#display_library: wx
+#display_library: x
+
+#=======================================================================
+# ROMIMAGE:
+# The ROM BIOS controls what the PC does when it first powers on.
+# Normally, you can use a precompiled BIOS in the source or binary
+# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded
+# starting at address 0xf0000, and it is exactly 64k long.
+# You can also use the environment variable $BXSHARE to specify the
+# location of the BIOS.
+# The usage of external large BIOS images (up to 512k) at memory top is
+# now supported, but we still recommend to use the BIOS distributed with
+# Bochs. Now the start address can be calculated from image size.
+#=======================================================================
+romimage: file=bochs/bios/BIOS-bochs-latest, address=0xe0000
+#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
+#romimage: file=mybios.bin # calculate start address from image size
+
+#=======================================================================
+# CPU:
+# This defines cpu-related parameters inside Bochs:
+#
+#  COUNT:
+#  Set the number of processors:cores per processor:threads per core 
+#  when Bochs is compiled for SMP emulation.
+#  Bochs currently supports up to 8 threads running simultaniosly. 
+#  If Bochs is compiled without SMP support, it won't accept values 
+#  different from 1.
+#
+#  RESET_ON_TRIPLE_FAULT:
+#  Reset the CPU when triple fault occur (highly recommended) rather than
+#  PANIC. Remember that if you trying to continue after triple fault the 
+#  simulation will be completely bogus !
+#
+#  IPS:
+#  Emulated Instructions Per Second.  This is the number of IPS that bochs
+#  is capable of running on your machine. You can recompile Bochs with
+#  --enable-show-ips option enabled, to find your workstation's capability.
+#  Measured IPS value will then be logged into your log file or status bar
+#  (if supported by the gui).
+#
+#  IPS is used to calibrate many time-dependent events within the bochs 
+#  simulation.  For example, changing IPS affects the frequency of VGA
+#  updates, the duration of time before a key starts to autorepeat, and
+#  the measurement of BogoMips and other benchmarks.
+#
+#  Examples:
+#  Machine                                         Mips
+# ________________________________________________________________
+#  2.1Ghz Athlon XP with Linux 2.6/g++ 3.4         12 to 15 Mips
+#  1.6Ghz Intel P4 with Win2000/g++ 3.3             5 to  7 Mips
+#  650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66  2 to  2.5 Mips
+#  400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3   1 to  1.8 Mips
+#=======================================================================
+cpu: count=1, ips=10000000, reset_on_triple_fault=1
+
+#=======================================================================
+# MEGS
+# Set the number of Megabytes of physical memory you want to emulate. 
+# The default is 32MB, most OS's won't need more than that.
+# The maximum amount of memory supported is 2048Mb.
+#=======================================================================
+#megs: 256
+#megs: 128
+#megs: 64
+megs: 32
+#megs: 16
+#megs: 8
+
+#=======================================================================
+# OPTROMIMAGE[1-4]:
+# You may now load up to 4 optional ROM images. Be sure to use a 
+# read-only area, typically between C8000 and EFFFF. These optional
+# ROM images should not overwrite the rombios (located at
+# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
+# Those ROM images will be initialized by the bios if they contain 
+# the right signature (0x55AA) and a valid checksum.
+# It can also be a convenient way to upload some arbitrary code/data
+# in the simulation, that can be retrieved by the boot loader
+#=======================================================================
+#optromimage1: file=optionalrom.bin, address=0xd0000
+#optromimage2: file=optionalrom.bin, address=0xd1000
+#optromimage3: file=optionalrom.bin, address=0xd2000
+#optromimage4: file=optionalrom.bin, address=0xd3000
+optromimage1: file=../../src/bin/pnic.rom, address=0xd0000
+#optromimage1: file=../../src/bin/rtl8029.rom, address=0xd0000
+
+#optramimage1: file=/path/file1.img, address=0x0010000
+#optramimage2: file=/path/file2.img, address=0x0020000
+#optramimage3: file=/path/file3.img, address=0x0030000
+#optramimage4: file=/path/file4.img, address=0x0040000
+
+#=======================================================================
+# VGAROMIMAGE
+# You now need to load a VGA ROM BIOS into C0000.
+#=======================================================================
+#vgaromimage: file=bios/VGABIOS-elpin-2.40
+vgaromimage: file=bochs/bios/VGABIOS-lgpl-latest
+#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
+
+#=======================================================================
+# VGA:
+# Here you can specify the display extension to be used. With the value
+# 'none' you can use standard VGA with no extension. Other supported
+# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
+#=======================================================================
+#vga: extension=cirrus
+#vga: extension=vbe
+vga: extension=none
+
+#=======================================================================
+# FLOPPYA:
+# Point this to pathname of floppy image file or device
+# This should be of a bootable floppy(image/device) if you're
+# booting from 'a' (or 'floppy').
+#
+# You can set the initial status of the media to 'ejected' or 'inserted'.
+#   floppya: 2_88=path, status=ejected             (2.88M 3.5" floppy)
+#   floppya: 1_44=path, status=inserted            (1.44M 3.5" floppy)
+#   floppya: 1_2=path, status=ejected              (1.2M  5.25" floppy)
+#   floppya: 720k=path, status=inserted            (720K  3.5" floppy)
+#   floppya: 360k=path, status=inserted            (360K  5.25" floppy)
+#   floppya: 320k=path, status=inserted            (320K  5.25" floppy)
+#   floppya: 180k=path, status=inserted            (180K  5.25" floppy)
+#   floppya: 160k=path, status=inserted            (160K  5.25" floppy)
+#   floppya: image=path, status=inserted           (guess type from image size)
+#
+# The path should be the name of a disk image file.  On Unix, you can use a raw
+# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
+# such as a: or b: as the path.  The parameter 'image' works with image files
+# only. In that case the size must match one of the supported types.
+#=======================================================================
+#floppya: 1_44=/dev/fd0, status=inserted
+#floppya: image=../1.44, status=inserted
+#floppya: 1_44=/dev/fd0H1440, status=inserted
+#floppya: 1_2=../1_2, status=inserted
+#floppya: 1_44=a:, status=inserted
+#floppya: 1_44=a.img, status=inserted
+#floppya: 1_44=/dev/rfd0a, status=inserted
+floppya: 1_44=../../src/bin/pnic.dsk, status=inserted
+
+#=======================================================================
+# FLOPPYB:
+# See FLOPPYA above for syntax
+#=======================================================================
+#floppyb: 1_44=b:, status=inserted
+floppyb: 1_44=b.img, status=inserted
+
+#=======================================================================
+# ATA0, ATA1, ATA2, ATA3
+# ATA controller for hard disks and cdroms
+#
+# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
+# 
+# These options enables up to 4 ata channels. For each channel
+# the two base io addresses and the irq must be specified.
+# 
+# ata0 and ata1 are enabled by default with the values shown below
+#
+# Examples:
+#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
+#=======================================================================
+ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
+
+#=======================================================================
+# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
+#
+# This defines the type and characteristics of all attached ata devices:
+#   type=       type of attached device [disk|cdrom] 
+#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
+#   mode=       only valid for disks [undoable|growing|volatile]
+#   path=       path of the image
+#   cylinders=  only valid for disks
+#   heads=      only valid for disks
+#   spt=        only valid for disks
+#   status=     only valid for cdroms [inserted|ejected]
+#   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
+#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
+#   model=      string returned by identify device command
+#   journal=    optional filename of the redolog for undoable and volatile disks
+#   
+# Point this at a hard disk image file, cdrom iso file, or physical cdrom
+# device.  To create a hard disk image, try running bximage.  It will help you
+# choose the size and then suggest a line that works with it.
+#
+# In UNIX it may be possible to use a raw device as a Bochs hard disk, 
+# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
+#
+# In windows, the drive letter + colon notation should be used for cdroms.
+# Depending on versions of windows and drivers, you may only be able to 
+# access the "first" cdrom in the system.  On MacOSX, use path="drive"
+# to access the physical drive.
+#
+# The path is always mandatory. For flat hard disk images created with
+# bximage geometry autodetection can be used (cylinders=0 -> cylinders are
+# calculated using heads=16 and spt=63). For other hard disk images and modes
+# the cylinders, heads, and spt are mandatory.
+#
+# Default values are:
+#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
+#
+# The biosdetect option has currently no effect on the bios
+#
+# Examples:
+#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
+#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
+#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
+#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
+#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
+#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
+#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
+#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
+#=======================================================================
+#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
+#ata0-slave: type=cdrom, path=D:, status=inserted
+#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
+#ata0-slave: type=cdrom, path="drive", status=inserted
+#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted 
+
+#=======================================================================
+# BOOT:
+# This defines the boot sequence. Now you can specify up to 3 boot drives.
+# You can either boot from 'floppy', 'disk' or 'cdrom'
+# legacy 'a' and 'c' are also supported
+# Examples:
+#   boot: floppy
+#   boot: disk
+#   boot: cdrom
+#   boot: c
+#   boot: a
+#   boot: cdrom, floppy, disk
+#=======================================================================
+#boot: floppy
+#boot: disk
+
+#=======================================================================
+# CLOCK:
+# This defines the parameters of the clock inside Bochs:
+#
+#  SYNC:
+#  TO BE COMPLETED (see Greg explanation in feature request #536329)
+#
+#  TIME0:
+#  Specifies the start (boot) time of the virtual machine. Use a time 
+#  value as returned by the time(2) system call. If no time0 value is 
+#  set or if time0 equal to 1 (special case) or if time0 equal 'local', 
+#  the simulation will be started at the current local host time.
+#  If time0 equal to 2 (special case) or if time0 equal 'utc',
+#  the simulation will be started at the current utc time.
+#
+# Syntax:
+#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
+#
+# Example:
+#   clock: sync=none,     time0=local       # Now (localtime)
+#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
+#   clock: sync=none,     time0=631148400   # Mon Jan  1 00:00:00 1990
+#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
+#   clock: sync=realtime, time0=946681200   # Sat Jan  1 00:00:00 2000
+#   clock: sync=none,     time0=1           # Now (localtime)
+#   clock: sync=none,     time0=utc         # Now (utc/gmt)
+# 
+# Default value are sync=none, time0=local
+#=======================================================================
+#clock: sync=none, time0=local
+
+
+#=======================================================================
+# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
+# Enables or disables the 0xaa55 signature check on boot floppies
+# Defaults to disabled=0
+# Examples:
+#   floppy_bootsig_check: disabled=0
+#   floppy_bootsig_check: disabled=1
+#=======================================================================
+#floppy_bootsig_check: disabled=1
+floppy_bootsig_check: disabled=0
+
+#=======================================================================
+# LOG:
+# Give the path of the log file you'd like Bochs debug and misc. verbiage
+# to be written to. If you don't use this option or set the filename to
+# '-' the output is written to the console. If you really don't want it,
+# make it "/dev/null" (Unix) or "nul" (win32). :^(
+#
+# Examples:
+#   log: ./bochs.out
+#   log: /dev/tty
+#=======================================================================
+#log: /dev/null
+log: bochsout.txt
+
+#=======================================================================
+# LOGPREFIX:
+# This handles the format of the string prepended to each log line.
+# You may use those special tokens :
+#   %t : 11 decimal digits timer tick
+#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
+#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
+#   %d : 5 characters string of the device, between brackets
+# 
+# Default : %t%e%d
+# Examples:
+#   logprefix: %t-%e-@%i-%d
+#   logprefix: %i%e%d
+#=======================================================================
+#logprefix: %t%e%d
+
+#=======================================================================
+# LOG CONTROLS
+#
+# Bochs now has four severity levels for event logging.
+#   panic: cannot proceed.  If you choose to continue after a panic, 
+#          don't be surprised if you get strange behavior or crashes.
+#   error: something went wrong, but it is probably safe to continue the
+#          simulation.
+#   info: interesting or useful messages.
+#   debug: messages useful only when debugging the code.  This may
+#          spit out thousands per second.
+#
+# For events of each level, you can choose to crash, report, or ignore.
+# TODO: allow choice based on the facility: e.g. crash on panics from
+#       everything except the cdrom, and only report those.
+#
+# If you are experiencing many panics, it can be helpful to change
+# the panic action to report instead of fatal.  However, be aware
+# that anything executed after a panic is uncharted territory and can 
+# cause bochs to become unstable.  The panic is a "graceful exit," so
+# if you disable it you may get a spectacular disaster instead.
+#=======================================================================
+panic: action=ask
+error: action=report
+info: action=report
+debug: action=ignore
+#pass: action=fatal
+
+#=======================================================================
+# DEBUGGER_LOG:
+# Give the path of the log file you'd like Bochs to log debugger output.
+# If you really don't want it, make it /dev/null or '-'. :^(
+#
+# Examples:
+#   debugger_log: ./debugger.out
+#=======================================================================
+#debugger_log: /dev/null
+#debugger_log: debugger.out
+debugger_log: -
+
+#=======================================================================
+# COM1, COM2, COM3, COM4:
+# This defines a serial port (UART type 16550A). In the 'term' you can specify
+# a device to use as com1. This can be a real serial line, or a pty.  To use
+# a pty (under X/Unix), create two windows (xterms, usually).  One of them will
+# run bochs, and the other will act as com1. Find out the tty the com1
+# window using the `tty' command, and use that as the `dev' parameter.
+# Then do `sleep 1000000' in the com1 window to keep the shell from
+# messing with things, and run bochs in the other window.  Serial I/O to
+# com1 (port 0x3f8) will all go to the other window.
+# Other serial modes are 'null' (no input/output), 'file' (output to a file
+# specified as the 'dev' parameter), 'raw' (use the real serial port - under
+# construction for win32), 'mouse' (standard serial mouse - requires
+# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket'
+# (connect a networking socket).
+#
+# Examples:
+#   com1: enabled=1, mode=null
+#   com1: enabled=1, mode=mouse
+#   com2: enabled=1, mode=file, dev=serial.out
+#   com3: enabled=1, mode=raw, dev=com1
+#   com3: enabled=1, mode=socket, dev=localhost:8888
+#=======================================================================
+#com1: enabled=1, mode=term, dev=/dev/ttyp9
+
+
+#=======================================================================
+# PARPORT1, PARPORT2:
+# This defines a parallel (printer) port. When turned on and an output file is
+# defined the emulated printer port sends characters printed by the guest OS
+# into the output file. On some platforms a device filename can be used to
+# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
+# win32 platforms).
+#
+# Examples:
+#   parport1: enabled=1, file="parport.out"
+#   parport2: enabled=1, file="/dev/lp0"
+#   parport1: enabled=0
+#=======================================================================
+parport1: enabled=1, file="parport.out"
+
+#=======================================================================
+# SB16:
+# This defines the SB16 sound emulation. It can have several of the
+# following properties.
+# All properties are in the format sb16: property=value
+# midi: The filename is where the midi data is sent. This can be a
+#       device or just a file if you want to record the midi data.
+# midimode:
+#      0=no data
+#      1=output to device (system dependent. midi denotes the device driver)
+#      2=SMF file output, including headers
+#      3=output the midi data stream to the file (no midi headers and no
+#        delta times, just command and data bytes)
+# wave: This is the device/file where wave output is stored
+# wavemode:
+#      0=no data
+#      1=output to device (system dependent. wave denotes the device driver)
+#      2=VOC file output, incl. headers
+#      3=output the raw wave stream to the file
+# log:  The file to write the sb16 emulator messages to.
+# loglevel:
+#      0=no log
+#      1=resource changes, midi program and bank changes
+#      2=severe errors
+#      3=all errors
+#      4=all errors plus all port accesses
+#      5=all errors and port accesses plus a lot of extra info
+# dmatimer:
+#      microseconds per second for a DMA cycle.  Make it smaller to fix
+#      non-continuous sound.  750000 is usually a good value.  This needs a
+#      reasonably correct setting for the IPS parameter of the CPU option.
+#
+# For an example look at the next line:
+#=======================================================================
+
+#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
+
+#=======================================================================
+# VGA_UPDATE_INTERVAL:
+# Video memory is scanned for updates and screen updated every so many
+# virtual seconds.  The default is 40000, about 25Hz. Keep in mind that
+# you must tweak the 'cpu: ips=N' directive to be as close to the number
+# of emulated instructions-per-second your workstation can do, for this
+# to be accurate.
+#
+# Examples:
+#   vga_update_interval: 250000
+#=======================================================================
+vga_update_interval: 300000
+
+# using for Winstone '98 tests
+#vga_update_interval:  100000
+
+#=======================================================================
+# KEYBOARD_SERIAL_DELAY:
+# Approximate time in microseconds that it takes one character to
+# be transfered from the keyboard to controller over the serial path.
+# Examples:
+#   keyboard_serial_delay: 200
+#=======================================================================
+keyboard_serial_delay: 250
+
+#=======================================================================
+# KEYBOARD_PASTE_DELAY:
+# Approximate time in microseconds between attempts to paste
+# characters to the keyboard controller. This leaves time for the
+# guest os to deal with the flow of characters.  The ideal setting
+# depends on how your operating system processes characters.  The
+# default of 100000 usec (.1 seconds) was chosen because it works 
+# consistently in Windows.
+#
+# If your OS is losing characters during a paste, increase the paste
+# delay until it stops losing characters.
+#
+# Examples:
+#   keyboard_paste_delay: 100000
+#=======================================================================
+keyboard_paste_delay: 100000
+
+#=======================================================================
+# MOUSE: 
+# This option prevents Bochs from creating mouse "events" unless a mouse
+# is  enabled. The hardware emulation itself is not disabled by this.
+# You can turn the mouse on by setting enabled to 1, or turn it off by
+# setting enabled to 0. Unless you have a particular reason for enabling
+# the mouse by default, it is recommended that you leave it off.
+# You can also toggle the mouse usage at runtime (control key + middle
+# mouse button on X11, SDL, wxWidgets and Win32).
+# With the mouse type option you can select the type of mouse to emulate.
+# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
+# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
+# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
+# connected with the 'mouse' device - requires PCI and USB support).
+#
+# Examples:
+#   mouse: enabled=1
+#   mouse: enabled=1, type=imps2
+#   mouse: enabled=1, type=serial
+#   mouse: enabled=0
+#=======================================================================
+mouse: enabled=0
+
+#=======================================================================
+# private_colormap: Request that the GUI create and use it's own
+#                   non-shared colormap.  This colormap will be used
+#                   when in the bochs window.  If not enabled, a
+#                   shared colormap scheme may be used.  Not implemented
+#                   on all GUI's.
+#
+# Examples:
+#   private_colormap: enabled=1
+#   private_colormap: enabled=0
+#=======================================================================
+private_colormap: enabled=0
+
+#=======================================================================
+# fullscreen: ONLY IMPLEMENTED ON AMIGA
+#             Request that Bochs occupy the entire screen instead of a 
+#             window.
+#
+# Examples:
+#   fullscreen: enabled=0
+#   fullscreen: enabled=1
+#=======================================================================
+#fullscreen: enabled=0
+#screenmode: name="sample"
+
+#=======================================================================
+# ne2k: NE2000 compatible ethernet adapter
+#
+# Examples:
+# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+#
+# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
+# are IRQ conflicts.
+#
+# mac: The MAC address MUST NOT match the address of any machine on the net.
+# Also, the first byte must be an even number (bit 0 set means a multicast
+# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
+# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
+# be other restrictions too.  To be safe, just use the b0:c4... address.
+#
+# ethdev: The ethdev value is the name of the network interface on your host
+# platform.  On UNIX machines, you can get the name by running ifconfig.  On
+# Windows machines, you must run niclist to get the name of the ethdev.
+# Niclist source code is in misc/niclist.c and it is included in Windows 
+# binary releases.
+#
+# script: The script value is optional, and is the name of a script that 
+# is executed after bochs initialize the network interface. You can use 
+# this script to configure this network interface, or enable masquerading.
+# This is mainly useful for the tun/tap devices that only exist during
+# Bochs execution. The network interface name is supplied to the script
+# as first parameter
+#
+# If you don't want to make connections to any physical networks,
+# you can use the following 'ethmod's to simulate a virtual network.
+#   null: All packets are discarded, but logged to a few files.
+#   arpback: ARP is simulated. Disabled by default.
+#   vde:  Virtual Distributed Ethernet
+#   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
+#         The virtual host uses 192.168.10.1.
+#         DHCP assigns 192.168.10.2 to the guest.
+#         TFTP uses the ethdev value for the root directory and doesn't
+#         overwrite files.
+#
+#=======================================================================
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
+pnic: mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
+#ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
+
+#=======================================================================
+# KEYBOARD_MAPPING:
+# This enables a remap of a physical localized keyboard to a 
+# virtualized us keyboard, as the PC architecture expects.
+# If enabled, the keymap file must be specified.
+# 
+# Examples:
+#   keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map
+#=======================================================================
+keyboard_mapping: enabled=0, map=
+
+#=======================================================================
+# KEYBOARD_TYPE:
+# Type of keyboard return by a "identify keyboard" command to the
+# keyboard controler. It must be one of "xt", "at" or "mf".
+# Defaults to "mf". It should be ok for almost everybody. A known
+# exception is french macs, that do have a "at"-like keyboard.
+#
+# Examples:
+#   keyboard_type: mf
+#=======================================================================
+#keyboard_type: mf
+
+#=======================================================================
+# USER_SHORTCUT:
+# This defines the keyboard shortcut to be sent when you press the "user"
+# button in the headerbar. The shortcut string is a combination of maximum
+# 3 key names (listed below) separated with a '-' character. The old-style
+# syntax (without the '-') still works for the key combinations supported
+# in Bochs 2.2.1.
+# Valid key names:
+# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
+# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
+# "plus", "right", "shift", "space", "tab", "up", and "win".
+#
+# Example:
+#   user_shortcut: keys=ctrl-alt-del
+#=======================================================================
+user_shortcut: keys=ctrl-alt-del
+
+#=======================================================================
+# I440FXSUPPORT:
+# This option controls the presence of the i440FX PCI chipset. You can
+# also specify the devices connected to PCI slots. Up to 5 slots are
+# available now. These devices are currently supported: ne2k, pcivga,
+# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support
+# you'll have the additional choice 'cirrus'.
+#
+# Example:
+#   i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k
+#=======================================================================
+i440fxsupport: enabled=1, slot1=pcipnic
+#i440fxsupport: enabled=1, slot1=ne2k
+
+#=======================================================================
+# USB1:
+# This option controls the presence of the USB root hub which is a part
+# of the i440FX PCI chipset. With the portX option you can connect devices
+# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
+# the mouse to one of the ports and use the mouse option 'type=usb' you'll
+# have a 3-button USB mouse.
+#
+# Example:
+#   usb1: enabled=1, port1=mouse, port2=keypad
+#=======================================================================
+#usb1: enabled=1
+
+#=======================================================================
+# CMOSIMAGE:
+# This defines image file that can be loaded into the CMOS RAM at startup.
+# The rtc_init parameter controls whether initialize the RTC with values stored
+# in the image. By default the time0 argument given to the clock option is used.
+# With 'rtc_init=image' the image is the source for the initial time.
+#
+# Example:
+#   cmosimage: file=cmos.img, rtc_init=image
+#=======================================================================
+#cmosimage: file=cmos.img, rtc_init=time0
+
+#=======================================================================
+# other stuff
+#=======================================================================
+magic_break: enabled=1
+#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
+#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
+#text_snapshot_check: enable
+
+#-------------------------
+# PCI host device mapping
+#-------------------------
+#pcidev: vendor=0x1234, device=0x5678
+
+#=======================================================================
+# GDBSTUB:
+# Enable GDB stub. See user documentation for details.
+# Default value is enabled=0.
+#=======================================================================
+#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
+
+#=======================================================================
+# IPS:
+# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU
+# directive instead.
+#=======================================================================
+#ips: 10000000
+
+#=======================================================================
+# for Macintosh, use the style of pathnames in the following
+# examples.
+#
+# vgaromimage: :bios:VGABIOS-elpin-2.40
+# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
+# floppya: 1_44=[fd:], status=inserted
+#=======================================================================
diff --git a/bochs/qemu-patch b/bochs/qemu-patch
new file mode 100644 (file)
index 0000000..5fb6c09
--- /dev/null
@@ -0,0 +1,26 @@
+Index: qemu/cpu-exec.c
+===================================================================
+RCS file: /sources/qemu/qemu/cpu-exec.c,v
+retrieving revision 1.84
+diff -u -r1.84 cpu-exec.c
+--- qemu/cpu-exec.c    29 Jul 2006 19:09:31 -0000      1.84
++++ qemu/cpu-exec.c    28 Aug 2006 01:54:15 -0000
+@@ -788,6 +788,18 @@
+                     cpu_loop_exit();
+                 }
+ #endif
++#if 1
++#define MIN_CYCLE_COUNT 100
++              {
++                    static int cycle_count;
++                
++                  if (++cycle_count > MIN_CYCLE_COUNT) {
++                        cycle_count = 0;
++                        env->exception_index = EXCP_INTERRUPT;
++                        cpu_loop_exit();
++                    }
++              }
++#endif
+             }
+         } else {
+             env_to_regs();
diff --git a/bochs/serial-console b/bochs/serial-console
new file mode 100755 (executable)
index 0000000..8cd3835
--- /dev/null
@@ -0,0 +1,278 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+serial-console
+
+=head1 SYNOPSIS
+
+serial-console [options]
+
+Options:
+
+    -h,--help         Display brief help message
+    -v,--verbose      Increase verbosity
+    -q,--quiet        Decrease verbosity
+    -l,--log FILE     Log output to file
+    -r,--rcfile        FILE  Modify specified bochsrc file
+
+=head1 DESCRIPTION
+
+C<serial-console> provides a virtual serial console for use with
+Bochs.  Running C<serial-console> creates a pseudo-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(C<bochsrc.txt>) for use by a subsequent Bochs session.
+
+=head1 EXAMPLES
+
+=over 4
+
+=item C<serial-console>
+
+Create a virtual serial console for Bochs, modify C<bochsrc.txt>
+appropriately.
+
+=item C<serial-console -r ../.bochsrc -l serial.log>
+
+Create a virtual serial console for Bochs, modify C<../.bochsrc>
+appropriately, log output to C<serial.log>.
+
+=back
+
+=head1 INVOCATION
+
+Before starting Bochs, run C<serial-console> in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running C<serial-console>, and anything typed in
+the C<serial-console> window will arrive on the emulated machine's
+serial port.
+
+You do B<not> need to rerun C<serial-console> afresh for each Bochs
+session.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-l,--log FILE>
+
+Log all output (i.e. everything that is printed in the
+C<serial-console> window) to the specified file.
+
+=item B<-r,--rcfile FILE>
+
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when C<serial-console> exits.  The
+default is to modify the file C<bochsrc.txt> in the current directory.
+
+To avoid modifying any bochsrc file, use C<--norcfile>.
+
+=back
+
+=cut
+
+use IO::Pty;
+use IO::Select;
+use File::Spec::Functions qw ( :ALL );
+use Getopt::Long;
+use Pod::Usage;
+use POSIX qw ( :termios_h );
+use strict;
+use warnings;
+
+my $o;
+my $restore_file = {};
+my $restore_termios;
+use constant BLOCKSIZE => 8192;
+
+##############################################################################
+#
+# Parse command line options into options hash ($o)
+#
+# $o = parse_opts();
+
+sub parse_opts {
+  # $o is the hash that will hold the options
+  my $o = {
+    verbosity => 1,
+    rcfile => 'bochsrc.txt',
+  };
+  # Special handlers for some options
+  my $opt_handlers = {
+    verbose => sub { $o->{verbosity}++; },
+    quiet => sub { $o->{verbosity}--; },
+    help => sub { pod2usage(1); },
+    norcfile => sub { delete $o->{rcfile}; },
+  };
+  # Merge handlers into main options hash (so that Getopt::Long can find them)
+  $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
+  # Option specifiers for Getopt::Long
+  my @optspec = ( 'help|h|?',
+                  'quiet|q+',
+                  'verbose|v+',
+                 'log|l=s',
+                 'rcfile|r=s',
+                 'norcfile',
+                  );
+  # Do option parsing
+  Getopt::Long::Configure ( 'bundling' );
+  pod2usage("Error parsing command-line options") unless GetOptions (
+  $o, @optspec );
+  # Clean up $o by removing the handlers
+  delete $o->{$_} foreach keys %$opt_handlers;
+  return $o;
+}
+
+##############################################################################
+#
+# Modify bochsrc file
+
+sub patch_bochsrc {
+  my $active = shift;
+  my $pty = shift;
+
+  # Rename active file to backup file
+  ( my $vol, my $dir, my $file ) = splitpath ( $active );
+  $file = '.'.$file.".serial-console";
+  my $backup = catpath ( $vol, $dir, $file );
+  rename $active, $backup
+      or die "Could not back up $active to $backup: $!\n";
+
+  # Derive line to be inserted
+  my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
+
+  # Modify file
+  open my $old, "<$backup" or die "Could not open $backup: $!\n";
+  open my $new, ">$active" or die "Could not open $active: $!\n";
+  print $new <<"EOF";
+##################################################
+#
+# This file has been modified by serial-console.
+#
+# Do not modify this file; it will be erased when
+# serial-console (pid $$) exits and will be
+# replaced with the backup copy held in
+# $backup.
+#
+##################################################
+
+
+EOF
+  my $patched;
+  while ( my $line = <$old> ) {
+    if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
+      if ( ! $patched ) {
+       $line = $patch;
+       $patched = 1;
+      } else {
+       $line = '# '.$line unless $line =~ /^\s*\#/;
+      }
+    }
+    print $new $line;
+  }
+  print $new $patch unless $patched;
+  close $old;
+  close $new;
+
+  return $backup;
+}
+
+##############################################################################
+#
+# Attach/detach message printing and terminal settings
+
+sub bochs_attached {
+  print STDERR "Bochs attached.\n\n\n"
+      if $o->{verbosity} >= 1;
+}
+
+sub bochs_detached {
+  print STDERR "\n\nWaiting for bochs to attach...\n"
+      if $o->{verbosity} >= 1;
+}
+
+##############################################################################
+#
+# Main program
+
+$o = parse_opts();
+pod2usage(1) if @ARGV;
+
+# Catch signals
+my $sigdie = sub { die "Exiting via signal\n"; };
+$SIG{INT} = $sigdie;
+
+# Create Pty, close slave side
+my $pty = IO::Pty->new();
+$pty->close_slave();
+$pty->set_raw();
+print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
+
+# Open logfile
+my $log;
+if ( $o->{log} ) {
+  open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
+}
+
+# Set up terminal
+my $termios;
+if ( -t STDIN ) {
+  $termios = POSIX::Termios->new;
+  $restore_termios = POSIX::Termios->new;
+  $termios->getattr ( fileno(STDIN) );
+  $restore_termios->getattr ( fileno(STDIN) );
+  $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
+  $termios->setiflag ( $termios->getiflag & ~(ICRNL) );
+  $termios->setattr ( fileno(STDIN), TCSANOW );
+}
+
+# Modify bochsrc file
+$restore_file = { $o->{rcfile} =>
+                 patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
+    if $o->{rcfile};
+
+# Start character shunt
+my $attached = 1;
+my $select = IO::Select->new ( \*STDIN, $pty );
+while ( 1 ) {
+  my %can_read = map { $_ => 1 }
+                    $select->can_read ( $attached ? undef : 1 );
+  if ( $can_read{\*STDIN} ) {
+    sysread ( STDIN, my $data, BLOCKSIZE )
+       or die "Cannot read from STDIN: $!\n";
+    $pty->syswrite ( $data );
+  }
+  if ( $can_read{$pty} ) {
+    if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
+      # Actual data available
+      bochs_attached() if $attached == 0;
+      $attached = 1;
+      syswrite ( STDOUT, $data );
+      $log->syswrite ( $data ) if $log;
+    } else {
+      # No data available but select() says we can read.  This almost
+      # certainly indicates that nothing is attached to the slave.
+      bochs_detached() if $attached == 1;
+      $attached = 0;
+      sleep ( 1 );
+    }
+  } else {
+    bochs_attached() if $attached == 0;
+    $attached = 1;
+  }
+}
+
+END {
+  # Restore bochsrc file if applicable
+  if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
+    unlink $orig_file;
+    rename $backup_file, $orig_file;
+  }
+  # Restore terminal settings if applicable
+  if ( $restore_termios ) {
+    $restore_termios->setattr ( fileno(STDIN), TCSANOW );
+  }
+}
diff --git a/bochs/serial-console.1 b/bochs/serial-console.1
new file mode 100644 (file)
index 0000000..210de55
--- /dev/null
@@ -0,0 +1,191 @@
+.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  | will give a
+.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
+.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
+.\" expand to `' in nroff, nothing in troff, for use with C<>.
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "SERIAL-CONSOLE 1"
+.TH SERIAL-CONSOLE 1 "2004-03-10" "perl v5.8.0" "User Contributed Perl Documentation"
+.SH "NAME"
+serial\-console
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+serial-console [options]
+.PP
+Options:
+.PP
+.Vb 5
+\&    -h,--help         Display brief help message
+\&    -v,--verbose      Increase verbosity
+\&    -q,--quiet        Decrease verbosity
+\&    -l,--log FILE     Log output to file
+\&    -r,--rcfile FILE  Modify specified bochsrc file
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with
+Bochs.  Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo\-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.ie n .IP """serial\-console""" 4
+.el .IP "\f(CWserial\-console\fR" 4
+.IX Item "serial-console"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR
+appropriately.
+.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4
+.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4
+.IX Item "serial-console -r ../.bochsrc -l serial.log"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR
+appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR.
+.SH "INVOCATION"
+.IX Header "INVOCATION"
+Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in
+the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's
+serial port.
+.PP
+You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs
+session.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4
+.IX Item "-l,--log FILE"
+Log all output (i.e. everything that is printed in the
+\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file.
+.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4
+.IX Item "-r,--rcfile FILE"
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits.  The
+default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory.
+.Sp
+To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR.
diff --git a/bochs/tunctl.c b/bochs/tunctl.c
new file mode 100644 (file)
index 0000000..6e43906
--- /dev/null
@@ -0,0 +1,113 @@
+/* Copyright 2002 Jeff Dike
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/if_tun.h>
+
+static void Usage(char *name)
+{
+  fprintf(stderr, "Create: %s [-b] [-u owner] [-t device-name] "
+         "[-f tun-clone-device]\n", name);
+  fprintf(stderr, "Delete: %s -d device-name [-f tun-clone-device]\n\n", 
+         name);
+  fprintf(stderr, "The default tun clone device is /dev/net/tun - some systems"
+         " use\n/dev/misc/net/tun instead\n\n");
+  fprintf(stderr, "-b will result in brief output (just the device name)\n");
+  exit(1);
+}
+
+int main(int argc, char **argv)
+{
+  struct ifreq ifr;
+  struct passwd *pw;
+  long owner = geteuid();
+  int tap_fd, opt, delete = 0, brief = 0;
+  char *tun = "", *file = "/dev/net/tun", *name = argv[0], *end;
+
+  while((opt = getopt(argc, argv, "bd:f:t:u:")) > 0){
+    switch(opt) {
+      case 'b':
+        brief = 1;
+        break;
+      case 'd':
+        delete = 1;
+       tun = optarg;
+        break;
+      case 'f':
+       file = optarg;
+       break;
+      case 'u':
+       pw = getpwnam(optarg);
+       if(pw != NULL){
+         owner = pw->pw_uid;
+         break;
+       }
+        owner = strtol(optarg, &end, 0);
+       if(*end != '\0'){
+         fprintf(stderr, "'%s' is neither a username nor a numeric uid.\n",
+                 optarg);
+         Usage(name);
+       }
+        break;
+      case 't':
+        tun = optarg;
+        break;
+      case 'h':
+      default:
+        Usage(name);
+    }
+  }
+
+  argv += optind;
+  argc -= optind;
+
+  if(argc > 0)
+    Usage(name);
+
+  if((tap_fd = open(file, O_RDWR)) < 0){
+    fprintf(stderr, "Failed to open '%s' : ", file);
+    perror("");
+    exit(1);
+  }
+
+  memset(&ifr, 0, sizeof(ifr));
+
+  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+  strncpy(ifr.ifr_name, tun, sizeof(ifr.ifr_name) - 1);
+  if(ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0){
+    perror("TUNSETIFF");
+    exit(1);
+  }
+
+  if(delete){
+    if(ioctl(tap_fd, TUNSETPERSIST, 0) < 0){
+      perror("TUNSETPERSIST");
+      exit(1);
+    }    
+    printf("Set '%s' nonpersistent\n", ifr.ifr_name);
+  }
+  else {
+    if(ioctl(tap_fd, TUNSETPERSIST, 1) < 0){
+      perror("TUNSETPERSIST");
+      exit(1);
+    }
+    if(ioctl(tap_fd, TUNSETOWNER, owner) < 0){
+      perror("TUNSETPERSIST");
+      exit(1);
+    } 
+    if(brief)
+      printf("%s\n", ifr.ifr_name);
+    else printf("Set '%s' persistent and owned by uid %ld\n", ifr.ifr_name, 
+               owner);
+  }
+  return(0);
+}
diff --git a/bootptodhcp/bootptodhcp.pl b/bootptodhcp/bootptodhcp.pl
new file mode 100755 (executable)
index 0000000..c8d6465
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+#
+# Quick hack to convert /etc/bootptab to format required by ISC DHCPD
+# This only outputs the fixed hosts portion of the config file
+# You still have to provide the global options and the subnet scoping
+#
+# Turn $useipaddr on if you prefer to use IP addresses in the config file
+# I run DNS so I prefer domain names
+$useipaddr = 0;
+# This will be appended to get the FQDN unless the hostname is already FQDN
+$domainname = "ken.com.au";
+$tftpdir = "/tftpdir/";
+open(B, "/etc/bootptab") or die "/etc/bootptab: $!\n";
+while(<B>) {
+       if (/^[^a-z]/) {
+               $prevline = $_;
+               next;
+       }
+       chomp($_);
+       ($hostname, @tags) = split(/:/, $_, 5);
+       ($fqdn = $hostname) .= ".$domainname" unless($hostname =~ /\./);
+       ($macaddr) = grep(/^ha=/, @tags);
+       $macaddr =~ s/ha=//;
+       $macaddr =~ s/(..)(..)(..)(..)(..)(..)/$1:$2:$3:$4:$5:$6/g;
+       ($ipaddr) = grep(/^ip=/, @tags);
+       $ipaddr =~ s/ip=//;
+       ($bootfile) = grep(/^bf=/, @tags);
+       $bootfile =~ s/bf=//;
+       $bootfile = $tftpdir . $bootfile;
+# I have a comment line above most entries and I like to carry this over
+       print $prevline if ($prevline =~ /^#/);
+       $address = $useipaddr ? $ipaddr : $fqdn;
+       print <<EOF
+       host $hostname {
+               hardware ethernet $macaddr;
+               fixed-address $address;
+               filename "$bootfile";
+       }
+EOF
+;
+       $prevline = $_;
+}
diff --git a/compressor/COPYING b/compressor/COPYING
new file mode 100644 (file)
index 0000000..e574f7c
--- /dev/null
@@ -0,0 +1,23 @@
+The compression code as implemented in "lzhuf.c" was taken from a BBS
+program written by Joachim Schurig <jschurig@zedat.fu-berlin.de>. He
+states that the code can be used freely for programs that are covered
+by a "freeware" license. This probably includes both BSD style
+licenses and the GPL.
+
+The code in "loader.asm" is a reimplementation of the uncompressor. It
+has been written from scratch and is hereby placed under the
+conditions of the GNU General Public License (GPL). The algorithm is
+outlined in "algorithm.doc".
+
+Thus, there are no copyright problems with using this code, but there
+still might be difficulties with software patents. These patents are
+not legal in most parts of the world, but if you live in a country
+that honors software patents then you should verify that using these
+algorithms is legally permitted. Unless you are absolutely sure, that
+there are no legal obstacles, you should use the code for educational
+purposes only (this assumes that your educational institution is
+exempted from patent laws). The author cannot be held responsible for
+using the program code in violation of applicable local laws.
+
+If you are aware of patents that might affect the legality of using
+the code in some parts of the world, please let me know.
diff --git a/compressor/algorithm.doc b/compressor/algorithm.doc
new file mode 100644 (file)
index 0000000..74a7646
--- /dev/null
@@ -0,0 +1,58 @@
+The  compressor achieves  an  average compression  rate of 60%  of the
+original size which is on par with "gzip". It seems that you cannot do
+much better for compressing  compiled  binaries.  This means that  the
+break even  point  for using compressed  images is   reached, once the
+uncompressed size approaches 1.5kB. We  can stuff more than 12kB  into
+an 8kB EPROM and more than 25kB into an 16kB EPROM.   As there is only
+32kB of RAM  for both the uncompressed  image  and its BSS  area, this
+means that 32kB EPROMs will hardly ever be required.
+
+The compression  algorithm uses a  4kB  ring buffer  for buffering the
+uncompressed data. Before   compression starts,  the  ring buffer   is
+filled  with spaces (ASCII  character  0x20).  The algorithm tries  to
+find repeated  input sequences of a  maximum length of  60 bytes.  All
+256 different input  bytes  plus the 58 (60   minus a threshold of  2)
+possible  repeat lengths form a set  of 314 symbols. These symbols are
+adaptively Huffman encoded.  The  algorithm starts out with a Huffmann
+tree  that  assigns equal code lengths    to each of  the  314 symbols
+(slightly favoring the repeat  symbols over symbols for regular  input
+characters), but  it will be changed whenever  the frequency of any of
+the symbols  changes. Frequency counts are  kept in 16bit  words until
+the total number of compressed codes totals 2^15.  Then, all frequency
+counts will be halfed (rounding to the bigger number).  For unrepeated
+characters (symbols 0..255) the Huffman code  is written to the output
+stream.  For repeated characters the  Huffmann code, which denotes the
+length of the repeated character sequence, is written out and then the
+index in the ring buffer is computed.   From this index, the algorithm
+computes  the offset   relative to  the current  index  into  the ring
+buffer. Thus,  for typical input data,  one would expect that short to
+medium range offsets are more frequent  than extremely short or medium
+range to long range offsets. Thus the  12bit (for a 4kB buffer) offset
+value  is statically Huffman encoded  using a precomputed Huffman tree
+that favors  those  offset  values    that  are deemed to   be    more
+frequent. The  Huffman encoded offset  is  written to the output  data
+stream,  directly  following the code  that   determines the length of
+repeated characters.
+
+This algorithm, as implemented in the  C example code, looks very good
+and  its operating parameters are   already well optimized. This  also
+explains   why  it achieves     compression ratios    comparable  with
+"gzip". Depending on the input data, it sometimes excells considerably
+beyond what "gzip -9" does, but this  phenomenon does not appear to be
+typical. There are some flaws with  the algorithm, such as the limited
+buffer  sizes, the  adaptive  Huffman tree  which takes  very  long to
+change, if    the input  characters  experience   a sudden   change in
+distribution, and the static Huffman   tree for encoding offsets  into
+the  buffer.   The slow  changes of   the  adaptive  Huffman  tree are
+partially counteracted by  artifically keeping  a 16bit precision  for
+the frequency counts, but  this does not  come into play until 32kB of
+compressed data is output, so  it does not  have any impact on our use
+for "etherboot", because  the BOOT Prom  does not support uncompressed
+data of more then 32kB (c.f. doc/spec.doc).
+
+Nonetheless,  these problems  do  not  seem  to affect  compression of
+compiled  programs very much.  Mixing  object code with English  text,
+would not work too  well though, and  the algorithm should be reset in
+between. Actually, we  might  gain a little  improvement, if  text and
+data   segments    were compressed  individually,    but   I have  not
+experimented with this option, yet.
diff --git a/compressor/loader.h b/compressor/loader.h
new file mode 100644 (file)
index 0000000..20fa9af
--- /dev/null
@@ -0,0 +1,14 @@
+/* Do not change these values unless you really know what you are doing;
+   the pre-computed lookup tables rely on the buffer size being 4kB or
+   smaller. The buffer size must be a power of two. The lookahead size has
+   to fit into 6 bits. If you change any of these numbers, you will also
+   have to adjust the decompressor accordingly.
+ */
+
+#define BUFSZ           4096
+#define LOOKAHEAD       60
+#define THRESHOLD       2
+#define NCHAR           (256+LOOKAHEAD-THRESHOLD)
+#define TABLESZ         (NCHAR+NCHAR-1)
+#define NIL             ((unsigned short)-1)
+
diff --git a/compressor/lzhuf.c b/compressor/lzhuf.c
new file mode 100644 (file)
index 0000000..ea65b5e
--- /dev/null
@@ -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/dhcpdconfeg/dhcpd.conf b/dhcpdconfeg/dhcpd.conf
new file mode 100644 (file)
index 0000000..4d13e0f
--- /dev/null
@@ -0,0 +1,16 @@
+This is an example of using vendor tags in DHCPD config, supplied by
+Bernd Wiebelt.
+
+
+subnet 10.97.0.0 netmask 255.255.0.0 {
+       range 10.97.0.2 10.97.0.254;
+       option option-128  e4:45:74:68:0:0;
+       option option-160 "default=193";
+       option option-184  "HALLO";
+               option option-192 "Linux:::linux.tagged:";
+       option option-193 "DOS Bootdisk:::dosboot.tagged";
+       option option-194 "RH61 Bootdisk:::boot.tagged";
+       option option-195 "Local Disk:::/dev/hda:85b103482a20682da703aa388933a6d8";
+}
+
+
diff --git a/dhcpdconfeg/vendorclassid.txt b/dhcpdconfeg/vendorclassid.txt
new file mode 100644 (file)
index 0000000..7b1f391
--- /dev/null
@@ -0,0 +1,140 @@
+From: Dax Kelson
+To: Etherboot users list
+Subject: [Etherboot-users] Example ISC DHCP v3 dhcpd.conf using conditional operations
+Date: Wed, 13 Jun 2001 20:22:21 -0600
+
+Hopefully someone will find this useful.  I spent a long time tracking
+down and figuring out all the pieces.  To the powers that be, feel free to
+stick this in contrib if you like it.
+
+Goal:  Use the vendor-class-identifier and ISC DHCP v3 "match" option to
+conditionally send proper options only when the DHCP discover/request from
+etherboot comes in.  We use static-MAC-to-IP mappings for classroom
+computers, and dynamic dhcp ranges for other clients (student laptops,
+etc).
+
+I used Etherboot 5.0.1 and the patch (required) in this email:
+
+http://www.geocrawler.com/lists/3/SourceForge/5299/0/5952625/
+
+Furture versions of Etherboot will likely already have this patch
+included.
+
+Dax Kelson
+Guru Labs
+
+######### Begin ISC DHCP v3 dhcpd.conf #############
+
+ddns-update-style ad-hoc;
+
+# Global default, can be overridden
+filename "/exports/kickstart/class1-rh7.1.ks";
+
+# Define options for Etherboot
+# There are more, these are just the ones I'm using
+option ebootmagic code 128 = string;
+option cmdline code 129 = string;
+option menudflts code 160 = string;
+option menuline1 code 192 = string;
+option menuline2 code 193 = string;
+option menuline3 code 194 = string;
+option menuline4 code 195 = string;
+option menuline5 code 196 = string;
+option menuline6 code 197 = string;
+option menuline7 code 198 = string;
+option menuline8 code 199 = string;
+option menuline9 code 200 = string;
+option menuline10 code 201 = string;
+option menuline11 code 202 = string;
+option menuline12 code 203 = string;
+option menuline13 code 204 = string;
+option menuline14 code 205 = string;
+option menuline15 code 206 = string;
+option menuline16 code 207 = string;
+option motdline1 code 184 = string;
+
+class "Etherboot" {
+    match if substring (option vendor-class-identifier, 0, 9) = "Etherboot";
+
+        option ebootmagic  = E4:45:74:68:00:00;
+
+# We don't use this here, because different menu items require
+# different cmdlines.  In our ".nbi" files we specify the cmdlines
+
+#        option cmdline  = "ks initrd=initrd.img lang= devfs=nomount";
+
+        option motdline1  = "Welcome to Guru Labs classroom";
+
+        option menudflts  = "timeout=30:default=192";
+
+        option menuline1  = "Boot from Hard Drive (Default):::/dev/hda:::";
+        option menuline2  = "Boot from Floppy:::/dev/fd0:::";
+        option menuline3  = "Boot from CDROM::::::";
+        option menuline4  = "Kickstart install Red Hat 7.1:::rh71-ks-etherboot.nbi:::";
+        option menuline5  = "Red Hat 7.1 network rescue:::rh71-rescue-etherboot.nbi:::";
+        option menuline6  = "Boot Win98SE startup floppy:::win98se-startupdisk.nbi:::";
+        option menuline7  = "Jumpstart install Solaris 8 (not working yet):::/dev/hda:::";
+        option menuline8  = "Install Windows 98 SE (not working yet):::/dev/hda:::";
+        option menuline9  = "Install Windows 2000 (not working yet):::/dev/hda:::";
+        option menuline10  = "Install FreeBSD 4.3 (not working yet):::/dev/hda:::";
+        option menuline11  = "Install OpenBSD 2.9 (not working yet):::/dev/hda:::";
+
+       # This is a hidden menu item, it should be password protected too
+        option menuline12  = "^[[3D^[[K^[[1A^M:::/dev/hda:::";
+
+# We are using the menu, with different bootfiles.  So we don't use this.
+# If you weren't using a menu, you could use this override the global
+# default "filename" setting.
+
+#        filename "rh71-ks-etherboot";
+
+# Use the following if etherboot compiled with -DREQUIRE_VCI_ETHERBOOT
+
+        option vendor-encapsulated-options 3c:09:45:74:68:65:72:62:6f:6f:74:ff;
+
+}
+
+subnet 10.100.0.0 netmask 255.255.255.0 {
+        authoritative;
+        option routers                  10.100.0.254;
+        option subnet-mask              255.255.255.0;
+        option domain-name              "example.com";
+        option domain-name-servers      10.100.0.254;
+        option time-offset              -7; # US/Mountain
+        option ntp-servers              10.100.0.254;
+        range dynamic-bootp 10.100.0.175 10.100.0.250;
+        default-lease-time 21600;
+        max-lease-time 43200;
+        option netbios-name-servers     10.100.0.254;
+        option netbios-node-type 2;
+        use-host-decl-names on;
+        next-server server1.example.com;
+
+}
+
+host station1 {
+        hardware ethernet 00:01:03:de:57:e2;
+        fixed-address 10.100.0.1;
+}
+host station2 {
+        hardware ethernet 00:01:03:de:57:e7;
+        fixed-address 10.100.0.2;
+}
+host station3 {
+        hardware ethernet 00:01:03:de:57:b4;
+        fixed-address 10.100.0.3;
+}
+host station4 {
+        hardware ethernet 00:01:03:de:57:38;
+        fixed-address 10.100.0.4;
+}
+host station5 {
+        hardware ethernet 00:01:03:de:58:3d;
+        fixed-address 10.100.0.5;
+}
+
+#
+# Etc, etc
+#
+
+############## End ISC DHCP v3 dhcpd.conf #############
diff --git a/dhcpid/dhcpid.txt b/dhcpid/dhcpid.txt
new file mode 100644 (file)
index 0000000..e6b5d27
--- /dev/null
@@ -0,0 +1,884 @@
+From daniel@insu.com Thu Apr 27 14:14:55 2000
+Sender: root@iNsu.COM
+Message-ID: <39075669.FAEB20F2@insu.com>
+Date: Wed, 26 Apr 2000 16:49:45 -0400
+From: Daniel Shane <daniel@insu.com>
+X-Mailer: Mozilla 4.72 [en] (X11; U; Linux 2.2.14-5.0 i686)
+X-Accept-Language: en
+MIME-Version: 1.0
+Subject: Re: New feature added to etherboot
+References: <20000425170804.6677127D8A@Goffman.iNsu.COM>
+Content-Type: multipart/mixed;
+ boundary="------------4734FDA0BF2F2FBDF8EB8DF6"
+
+This is a multi-part message in MIME format.
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Ok, here is a diff for etherboot 4.6.0 that adds identifiers.
+
+To test this you need to use a class in the dhcpd.conf file and
+also send back a string in option 208.
+
+These identifiers prevent a client from booting from other DHCP
+servers when you have more than 1 in your network.
+
+In will also prevent any client, except the valid ones, to use this
+DHCP server.
+
+Here is a subset of my dhcpd.conf :
+
+option iNdiskless-state code 208 = text;
+
+class "iNdiskless-boot" {
+    match if substring(option iNdiskless-state,0,4) = "BOOT";
+}
+class "iNdiskless-setup" {
+    match if substring(option iNdiskless-state,0,5) = "SETUP";
+}           
+
+subnet 10.4.1.0 netmask 255.255.255.0 {
+pool {
+  allow members of "iNdiskless-boot";
+  deny unknown clients;
+  range 10.4.1.2 10.4.1.200;
+  next-server 10.4.1.1;
+
+# Identify ourselves to the etherboot/DHCP client
+  option iNdiskless-state       "BOOT"; 
+
+  host labo01 {
+       hardware ethernet 00:80:c8:ec:04:1b;
+     }
+  host labo02 {
+       hardware ethernet 00:4f:4c:04:45:d6;
+     }
+  host labo03 {
+       hardware ethernet 00:50:ba:c8:db:d6;
+  }
+}
+pool {
+  allow members of "iNdiskless-setup";
+  range 10.4.1.201 10.4.1.254;
+  option iNdiskless-state       "SETUP";
+
+# send another kernel to setup the diskless workstation
+  }
+}    
+
+Daniel Shane.
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="main.c.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="main.c.diff"
+
+--- etherboot-4.6.0/src/main.c Tue Apr 25 08:30:01 2000
++++ etherboot-4.5.6-new/src/main.c     Wed Apr 26 16:17:09 2000
+@@ -42,6 +42,23 @@ char        *motd[RFC1533_VENDOR_NUMOFMOTD];
+ #ifdef        IMAGE_FREEBSD
+ int freebsd_howto = 0;
+ #endif
++
++#ifdef SERVER_IDENT 
++#ifdef DEFAULT_SERVER_IDENT
++char server_ident[9] = DEFAULT_SERVER_IDENT;
++#else
++char server_ident[9] = {};
++#endif   
++#endif
++
++#ifdef CLIENT_IDENT 
++#ifdef DEFAULT_CLIENT_IDENT
++char client_ident[9] = DEFAULT_CLIENT_IDENT;
++#else
++char client_ident[9] = {};
++#endif
++#endif
++
+ int     vendorext_isvalid;
+ char  config_buffer[TFTP_MAX_PACKET+1];       /* +1 for null byte */
+ unsigned long netmask;
+@@ -63,61 +80,85 @@ char    rfc1533_cookie[5] = { RFC1533_CO
+ char    rfc1533_cookie[] = { RFC1533_COOKIE};
+ char    rfc1533_end[]={RFC1533_END };
+ static const char dhcpdiscover[]={
+-              RFC2132_MSG_TYPE,1,DHCPDISCOVER,
+-              RFC2132_MAX_SIZE,2,2,64,
+-              RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY,
+-              RFC1533_HOSTNAME,RFC1533_EXTENSIONPATH
+-      };
+-static const char dhcprequest []={
+-              RFC2132_MSG_TYPE,1,DHCPREQUEST,
+-              RFC2132_SRV_ID,4,0,0,0,0,
+-              RFC2132_REQ_ADDR,4,0,0,0,0,
+-              RFC2132_MAX_SIZE,2,2,64,
+-              /* request parameters */
+-              RFC2132_PARAM_LIST,
+-#ifdef        IMAGE_FREEBSD
+-              /* 4 standard + 4 vendortags + 8 motd + 16 menu items */
+-              4 + 4 + 8 + 16,
++      RFC2132_MSG_TYPE,1,DHCPDISCOVER,
++      RFC2132_MAX_SIZE,2,2,64,
++#ifdef CLIENT_IDENT 
++      RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0,
++#endif
++      RFC2132_PARAM_LIST,
++#ifdef SERVER_IDENT 
++      5,
+ #else
+-              /* 4 standard + 3 vendortags + 8 motd + 16 menu items */
+-              4 + 3 + 8 + 16,
++      4,
+ #endif
+-              /* Standard parameters */
+-              RFC1533_NETMASK, RFC1533_GATEWAY,
+-              RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
+-              /* Etherboot vendortags */
+-              RFC1533_VENDOR_MAGIC,
++#ifdef SERVER_IDENT 
++      RFC1533_VENDOR_SERVER_IDENT,   
++#endif
++      RFC1533_NETMASK,
++      RFC1533_GATEWAY,
++      RFC1533_HOSTNAME,
++      RFC1533_EXTENSIONPATH
++};
++static const char dhcprequest []={
++      RFC2132_MSG_TYPE,1,DHCPREQUEST,
++      RFC2132_SRV_ID,4,0,0,0,0,
++      RFC2132_REQ_ADDR,4,0,0,0,0,
++#ifdef CLIENT_IDENT 
++      RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0,
++#endif
++      RFC2132_MAX_SIZE,2,2,64,
++      /* request parameters */
++      RFC2132_PARAM_LIST,
++      /* 4 standard + 3 vendortags + 8 motd + 16 menu items */
++      4 + 
++      3 + 
++#ifdef  IMAGE_FREEBSD
++      1 + /* One more vendortags for VENDOR_HOWTO */
++#endif
++#ifdef SERVER_IDENT 
++      1 + /* One more vendortags for VENDOR_SERVER_IDENT */
++#endif
++      8 + 
++      16,
++      /* Standard parameters */
++      RFC1533_NETMASK, RFC1533_GATEWAY,
++      RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
++      /* Etherboot vendortags */
++      RFC1533_VENDOR_MAGIC,
+ #ifdef        IMAGE_FREEBSD
+-              RFC1533_VENDOR_HOWTO,
++      RFC1533_VENDOR_HOWTO,
+ #endif
+-              RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
+-              /* 8 MOTD entries */
+-              RFC1533_VENDOR_MOTD,
+-              RFC1533_VENDOR_MOTD+1,
+-              RFC1533_VENDOR_MOTD+2,
+-              RFC1533_VENDOR_MOTD+3,
+-              RFC1533_VENDOR_MOTD+4,
+-              RFC1533_VENDOR_MOTD+5,
+-              RFC1533_VENDOR_MOTD+6,
+-              RFC1533_VENDOR_MOTD+7,
+-              /* 16 image entries */
+-              RFC1533_VENDOR_IMG,
+-              RFC1533_VENDOR_IMG+1,
+-              RFC1533_VENDOR_IMG+2,
+-              RFC1533_VENDOR_IMG+3,
+-              RFC1533_VENDOR_IMG+4,
+-              RFC1533_VENDOR_IMG+5,
+-              RFC1533_VENDOR_IMG+6,
+-              RFC1533_VENDOR_IMG+7,
+-              RFC1533_VENDOR_IMG+8,
+-              RFC1533_VENDOR_IMG+9,
+-              RFC1533_VENDOR_IMG+10,
+-              RFC1533_VENDOR_IMG+11,
+-              RFC1533_VENDOR_IMG+12,
+-              RFC1533_VENDOR_IMG+13,
+-              RFC1533_VENDOR_IMG+14,
+-              RFC1533_VENDOR_IMG+15,
+-      };
++#ifdef SERVER_IDENT
++      RFC1533_VENDOR_SERVER_IDENT,
++#endif
++      RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
++      /* 8 MOTD entries */
++      RFC1533_VENDOR_MOTD,
++      RFC1533_VENDOR_MOTD+1,
++      RFC1533_VENDOR_MOTD+2,
++      RFC1533_VENDOR_MOTD+3,
++      RFC1533_VENDOR_MOTD+4,
++      RFC1533_VENDOR_MOTD+5,
++      RFC1533_VENDOR_MOTD+6,
++      RFC1533_VENDOR_MOTD+7,
++      /* 16 image entries */
++      RFC1533_VENDOR_IMG,
++      RFC1533_VENDOR_IMG+1,
++      RFC1533_VENDOR_IMG+2,
++      RFC1533_VENDOR_IMG+3,
++      RFC1533_VENDOR_IMG+4,
++      RFC1533_VENDOR_IMG+5,
++      RFC1533_VENDOR_IMG+6,
++      RFC1533_VENDOR_IMG+7,
++      RFC1533_VENDOR_IMG+8,
++      RFC1533_VENDOR_IMG+9,
++      RFC1533_VENDOR_IMG+10,
++      RFC1533_VENDOR_IMG+11,
++      RFC1533_VENDOR_IMG+12,
++      RFC1533_VENDOR_IMG+13,
++      RFC1533_VENDOR_IMG+14,
++      RFC1533_VENDOR_IMG+15,
++};
+ #endif        /* NO_DHCP_SUPPORT */
+ static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+@@ -176,6 +217,55 @@ done:
+                       break;
+       }
+ #endif
++
++#ifdef SHIFTED_IDENT_INPUT
++      if (getshift() & 3)
++              {
++#endif
++      
++#ifdef  CLIENT_IDENT
++#   ifdef ASK_CLIENT_IDENT
++                      {
++                              char tmp_ident[9] = {};
++#      ifdef  DEFAULT_CLIENT_IDENT
++                              printf("Enter the client identifier (8 char max.) default [%s] : ",client_ident);
++#      else
++                              printf("Enter the client identifier (8 char max.) : ");
++#      endif
++                              getstr(tmp_ident,8);
++                              if (strlen(tmp_ident) != 0)
++                                      memcpy(client_ident,tmp_ident,8);
++                              else
++                                      printf("%s",client_ident);
++                              putchar('\n');
++                      }
++#   endif
++#endif
++
++#ifdef  SERVER_IDENT
++#   ifdef ASK_SERVER_IDENT
++                      {
++                              char tmp_ident[9] = {};
++#      ifdef  DEFAULT_SERVER_IDENT
++                              printf("Enter the server identifier (8 char max.) default [%s] : ",server_ident);
++#      else
++                              printf("Enter the server identifier (8 char max.) : ");
++#      endif
++                              getstr(tmp_ident,8);
++                              if (strlen(tmp_ident) != 0)
++                                      memcpy(server_ident,tmp_ident,8);
++                              else
++                                      printf("%s",server_ident);
++                              putchar('\n');
++                      }
++#   endif
++#endif
++
++#ifdef SHIFTED_IDENT_INPUT
++              }
++#endif
++
++      print_config();
+ #if   (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY)
+       disk_init();
+       printf("Trying floppy");
+@@ -188,7 +278,7 @@ done:
+       }
+       printf("no floppy\n");
+ #endif        /* TRY_FLOPPY_FIRST && FLOPPY */
+-      print_config();
++        print_config();
+       gateA20_set();
+ #ifdef        EMERGENCYDISKBOOT
+       if (!eth_probe()) {
+@@ -663,6 +753,8 @@ BOOTP - Get my IP address and load infor
+ int bootp()
+ {
+       int retry;
++        int offset = 0;
++
+ #ifndef       NO_DHCP_SUPPORT
+       int retry1;
+ #endif        /* NO_DHCP_SUPPORT */
+@@ -680,11 +772,18 @@ int bootp()
+       bp.bp_xid = xid = starttime = currticks();
+       memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+ #ifdef        NO_DHCP_SUPPORT
+-      memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */
++      memcpy(bp.bp_vend+offset, rfc1533_cookie, 5); /* request RFC-style options */
++      offset += sizeof rfc1533_cookie;
+ #else
+-      memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
+-      memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover);
+-      memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end);
++      memcpy(bp.bp_vend+offset, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
++      offset += sizeof rfc1533_cookie;        
++      memcpy(bp.bp_vend+offset, dhcpdiscover, sizeof dhcpdiscover);
++      offset += sizeof dhcpdiscover;
++#ifdef CLIENT_IDENT 
++      memcpy(bp.bp_vend+13, client_ident, strlen(client_ident));
++#endif
++      memcpy(bp.bp_vend+offset, rfc1533_end, sizeof rfc1533_end);
++      offset += sizeof rfc1533_end;
+ #endif        /* NO_DHCP_SUPPORT */
+       for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
+@@ -715,19 +814,22 @@ int bootp()
+ #else
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){
+                       if (dhcp_reply==DHCPOFFER){
+-              dhcp_reply=0;
+-              memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
+-              memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
+-              memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
+-              memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
+-              memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
+-                      for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
+-                      udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
+-                              sizeof(struct bootp_t), &bp);
+                               dhcp_reply=0;
+-                              if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+-                                      if (dhcp_reply==DHCPACK)
+-                                              return(1);
++                              memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
++                              memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
++                              memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
++                              memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
++                              memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
++#ifdef CLIENT_IDENT
++                              memcpy(bp.bp_vend+21, client_ident, strlen(client_ident));
++#endif
++                              for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
++                                      udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
++                                                   sizeof(struct bootp_t), &bp);
++                                      dhcp_reply=0;
++                                      if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
++                                              if (dhcp_reply==DHCPACK)
++                                                      return(1);
+                                       rfc951_sleep(++retry1);
+                               }
+                       } else
+@@ -750,6 +852,7 @@ AWAIT_REPLY - Wait until we get a respon
+ **************************************************************************/
+ int await_reply(int type, int ival, void *ptr, int timeout)
+ {
++      int result;
+       unsigned long time;
+       struct  iphdr *ip;
+       struct  udphdr *udp;
+@@ -757,6 +860,7 @@ int await_reply(int type, int ival, void
+       struct  bootp_t *bootpreply;
+       struct  rpc_t *rpc;
+       unsigned short ptype;
++      unsigned int min_packetlen;
+       unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
+                               sizeof(struct udphdr);
+@@ -766,35 +870,35 @@ int await_reply(int type, int ival, void
+        * needs a negligible amount of time.  */
+       for (;;) {
+               if (eth_poll()) {       /* We have something! */
+-                                      /* Check for ARP - No IP hdr */
++                      /* Check for ARP - No IP hdr */
+                       if (nic.packetlen >= ETHER_HDR_SIZE) {
+                               ptype = ((unsigned short) nic.packet[12]) << 8
+                                       | ((unsigned short) nic.packet[13]);
+                       } else continue; /* what else could we do with it? */
+                       if ((nic.packetlen >= ETHER_HDR_SIZE +
+-                              sizeof(struct arprequest)) &&
+-                         (ptype == ARP) ) {
++                           sizeof(struct arprequest)) &&
++                          (ptype == ARP) ) {
+                               unsigned long tmp;
+-
++                              
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
+-                                 !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
+-                                 (type == AWAIT_ARP)) {
++                                  !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
++                                  (type == AWAIT_ARP)) {
+                                       memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       return(1);
+                               }
+                               memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                               if ((arpreply->opcode == ntohs(ARP_REQUEST)) &&
+-                                      (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
++                                  (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
+                                       arpreply->opcode = htons(ARP_REPLY);
+                                       memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                                       eth_transmit(arpreply->thwaddr, ARP,
+-                                              sizeof(struct  arprequest),
+-                                              arpreply);
++                                                   sizeof(struct  arprequest),
++                                                   arpreply);
+ #ifdef        MDEBUG
+                                       memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                                       printf("Sent ARP reply to: %I\n",tmp);
+@@ -802,20 +906,20 @@ int await_reply(int type, int ival, void
+                               }
+                               continue;
+                       }
+-
++                      
+                       if (type == AWAIT_QDRAIN) {
+                               continue;
+                       }
+-
+-                                      /* Check for RARP - No IP hdr */
++                      
++                      /* Check for RARP - No IP hdr */
+                       if ((type == AWAIT_RARP) &&
+-                         (nic.packetlen >= ETHER_HDR_SIZE +
+-                              sizeof(struct arprequest)) &&
+-                         (ptype == RARP)) {
++                          (nic.packetlen >= ETHER_HDR_SIZE +
++                           sizeof(struct arprequest)) &&
++                          (ptype == RARP)) {
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(RARP_REPLY)) &&
+-                                 !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
++                                  !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
+                                       memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
+@@ -823,64 +927,72 @@ int await_reply(int type, int ival, void
+                               }
+                               continue;
+                       }
+-
+-                                      /* Anything else has IP header */
++                      
++                      /* Anything else has IP header */
+                       if ((nic.packetlen < protohdrlen) ||
+-                         (ptype != IP) ) continue;
++                          (ptype != IP) ) continue;
+                       ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((ip->verhdrlen != 0x45) ||
+-                              ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
+-                              (ip->protocol != IP_UDP)) continue;
++                          ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
++                          (ip->protocol != IP_UDP)) continue;
+                       udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE +
+-                              sizeof(struct iphdr)];
+-
+-                                      /* BOOTP ? */
++                                                        sizeof(struct iphdr)];
++                      
++                      /* BOOTP ? */
+                       bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE];
+-                      if ((type == AWAIT_BOOTP) &&
+-                         (nic.packetlen >= (ETHER_HDR_SIZE +
+-#ifdef        NO_DHCP_SUPPORT
+-                           sizeof(struct bootp_t))) &&
++#ifdef  NO_DHCP_SUPPORT
++                      min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t);
+ #else
+-                           sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
+-#endif        /* NO_DHCP_SUPPORT */
+-                         (ntohs(udp->dest) == BOOTP_CLIENT) &&
+-                         (bootpreply->bp_op == BOOTP_REPLY) &&
+-                         (bootpreply->bp_xid == xid)) {
+-                              arptable[ARP_CLIENT].ipaddr.s_addr =
+-                                      bootpreply->bp_yiaddr.s_addr;
++                      min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t) - DHCP_OPT_LEN;
++#endif
++                      if (
++                          (type == AWAIT_BOOTP) &&
++                          (nic.packetlen >= min_packetlen) &&
++                          (ntohs(udp->dest) == BOOTP_CLIENT) &&
++                          (bootpreply->bp_op == BOOTP_REPLY) &&
++                          (bootpreply->bp_xid == xid)
++                          ) {
++                              arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
+ #ifndef       NO_DHCP_SUPPORT
+                               dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
+ #endif        /* NO_DHCP_SUPPORT */
+                               netmask = default_netmask();
+-                              arptable[ARP_SERVER].ipaddr.s_addr =
+-                                      bootpreply->bp_siaddr.s_addr;
++                              arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
+                               memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+-                              arptable[ARP_GATEWAY].ipaddr.s_addr =
+-                                      bootpreply->bp_giaddr.s_addr;
++                              arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
+                               memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               if (bootpreply->bp_file[0]) {
+                                       memcpy(kernel_buf, bootpreply->bp_file, 128);
+                                       kernel = kernel_buf;
+                               }
+                               memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
+-                              decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
+-#ifdef        NO_DHCP_SUPPORT
+-                                             0, BOOTP_VENDOR_LEN +
+-                                             MAX_BOOTP_EXTLEN, 1);
+-#else
+-                                             0, DHCP_OPT_LEN, 1);
+-#endif        /* NO_DHCP_SUPPORT */
+-                              return(1);
++#ifdef  NO_DHCP_SUPPORT
++                              if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
++                                                 0, BOOTP_VENDOR_LEN +
++                                                 MAX_BOOTP_EXTLEN, 1)) {
++                                      return(1);
++                              }
++                              else {
++                                      continue;
++                              }
++#else 
++                              if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
++                                                 0, DHCP_OPT_LEN, 1)) {
++                                      return(1);
++                              }
++                              else {
++                                      continue;
++                              }
+                       }
+-
++#endif        /* NO_DHCP_SUPPORT */
+ #ifdef        DOWNLOAD_PROTO_TFTP
+-                                      /* TFTP ? */
++                      /* TFTP ? */
+                       if ((type == AWAIT_TFTP) &&
+-                              (ntohs(udp->dest) == ival)) return(1);
++                          (ntohs(udp->dest) == ival)) return(1);
+ #endif        /* DOWNLOAD_PROTO_TFTP */
+-
++                      
+ #ifdef        DOWNLOAD_PROTO_NFS
+-                                      /* RPC ? */
++                      /* RPC ? */
+                       rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_RPC) &&
+                           (ntohs(udp->dest) == ival) &&
+@@ -889,19 +1001,19 @@ int await_reply(int type, int ival, void
+                               return (1);
+                       }
+ #endif        /* DOWNLOAD_PROTO_NFS */
+-
++                      
+               } else {
+-                      /* Check for abort key only if the Rx queue is empty -
+-                       * as long as we have something to process, don't
+-                       * assume that something failed.  It is unlikely that
+-                       * we have no processing time left between packets.  */
++                              /* Check for abort key only if the Rx queue is empty -
++                               * as long as we have something to process, don't
++                               * assume that something failed.  It is unlikely that
++                               * we have no processing time left between packets.  */
+                       if (iskey() && (getchar() == ESC))
+ #ifdef        EMERGENCYDISKBOOT
+                               exit(0);
+ #else
+-                              longjmp(jmp_bootmenu,1);
++                      longjmp(jmp_bootmenu,1);
+ #endif
+-                      /* Do the timeout after at least a full queue walk.  */
++                              /* Do the timeout after at least a full queue walk.  */
+                       if ((timeout == 0) || (currticks() > time)) {
+