aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--gpxe/COPYING339
-rw-r--r--gpxe/COPYRIGHTS26
-rw-r--r--gpxe/LOG12
-rw-r--r--gpxe/README53
-rw-r--r--gpxe/VERSION1
-rw-r--r--gpxe/contrib/3c90xutil/Makefile9
-rw-r--r--gpxe/contrib/3c90xutil/README31
-rw-r--r--gpxe/contrib/3c90xutil/bromutil.c169
-rw-r--r--gpxe/contrib/3c90xutil/cromutil.c103
-rw-r--r--gpxe/contrib/3c90xutil/romutil.txt36
-rw-r--r--gpxe/contrib/Diskless-From-NT/Config.txt537
-rw-r--r--gpxe/contrib/Diskless-From-NT/Diskless-From-NT.txt565
-rw-r--r--gpxe/contrib/Diskless-From-NT/furtmayr.html82
-rw-r--r--gpxe/contrib/auto-default/mail40
-rw-r--r--gpxe/contrib/auto-default/main.c.patch55
-rw-r--r--gpxe/contrib/award_plugin_roms/README2
-rwxr-xr-xgpxe/contrib/award_plugin_roms/award_plugin_roms.pl341
-rw-r--r--gpxe/contrib/baremetal/Makefile475
-rw-r--r--gpxe/contrib/baremetal/main.c1119
-rw-r--r--gpxe/contrib/baremetal/marini.txt52
-rw-r--r--gpxe/contrib/baremetal/misc.c351
-rw-r--r--gpxe/contrib/baremetal/startmpcc.S756
-rw-r--r--gpxe/contrib/bin2intelhex/Makefile9
-rw-r--r--gpxe/contrib/bin2intelhex/bin2intelhex.c148
-rw-r--r--gpxe/contrib/bin2intelhex/bin2intelhex.c.simple74
-rw-r--r--gpxe/contrib/bochs/.gitignore7
-rw-r--r--gpxe/contrib/bochs/Makefile10
-rw-r--r--gpxe/contrib/bochs/README94
-rw-r--r--gpxe/contrib/bochs/README.qemu87
-rw-r--r--gpxe/contrib/bochs/README.windows-ris31
-rw-r--r--gpxe/contrib/bochs/bochsrc.txt750
-rw-r--r--gpxe/contrib/bochs/qemu-patch26
-rwxr-xr-xgpxe/contrib/bochs/serial-console278
-rw-r--r--gpxe/contrib/bochs/serial-console.1191
-rw-r--r--gpxe/contrib/bochs/tunctl.c113
-rwxr-xr-xgpxe/contrib/bootptodhcp/bootptodhcp.pl42
-rw-r--r--gpxe/contrib/compressor/COPYING23
-rw-r--r--gpxe/contrib/compressor/algorithm.doc58
-rw-r--r--gpxe/contrib/compressor/loader.h14
-rw-r--r--gpxe/contrib/compressor/lzhuf.c764
-rw-r--r--gpxe/contrib/dhcpdconfeg/dhcpd.conf16
-rw-r--r--gpxe/contrib/dhcpdconfeg/vendorclassid.txt140
-rw-r--r--gpxe/contrib/dhcpid/dhcpid.txt884
-rw-r--r--gpxe/contrib/eepro100notes/flash-1.txt73
-rw-r--r--gpxe/contrib/eepro100notes/flash-2.txt149
-rw-r--r--gpxe/contrib/eepro100notes/flash-3.txt57
-rw-r--r--gpxe/contrib/flashimg/Makefile29
-rw-r--r--gpxe/contrib/flashimg/flashimg.asm497
-rw-r--r--gpxe/contrib/flashimg/flashimg.imgbin0 -> 1856 bytes
-rw-r--r--gpxe/contrib/hdload/Makefile15
-rw-r--r--gpxe/contrib/hdload/hdload.S162
-rw-r--r--gpxe/contrib/hdload/petr.msg175
-rw-r--r--gpxe/contrib/initrd/ChangeLog46
-rw-r--r--gpxe/contrib/initrd/Makefile187
-rw-r--r--gpxe/contrib/initrd/Manifest15
-rw-r--r--gpxe/contrib/initrd/README37
-rw-r--r--gpxe/contrib/initrd/dhcpd.conf.etherboot.include207
-rwxr-xr-xgpxe/contrib/initrd/include-modules63
-rw-r--r--gpxe/contrib/initrd/linux-wlan.cfg7
-rw-r--r--gpxe/contrib/initrd/linuxrc76
-rwxr-xr-xgpxe/contrib/initrd/mkinitrd-net165
-rw-r--r--gpxe/contrib/initrd/mkinitrd-net.spec112
-rwxr-xr-xgpxe/contrib/initrd/mknbi-set200
-rw-r--r--gpxe/contrib/initrd/mknbi-set.conf27
-rw-r--r--gpxe/contrib/initrd/script.c.patch11
-rw-r--r--gpxe/contrib/initrd/udhcpc-post25
-rw-r--r--gpxe/contrib/linux-2.0-transname.lsm93
-rw-r--r--gpxe/contrib/linux-3c503-patch/3c503.patch24
-rw-r--r--gpxe/contrib/linux-3c503-patch/README7
-rw-r--r--gpxe/contrib/mini-slamd/COPYING339
-rw-r--r--gpxe/contrib/mini-slamd/Makefile8
-rw-r--r--gpxe/contrib/mini-slamd/mini-slamd.c521
-rw-r--r--gpxe/contrib/mkQNXnbi/Makefile10
-rw-r--r--gpxe/contrib/mkQNXnbi/README36
-rw-r--r--gpxe/contrib/mkQNXnbi/examples/bootptab29
-rw-r--r--gpxe/contrib/mkQNXnbi/examples/ws.etherboot22
-rw-r--r--gpxe/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly22
-rw-r--r--gpxe/contrib/mkQNXnbi/mkQNXnbi.c196
-rwxr-xr-xgpxe/contrib/mkffwnb/2.0.10/linuxrc76
-rw-r--r--gpxe/contrib/mkffwnb/Extendinitrd.pm43
-rw-r--r--gpxe/contrib/mkffwnb/README69
-rwxr-xr-xgpxe/contrib/mkffwnb/mkffwnb.pl226
-rw-r--r--gpxe/contrib/mklrpnb/README.txt4
-rw-r--r--gpxe/contrib/mklrpnb/extractdach.pl191
-rwxr-xr-xgpxe/contrib/mklrpnb/mklrpnb45
-rwxr-xr-xgpxe/contrib/mntnbi/mntnbi.pl97
-rw-r--r--gpxe/contrib/nfs-swap/README2
-rw-r--r--gpxe/contrib/p910nd-0.8/Makefile10
-rwxr-xr-xgpxe/contrib/p910nd-0.8/banner.pl9
-rwxr-xr-xgpxe/contrib/p910nd-0.8/client.pl58
-rw-r--r--gpxe/contrib/p910nd-0.8/p910nd.893
-rw-r--r--gpxe/contrib/p910nd-0.8/p910nd.c420
-rwxr-xr-xgpxe/contrib/p910nd-0.8/p910nd.sh39
-rw-r--r--gpxe/contrib/ppmtoansi/Makefile67
-rw-r--r--gpxe/contrib/ppmtoansi/demo/dos.ansi1
-rw-r--r--gpxe/contrib/ppmtoansi/demo/dos.ppm51
-rw-r--r--gpxe/contrib/ppmtoansi/demo/dos.xpm29
-rw-r--r--gpxe/contrib/ppmtoansi/demo/etherboot.ansibin0 -> 1005 bytes
-rw-r--r--gpxe/contrib/ppmtoansi/demo/etherboot.ppm99
-rw-r--r--gpxe/contrib/ppmtoansi/demo/etherboot.xpm27
-rw-r--r--gpxe/contrib/ppmtoansi/demo/flash.ansi1
-rw-r--r--gpxe/contrib/ppmtoansi/demo/flash.ppm35
-rw-r--r--gpxe/contrib/ppmtoansi/demo/flash.xpm25
-rw-r--r--gpxe/contrib/ppmtoansi/demo/floppy.ansi1
-rw-r--r--gpxe/contrib/ppmtoansi/demo/floppy.ppm51
-rw-r--r--gpxe/contrib/ppmtoansi/demo/floppy.xpm29
-rw-r--r--gpxe/contrib/ppmtoansi/demo/hd.ansibin0 -> 213 bytes
-rw-r--r--gpxe/contrib/ppmtoansi/demo/hd.ppm51
-rw-r--r--gpxe/contrib/ppmtoansi/demo/hd.xpm30
-rw-r--r--gpxe/contrib/ppmtoansi/demo/ibmmap.ppm11
-rw-r--r--gpxe/contrib/ppmtoansi/demo/ibmmap.xpm16
-rw-r--r--gpxe/contrib/ppmtoansi/demo/linux-logo.ansibin0 -> 1490 bytes
-rw-r--r--gpxe/contrib/ppmtoansi/demo/linux-logo.ppm552
-rw-r--r--gpxe/contrib/ppmtoansi/demo/linux-logo.xpm73
-rwxr-xr-xgpxe/contrib/ppmtoansi/demo/make-ansi.sh17
-rw-r--r--gpxe/contrib/ppmtoansi/demo/text.ansibin0 -> 200 bytes
-rw-r--r--gpxe/contrib/ppmtoansi/demo/text.ppm51
-rw-r--r--gpxe/contrib/ppmtoansi/demo/text.xpm28
-rw-r--r--gpxe/contrib/ppmtoansi/demo/x.ansi1
-rw-r--r--gpxe/contrib/ppmtoansi/demo/x.ppm51
-rw-r--r--gpxe/contrib/ppmtoansi/demo/x.xpm25
-rw-r--r--gpxe/contrib/ppmtoansi/ppmtoansi.c235
-rw-r--r--gpxe/contrib/ppmtoansi/ppmtoansi.man120
-rw-r--r--gpxe/contrib/rom-scan/Makefile64
-rw-r--r--gpxe/contrib/rom-scan/rom-scan.c115
-rw-r--r--gpxe/contrib/romid/pktdrv.bat84
-rw-r--r--gpxe/contrib/romid/readme8
-rw-r--r--gpxe/contrib/romid/romid.c124
-rw-r--r--gpxe/contrib/romid/setenvs.c200
-rw-r--r--gpxe/contrib/smc9462tx-flash/Makefile20
-rw-r--r--gpxe/contrib/smc9462tx-flash/README24
-rw-r--r--gpxe/contrib/smc9462tx-flash/dp83820_write.c310
-rw-r--r--gpxe/contrib/smc9462tx-flash/dp83820flash.c152
-rw-r--r--gpxe/contrib/t2hproxy/README95
-rw-r--r--gpxe/contrib/t2hproxy/T2hproxy.java508
-rw-r--r--gpxe/contrib/t2hproxy/build.xml19
-rwxr-xr-xgpxe/contrib/t2hproxy/runT2proxy.sh15
-rwxr-xr-xgpxe/contrib/t2hproxy/t2hproxy.pl174
-rw-r--r--gpxe/contrib/t2hproxy/t2hproxy.xinetd29
-rw-r--r--gpxe/contrib/tftp/Makefile56
-rw-r--r--gpxe/contrib/tftp/README28
-rw-r--r--gpxe/contrib/tftp/arpa/tftp.h80
-rw-r--r--gpxe/contrib/tftp/main.c684
-rw-r--r--gpxe/contrib/tftp/tftp.1159
-rw-r--r--gpxe/contrib/tftp/tftp.c536
-rw-r--r--gpxe/contrib/tftp/tftpd.875
-rw-r--r--gpxe/contrib/tftp/tftpd.c742
-rw-r--r--gpxe/contrib/tftp/tftpsubs.c260
-rw-r--r--gpxe/contrib/tomsrtbt/tomsrtbt-net.txt37
-rw-r--r--gpxe/contrib/wakeonlan/README40
-rw-r--r--gpxe/contrib/wakeonlan/wol.c108
-rw-r--r--gpxe/contrib/wakeonlan/wol.h12
-rw-r--r--gpxe/src/.gitignore4
-rw-r--r--gpxe/src/Config386
-rw-r--r--gpxe/src/Makefile191
-rw-r--r--gpxe/src/Makefile.housekeeping603
-rw-r--r--gpxe/src/README.cvs65
-rw-r--r--gpxe/src/README.pixify90
-rw-r--r--gpxe/src/arch/i386/Config148
-rw-r--r--gpxe/src/arch/i386/Makefile107
-rw-r--r--gpxe/src/arch/i386/README.i386197
-rw-r--r--gpxe/src/arch/i386/core/aout_loader.c144
-rw-r--r--gpxe/src/arch/i386/core/basemem_packet.c30
-rw-r--r--gpxe/src/arch/i386/core/cpu.c73
-rw-r--r--gpxe/src/arch/i386/core/etherboot.prefix.lds100
-rw-r--r--gpxe/src/arch/i386/core/freebsd_loader.c377
-rw-r--r--gpxe/src/arch/i386/core/gdbsym.c33
-rw-r--r--gpxe/src/arch/i386/core/i386_string.c63
-rw-r--r--gpxe/src/arch/i386/core/i386_timer.c89
-rw-r--r--gpxe/src/arch/i386/core/nap.c12
-rw-r--r--gpxe/src/arch/i386/core/nulltrap.c51
-rw-r--r--gpxe/src/arch/i386/core/pcibios.c106
-rw-r--r--gpxe/src/arch/i386/core/pcidirect.c38
-rw-r--r--gpxe/src/arch/i386/core/pic8259.c63
-rw-r--r--gpxe/src/arch/i386/core/prefixudata.lds8
-rw-r--r--gpxe/src/arch/i386/core/prefixzdata.lds8
-rw-r--r--gpxe/src/arch/i386/core/realmode.c23
-rw-r--r--gpxe/src/arch/i386/core/relocate.c163
-rw-r--r--gpxe/src/arch/i386/core/setjmp.S40
-rw-r--r--gpxe/src/arch/i386/core/stack.S13
-rw-r--r--gpxe/src/arch/i386/core/stack16.S13
-rw-r--r--gpxe/src/arch/i386/core/start16.lds8
-rw-r--r--gpxe/src/arch/i386/core/start16z.lds65
-rw-r--r--gpxe/src/arch/i386/core/start32.S325
-rw-r--r--gpxe/src/arch/i386/core/umalloc.c224
-rw-r--r--gpxe/src/arch/i386/core/video_subr.c104
-rw-r--r--gpxe/src/arch/i386/core/virtaddr.S101
-rw-r--r--gpxe/src/arch/i386/core/wince_loader.c273
-rw-r--r--gpxe/src/arch/i386/drivers/net/undi.c146
-rw-r--r--gpxe/src/arch/i386/drivers/net/undiisr.S87
-rw-r--r--gpxe/src/arch/i386/drivers/net/undiload.c170
-rw-r--r--gpxe/src/arch/i386/drivers/net/undinet.c793
-rw-r--r--gpxe/src/arch/i386/drivers/net/undionly.c109
-rw-r--r--gpxe/src/arch/i386/drivers/net/undipreload.c35
-rw-r--r--gpxe/src/arch/i386/drivers/net/undirom.c232
-rw-r--r--gpxe/src/arch/i386/drivers/timer_bios.c57
-rw-r--r--gpxe/src/arch/i386/drivers/timer_rdtsc.c69
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/basemem.c44
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/bios_console.c294
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/e820mangler.S473
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/gateA20.c170
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/hidemem.c156
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/memmap.c221
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/pnpbios.c107
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/smbios.c323
-rw-r--r--gpxe/src/arch/i386/image/bootsector.c112
-rw-r--r--gpxe/src/arch/i386/image/bzimage.c567
-rw-r--r--gpxe/src/arch/i386/image/eltorito.c334
-rw-r--r--gpxe/src/arch/i386/image/multiboot.c445
-rw-r--r--gpxe/src/arch/i386/image/nbi.c458
-rw-r--r--gpxe/src/arch/i386/image/pxe_image.c109
-rw-r--r--gpxe/src/arch/i386/include/basemem.h33
-rw-r--r--gpxe/src/arch/i386/include/basemem_packet.h13
-rw-r--r--gpxe/src/arch/i386/include/bios.h11
-rw-r--r--gpxe/src/arch/i386/include/bios_disks.h69
-rw-r--r--gpxe/src/arch/i386/include/biosint.h18
-rw-r--r--gpxe/src/arch/i386/include/bits/byteswap.h76
-rw-r--r--gpxe/src/arch/i386/include/bits/cpu.h86
-rw-r--r--gpxe/src/arch/i386/include/bits/elf.h91
-rw-r--r--gpxe/src/arch/i386/include/bits/elf_x.h5
-rw-r--r--gpxe/src/arch/i386/include/bits/eltorito.h3
-rw-r--r--gpxe/src/arch/i386/include/bits/endian.h9
-rw-r--r--gpxe/src/arch/i386/include/bits/errfile.h34
-rw-r--r--gpxe/src/arch/i386/include/bits/stdint.h21
-rw-r--r--gpxe/src/arch/i386/include/bits/string.h252
-rw-r--r--gpxe/src/arch/i386/include/bits/timer2.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/uaccess.h6
-rw-r--r--gpxe/src/arch/i386/include/bits/uuid.h10
-rw-r--r--gpxe/src/arch/i386/include/bochs.h34
-rw-r--r--gpxe/src/arch/i386/include/bootsector.h12
-rw-r--r--gpxe/src/arch/i386/include/bzimage.h129
-rw-r--r--gpxe/src/arch/i386/include/callbacks_arch.h243
-rw-r--r--gpxe/src/arch/i386/include/gateA20.h7
-rw-r--r--gpxe/src/arch/i386/include/int13.h277
-rw-r--r--gpxe/src/arch/i386/include/io.h265
-rw-r--r--gpxe/src/arch/i386/include/kir.h18
-rw-r--r--gpxe/src/arch/i386/include/libkir.h233
-rw-r--r--gpxe/src/arch/i386/include/librm.h289
-rw-r--r--gpxe/src/arch/i386/include/limits.h59
-rw-r--r--gpxe/src/arch/i386/include/memsizes.h17
-rw-r--r--gpxe/src/arch/i386/include/multiboot.h147
-rw-r--r--gpxe/src/arch/i386/include/pci_io.h35
-rw-r--r--gpxe/src/arch/i386/include/pcibios.h122
-rw-r--r--gpxe/src/arch/i386/include/pcidirect.h126
-rw-r--r--gpxe/src/arch/i386/include/pic8259.h69
-rw-r--r--gpxe/src/arch/i386/include/pnpbios.h15
-rw-r--r--gpxe/src/arch/i386/include/pxe_addr.h17
-rw-r--r--gpxe/src/arch/i386/include/pxe_call.h34
-rw-r--r--gpxe/src/arch/i386/include/realmode.h128
-rw-r--r--gpxe/src/arch/i386/include/registers.h187
-rw-r--r--gpxe/src/arch/i386/include/setjmp.h12
-rw-r--r--gpxe/src/arch/i386/include/smbios.h51
-rw-r--r--gpxe/src/arch/i386/include/undi.h102
-rw-r--r--gpxe/src/arch/i386/include/undiload.h33
-rw-r--r--gpxe/src/arch/i386/include/undinet.h15
-rw-r--r--gpxe/src/arch/i386/include/undipreload.h16
-rw-r--r--gpxe/src/arch/i386/include/undirom.h51
-rw-r--r--gpxe/src/arch/i386/include/vga.h228
-rw-r--r--gpxe/src/arch/i386/include/virtaddr.h105
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/biosint.c101
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/int13.c653
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_call.c450
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_entry.S195
-rw-r--r--gpxe/src/arch/i386/kir-Makefile26
-rw-r--r--gpxe/src/arch/i386/prefix/bImageprefix.S611
-rw-r--r--gpxe/src/arch/i386/prefix/bootpart.S216
-rw-r--r--gpxe/src/arch/i386/prefix/comprefix.S46
-rw-r--r--gpxe/src/arch/i386/prefix/dskprefix.S375
-rw-r--r--gpxe/src/arch/i386/prefix/elf_dprefix.S94
-rw-r--r--gpxe/src/arch/i386/prefix/elfprefix.S94
-rwxr-xr-xgpxe/src/arch/i386/prefix/exeprefix.S41
-rw-r--r--gpxe/src/arch/i386/prefix/hdprefix.S103
-rw-r--r--gpxe/src/arch/i386/prefix/kpxeprefix.S7
-rw-r--r--gpxe/src/arch/i386/prefix/libprefix.S657
-rw-r--r--gpxe/src/arch/i386/prefix/lkrnprefix.S155
-rw-r--r--gpxe/src/arch/i386/prefix/lmelf_dprefix.S161
-rw-r--r--gpxe/src/arch/i386/prefix/lmelf_prefix.S161
-rw-r--r--gpxe/src/arch/i386/prefix/mbr.S13
-rw-r--r--gpxe/src/arch/i386/prefix/nbiprefix.S76
-rw-r--r--gpxe/src/arch/i386/prefix/nullprefix.S13
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S666
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S383
-rw-r--r--gpxe/src/arch/i386/prefix/unnrv2b.S182
-rw-r--r--gpxe/src/arch/i386/prefix/usbdisk.S23
-rw-r--r--gpxe/src/arch/i386/scripts/i386-kir.lds196
-rw-r--r--gpxe/src/arch/i386/scripts/i386.lds272
-rw-r--r--gpxe/src/arch/i386/transitions/libkir.S254
-rw-r--r--gpxe/src/arch/i386/transitions/libpm.S0
-rw-r--r--gpxe/src/arch/i386/transitions/librm.S559
-rw-r--r--gpxe/src/config.h169
-rw-r--r--gpxe/src/config/.gitignore2
-rw-r--r--gpxe/src/core/abft.c60
-rw-r--r--gpxe/src/core/acpi.c40
-rw-r--r--gpxe/src/core/ansiesc.c114
-rw-r--r--gpxe/src/core/asprintf.c47
-rw-r--r--gpxe/src/core/basename.c62
-rw-r--r--gpxe/src/core/bitmap.c99
-rw-r--r--gpxe/src/core/bitops.c11
-rw-r--r--gpxe/src/core/btext.c5039
-rw-r--r--gpxe/src/core/config.c203
-rw-r--r--gpxe/src/core/console.c137
-rw-r--r--gpxe/src/core/cpio.c40
-rw-r--r--gpxe/src/core/cwuri.c41
-rw-r--r--gpxe/src/core/debug.c195
-rw-r--r--gpxe/src/core/device.c102
-rw-r--r--gpxe/src/core/downloader.c270
-rw-r--r--gpxe/src/core/errno.c18
-rw-r--r--gpxe/src/core/exec.c159
-rw-r--r--gpxe/src/core/filter.c72
-rw-r--r--gpxe/src/core/getkey.c79
-rw-r--r--gpxe/src/core/getopt.c271
-rw-r--r--gpxe/src/core/hw.c74
-rw-r--r--gpxe/src/core/i82365.c656
-rw-r--r--gpxe/src/core/ibft.c341
-rw-r--r--gpxe/src/core/image.c309
-rw-r--r--gpxe/src/core/init.c117
-rw-r--r--gpxe/src/core/interface.c60
-rw-r--r--gpxe/src/core/iobuf.c94
-rw-r--r--gpxe/src/core/job.c87
-rw-r--r--gpxe/src/core/linebuf.c109
-rw-r--r--gpxe/src/core/main.c40
-rw-r--r--gpxe/src/core/malloc.c384
-rw-r--r--gpxe/src/core/misc.c91
-rw-r--r--gpxe/src/core/monojob.c91
-rw-r--r--gpxe/src/core/nvo.c261
-rw-r--r--gpxe/src/core/open.c184
-rw-r--r--gpxe/src/core/pc_kbd.c112
-rw-r--r--gpxe/src/core/pcmcia.c267
-rw-r--r--gpxe/src/core/posix_io.c353
-rw-r--r--gpxe/src/core/process.c102
-rw-r--r--gpxe/src/core/proto_eth_slow.c406
-rw-r--r--gpxe/src/core/random.c39
-rw-r--r--gpxe/src/core/refcnt.c76
-rw-r--r--gpxe/src/core/resolv.c400
-rw-r--r--gpxe/src/core/serial.c268
-rw-r--r--gpxe/src/core/settings.c1037
-rw-r--r--gpxe/src/core/string.c353
-rw-r--r--gpxe/src/core/stringextra.c273
-rw-r--r--gpxe/src/core/timer.c113
-rw-r--r--gpxe/src/core/uri.c383
-rw-r--r--gpxe/src/core/uuid.c48
-rw-r--r--gpxe/src/core/vsprintf.c421
-rw-r--r--gpxe/src/core/xfer.c405
-rw-r--r--gpxe/src/crypto/asn1.c159
-rw-r--r--gpxe/src/crypto/axtls/aes.c478
-rw-r--r--gpxe/src/crypto/axtls/axtls_asn1.c867
-rw-r--r--gpxe/src/crypto/axtls/bigint.c1496
-rw-r--r--gpxe/src/crypto/axtls/bigint.h93
-rw-r--r--gpxe/src/crypto/axtls/bigint_impl.h105
-rw-r--r--gpxe/src/crypto/axtls/crypto.h298
-rw-r--r--gpxe/src/crypto/axtls/os_port.h61
-rw-r--r--gpxe/src/crypto/axtls/rsa.c332
-rw-r--r--gpxe/src/crypto/axtls/sha1.c240
-rw-r--r--gpxe/src/crypto/axtls_aes.c54
-rw-r--r--gpxe/src/crypto/axtls_sha1.c26
-rw-r--r--gpxe/src/crypto/chap.c122
-rw-r--r--gpxe/src/crypto/cipher.c24
-rw-r--r--gpxe/src/crypto/cryptoLayer.h120
-rw-r--r--gpxe/src/crypto/crypto_null.c69
-rw-r--r--gpxe/src/crypto/framework.c86
-rw-r--r--gpxe/src/crypto/hmac.c120
-rw-r--r--gpxe/src/crypto/matrixssl/mpi.h487
-rw-r--r--gpxe/src/crypto/matrixssl/pscrypto.h661
-rw-r--r--gpxe/src/crypto/md5.c235
-rw-r--r--gpxe/src/crypto/ssl.c136
-rw-r--r--gpxe/src/crypto/ssl.h19
-rw-r--r--gpxe/src/crypto/ssl_constructs.h342
-rw-r--r--gpxe/src/doc/build_sys.dox419
-rw-r--r--gpxe/src/doc/pxe_extensions279
-rw-r--r--gpxe/src/doxygen.cfg1245
-rw-r--r--gpxe/src/drivers/bitbash/bitbash.c55
-rw-r--r--gpxe/src/drivers/bitbash/i2c_bit.c322
-rw-r--r--gpxe/src/drivers/bitbash/spi_bit.c196
-rw-r--r--gpxe/src/drivers/block/ata.c159
-rw-r--r--gpxe/src/drivers/block/ramdisk.c91
-rw-r--r--gpxe/src/drivers/block/scsi.c271
-rw-r--r--gpxe/src/drivers/bus/eisa.c185
-rw-r--r--gpxe/src/drivers/bus/isa.c175
-rw-r--r--gpxe/src/drivers/bus/isa_ids.c26
-rw-r--r--gpxe/src/drivers/bus/isapnp.c758
-rw-r--r--gpxe/src/drivers/bus/mca.c180
-rw-r--r--gpxe/src/drivers/bus/pci.c343
-rw-r--r--gpxe/src/drivers/bus/pciextra.c79
-rw-r--r--gpxe/src/drivers/infiniband/MT25218_PRM.h3460
-rw-r--r--gpxe/src/drivers/infiniband/MT25408_PRM.h3313
-rw-r--r--gpxe/src/drivers/infiniband/arbel.c1979
-rw-r--r--gpxe/src/drivers/infiniband/arbel.h468
-rw-r--r--gpxe/src/drivers/infiniband/hermon.c2016
-rw-r--r--gpxe/src/drivers/infiniband/hermon.h466
-rw-r--r--gpxe/src/drivers/infiniband/mlx_bitops.h209
-rw-r--r--gpxe/src/drivers/net/3c509-eisa.c49
-rw-r--r--gpxe/src/drivers/net/3c509.c430
-rw-r--r--gpxe/src/drivers/net/3c509.h392
-rw-r--r--gpxe/src/drivers/net/3c515.c762
-rw-r--r--gpxe/src/drivers/net/3c515.txt31
-rw-r--r--gpxe/src/drivers/net/3c529.c60
-rw-r--r--gpxe/src/drivers/net/3c595.c551
-rw-r--r--gpxe/src/drivers/net/3c595.h435
-rw-r--r--gpxe/src/drivers/net/3c5x9.c414
-rw-r--r--gpxe/src/drivers/net/3c90x.c1027
-rw-r--r--gpxe/src/drivers/net/3c90x.txt307
-rw-r--r--gpxe/src/drivers/net/amd8111e.c691
-rw-r--r--gpxe/src/drivers/net/amd8111e.h629
-rw-r--r--gpxe/src/drivers/net/bnx2.c2695
-rw-r--r--gpxe/src/drivers/net/bnx2.h4704
-rw-r--r--gpxe/src/drivers/net/bnx2_fw.h3494
-rw-r--r--gpxe/src/drivers/net/cs89x0.c737
-rw-r--r--gpxe/src/drivers/net/cs89x0.h479
-rw-r--r--gpxe/src/drivers/net/cs89x0.txt45
-rw-r--r--gpxe/src/drivers/net/davicom.c725
-rw-r--r--gpxe/src/drivers/net/depca.c803
-rw-r--r--gpxe/src/drivers/net/dmfe.c1224
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.c1116
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.h303
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_hw.c9050
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_hw.h3413
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_osdep.h142
-rw-r--r--gpxe/src/drivers/net/eepro.c635
-rw-r--r--gpxe/src/drivers/net/eepro100.c851
-rw-r--r--gpxe/src/drivers/net/epic100.c537
-rw-r--r--gpxe/src/drivers/net/epic100.h188
-rw-r--r--gpxe/src/drivers/net/etherfabric.c3436
-rw-r--r--gpxe/src/drivers/net/etherfabric.h551
-rw-r--r--gpxe/src/drivers/net/forcedeth.c1436
-rw-r--r--gpxe/src/drivers/net/hfa384x.h3067
-rw-r--r--gpxe/src/drivers/net/ipoib.c929
-rw-r--r--gpxe/src/drivers/net/legacy.c152
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/MT23108_PRM.h2800
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/MT23108_PRM_append.h199
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/MT25218_PRM.h3463
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/bit_ops.h126
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif.h50
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif_comm.c564
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif_comm.h60
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif_mt23108.c193
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif_mt25218.c457
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/cmdif_priv.h50
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/doc/README.boot_over_ib176
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_driver.c342
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_driver.h169
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_mad.c396
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_mad.h110
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_mt23108.c1701
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_mt25218.c1929
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ipoib.c1027
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ipoib.h297
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mad_attrib.h244
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt23108.c245
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt23108.h543
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt23108_imp.c229
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt25218.c245
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt25218.h546
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt25218_imp.c229
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/mt_version.c23
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/patches/dhcpd.patch23
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/samples/dhcpd.conf56
-rw-r--r--gpxe/src/drivers/net/mtd80x.c1084
-rwxr-xr-xgpxe/src/drivers/net/mtnic.c1758
-rwxr-xr-xgpxe/src/drivers/net/mtnic.h716
-rw-r--r--gpxe/src/drivers/net/natsemi.c603
-rw-r--r--gpxe/src/drivers/net/natsemi.h230
-rwxr-xr-xgpxe/src/drivers/net/ns83820.c1012
-rw-r--r--gpxe/src/drivers/net/ns8390.c1029
-rw-r--r--gpxe/src/drivers/net/ns8390.h238
-rw-r--r--gpxe/src/drivers/net/p80211hdr.h299
-rw-r--r--gpxe/src/drivers/net/pcnet32.c1025
-rw-r--r--gpxe/src/drivers/net/pnic.c276
-rw-r--r--gpxe/src/drivers/net/pnic_api.h59
-rw-r--r--gpxe/src/drivers/net/prism2.c855
-rw-r--r--gpxe/src/drivers/net/prism2_pci.c59
-rw-r--r--gpxe/src/drivers/net/prism2_plx.c121
-rw-r--r--gpxe/src/drivers/net/r8169.c1184
-rw-r--r--gpxe/src/drivers/net/rtl8139.c583
-rw-r--r--gpxe/src/drivers/net/sis900.c1296
-rw-r--r--gpxe/src/drivers/net/sis900.h373
-rw-r--r--gpxe/src/drivers/net/smc9000.c952
-rw-r--r--gpxe/src/drivers/net/smc9000.h433
-rw-r--r--gpxe/src/drivers/net/sundance.c885
-rw-r--r--gpxe/src/drivers/net/tg3.c3400
-rw-r--r--gpxe/src/drivers/net/tg3.h2211
-rw-r--r--gpxe/src/drivers/net/tlan.c1720
-rw-r--r--gpxe/src/drivers/net/tlan.h524
-rw-r--r--gpxe/src/drivers/net/tulip.c2097
-rw-r--r--gpxe/src/drivers/net/tulip.txt54
-rw-r--r--gpxe/src/drivers/net/via-rhine.c1443
-rw-r--r--gpxe/src/drivers/net/via-velocity.c1939
-rw-r--r--gpxe/src/drivers/net/via-velocity.h1930
-rw-r--r--gpxe/src/drivers/net/w89c840.c962
-rw-r--r--gpxe/src/drivers/net/wlan_compat.h575
-rw-r--r--gpxe/src/drivers/nvs/nvs.c147
-rw-r--r--gpxe/src/drivers/nvs/spi.c138
-rw-r--r--gpxe/src/drivers/nvs/threewire.c88
-rw-r--r--gpxe/src/hci/commands/autoboot_cmd.c25
-rw-r--r--gpxe/src/hci/commands/config_cmd.c37
-rw-r--r--gpxe/src/hci/commands/dhcp_cmd.c108
-rw-r--r--gpxe/src/hci/commands/ifmgmt_cmd.c177
-rw-r--r--gpxe/src/hci/commands/image_cmd.c579
-rw-r--r--gpxe/src/hci/commands/nvo_cmd.c77
-rw-r--r--gpxe/src/hci/commands/route_cmd.c85
-rw-r--r--gpxe/src/hci/commands/sanboot_cmd.c68
-rw-r--r--gpxe/src/hci/editstring.c190
-rw-r--r--gpxe/src/hci/mucurses/alert.c18
-rw-r--r--gpxe/src/hci/mucurses/ansi_screen.c72
-rw-r--r--gpxe/src/hci/mucurses/clear.c88
-rw-r--r--gpxe/src/hci/mucurses/colour.c64
-rw-r--r--gpxe/src/hci/mucurses/cursor.h35
-rw-r--r--gpxe/src/hci/mucurses/edging.c111
-rw-r--r--gpxe/src/hci/mucurses/kb.c143
-rw-r--r--gpxe/src/hci/mucurses/mucurses.c145
-rw-r--r--gpxe/src/hci/mucurses/mucurses.h21
-rw-r--r--gpxe/src/hci/mucurses/print.c84
-rw-r--r--gpxe/src/hci/mucurses/print_nadv.c26
-rw-r--r--gpxe/src/hci/mucurses/slk.c363
-rw-r--r--gpxe/src/hci/mucurses/widgets/editbox.c96
-rw-r--r--gpxe/src/hci/mucurses/winattrs.c131
-rw-r--r--gpxe/src/hci/mucurses/windows.c158
-rw-r--r--gpxe/src/hci/mucurses/wininit.c35
-rw-r--r--gpxe/src/hci/readline.c117
-rw-r--r--gpxe/src/hci/shell.c105
-rw-r--r--gpxe/src/hci/shell_banner.c75
-rw-r--r--gpxe/src/hci/strerror.c121
-rw-r--r--gpxe/src/hci/tui/settings_ui.c427
-rw-r--r--gpxe/src/image/elf.c150
-rw-r--r--gpxe/src/image/embed.S7
-rw-r--r--gpxe/src/image/embedded.c49
-rw-r--r--gpxe/src/image/initrd.c37
-rw-r--r--gpxe/src/image/script.c128
-rw-r--r--gpxe/src/image/segment.c72
-rw-r--r--gpxe/src/include/.gitignore1
-rw-r--r--gpxe/src/include/alloca.h25
-rw-r--r--gpxe/src/include/assert.h65
-rw-r--r--gpxe/src/include/big_bswap.h33
-rw-r--r--gpxe/src/include/bootp.h230
-rw-r--r--gpxe/src/include/btext.h62
-rw-r--r--gpxe/src/include/byteswap.h22
-rw-r--r--gpxe/src/include/cmdline.h8
-rw-r--r--gpxe/src/include/cmdlinelib.h99
-rw-r--r--gpxe/src/include/cmdlist.h18
-rw-r--r--gpxe/src/include/coff.h73
-rw-r--r--gpxe/src/include/compiler.h357
-rw-r--r--gpxe/src/include/console.h114
-rw-r--r--gpxe/src/include/cpu.h6
-rw-r--r--gpxe/src/include/ctype.h28
-rw-r--r--gpxe/src/include/curses.h753
-rw-r--r--gpxe/src/include/debug.h28
-rw-r--r--gpxe/src/include/dhcp.h12
-rw-r--r--gpxe/src/include/elf.h236
-rw-r--r--gpxe/src/include/endian.h19
-rw-r--r--gpxe/src/include/errno.h508
-rw-r--r--gpxe/src/include/etherboot.h42
-rw-r--r--gpxe/src/include/fs.h41
-rw-r--r--gpxe/src/include/getopt.h92
-rw-r--r--gpxe/src/include/gpxe/abft.h35
-rw-r--r--gpxe/src/include/gpxe/acpi.h41
-rw-r--r--gpxe/src/include/gpxe/aes.h8
-rw-r--r--gpxe/src/include/gpxe/ansiesc.h118
-rw-r--r--gpxe/src/include/gpxe/aoe.h126
-rw-r--r--gpxe/src/include/gpxe/arp.h41
-rw-r--r--gpxe/src/include/gpxe/asn1.h32
-rw-r--r--gpxe/src/include/gpxe/async.h228
-rw-r--r--gpxe/src/include/gpxe/ata.h205
-rw-r--r--gpxe/src/include/gpxe/bitbash.h50
-rw-r--r--gpxe/src/include/gpxe/bitmap.h83
-rw-r--r--gpxe/src/include/gpxe/bitops.h27
-rw-r--r--gpxe/src/include/gpxe/blockdev.h43
-rw-r--r--gpxe/src/include/gpxe/chap.h51
-rw-r--r--gpxe/src/include/gpxe/command.h22
-rw-r--r--gpxe/src/include/gpxe/cpio.h51
-rw-r--r--gpxe/src/include/gpxe/crypto.h116
-rw-r--r--gpxe/src/include/gpxe/device.h111
-rw-r--r--gpxe/src/include/gpxe/dhcp.h455
-rw-r--r--gpxe/src/include/gpxe/dhcpopts.h32
-rw-r--r--gpxe/src/include/gpxe/dhcppkt.h35
-rw-r--r--gpxe/src/include/gpxe/dns.h90
-rw-r--r--gpxe/src/include/gpxe/downloader.h17
-rw-r--r--gpxe/src/include/gpxe/editbox.h51
-rw-r--r--gpxe/src/include/gpxe/editstring.h31
-rw-r--r--gpxe/src/include/gpxe/eisa.h125
-rw-r--r--gpxe/src/include/gpxe/elf.h15
-rw-r--r--gpxe/src/include/gpxe/embedded.h9
-rw-r--r--gpxe/src/include/gpxe/errfile.h157
-rw-r--r--gpxe/src/include/gpxe/errortab.h19
-rw-r--r--gpxe/src/include/gpxe/ethernet.h33
-rw-r--r--gpxe/src/include/gpxe/fakedhcp.h21
-rw-r--r--gpxe/src/include/gpxe/features.h88
-rw-r--r--gpxe/src/include/gpxe/filter.h73
-rw-r--r--gpxe/src/include/gpxe/ftp.h13
-rw-r--r--gpxe/src/include/gpxe/hidemem.h23
-rw-r--r--gpxe/src/include/gpxe/hmac.h30
-rw-r--r--gpxe/src/include/gpxe/http.h21
-rw-r--r--gpxe/src/include/gpxe/i2c.h111
-rw-r--r--gpxe/src/include/gpxe/ibft.h300
-rw-r--r--gpxe/src/include/gpxe/icmp6.h57
-rw-r--r--gpxe/src/include/gpxe/if_arp.h100
-rw-r--r--gpxe/src/include/gpxe/if_ether.h33
-rw-r--r--gpxe/src/include/gpxe/image.h162
-rw-r--r--gpxe/src/include/gpxe/in.h94
-rw-r--r--gpxe/src/include/gpxe/infiniband.h751
-rw-r--r--gpxe/src/include/gpxe/init.h62
-rw-r--r--gpxe/src/include/gpxe/initrd.h14
-rw-r--r--gpxe/src/include/gpxe/interface.h56
-rw-r--r--gpxe/src/include/gpxe/iobuf.h189
-rw-r--r--gpxe/src/include/gpxe/ip.h95
-rw-r--r--gpxe/src/include/gpxe/ip6.h78
-rw-r--r--gpxe/src/include/gpxe/ipoib.h78
-rw-r--r--gpxe/src/include/gpxe/isa.h92
-rw-r--r--gpxe/src/include/gpxe/isa_ids.h49
-rw-r--r--gpxe/src/include/gpxe/isapnp.h273
-rw-r--r--gpxe/src/include/gpxe/iscsi.h654
-rw-r--r--gpxe/src/include/gpxe/job.h165
-rw-r--r--gpxe/src/include/gpxe/keys.h82
-rw-r--r--gpxe/src/include/gpxe/linebuf.h28
-rw-r--r--gpxe/src/include/gpxe/linux_compat.h25
-rw-r--r--gpxe/src/include/gpxe/list.h178
-rw-r--r--gpxe/src/include/gpxe/malloc.h57
-rw-r--r--gpxe/src/include/gpxe/mca.h103
-rw-r--r--gpxe/src/include/gpxe/md5.h22
-rw-r--r--gpxe/src/include/gpxe/memmap.h34
-rw-r--r--gpxe/src/include/gpxe/monojob.h15
-rw-r--r--gpxe/src/include/gpxe/ndp.h21
-rw-r--r--gpxe/src/include/gpxe/netdevice.h404
-rw-r--r--gpxe/src/include/gpxe/nvo.h53
-rw-r--r--gpxe/src/include/gpxe/nvs.h66
-rw-r--r--gpxe/src/include/gpxe/open.h95
-rw-r--r--gpxe/src/include/gpxe/pci.h356
-rw-r--r--gpxe/src/include/gpxe/pci_ids.h348
-rw-r--r--gpxe/src/include/gpxe/posix_io.h85
-rw-r--r--gpxe/src/include/gpxe/process.h75
-rw-r--r--gpxe/src/include/gpxe/profile.h78
-rw-r--r--gpxe/src/include/gpxe/ramdisk.h22
-rw-r--r--gpxe/src/include/gpxe/rarp.h14
-rw-r--r--gpxe/src/include/gpxe/refcnt.h44
-rw-r--r--gpxe/src/include/gpxe/resolv.h166
-rw-r--r--gpxe/src/include/gpxe/retry.h52
-rw-r--r--gpxe/src/include/gpxe/rsa.h10
-rw-r--r--gpxe/src/include/gpxe/scsi.h270
-rw-r--r--gpxe/src/include/gpxe/segment.h15
-rw-r--r--gpxe/src/include/gpxe/settings.h285
-rw-r--r--gpxe/src/include/gpxe/settings_ui.h14
-rw-r--r--gpxe/src/include/gpxe/sha1.h13
-rw-r--r--gpxe/src/include/gpxe/shell.h12
-rw-r--r--gpxe/src/include/gpxe/shell_banner.h12
-rw-r--r--gpxe/src/include/gpxe/socket.h95
-rw-r--r--gpxe/src/include/gpxe/spi.h239
-rw-r--r--gpxe/src/include/gpxe/spi_bit.h61
-rw-r--r--gpxe/src/include/gpxe/tables.h229
-rw-r--r--gpxe/src/include/gpxe/tcp.h306
-rw-r--r--gpxe/src/include/gpxe/tcpip.h118
-rw-r--r--gpxe/src/include/gpxe/tftp.h83
-rw-r--r--gpxe/src/include/gpxe/threewire.h89
-rw-r--r--gpxe/src/include/gpxe/timer.h41
-rw-r--r--gpxe/src/include/gpxe/tls.h171
-rw-r--r--gpxe/src/include/gpxe/uaccess.h27
-rw-r--r--gpxe/src/include/gpxe/udp.h47
-rw-r--r--gpxe/src/include/gpxe/umalloc.h17
-rw-r--r--gpxe/src/include/gpxe/uri.h139
-rw-r--r--gpxe/src/include/gpxe/uuid.h34
-rw-r--r--gpxe/src/include/gpxe/vsprintf.h71
-rw-r--r--gpxe/src/include/gpxe/xfer.h275
-rw-r--r--gpxe/src/include/i82365.h450
-rw-r--r--gpxe/src/include/igmp.h42
-rw-r--r--gpxe/src/include/lib.h42
-rw-r--r--gpxe/src/include/libgen.h7
-rw-r--r--gpxe/src/include/little_bswap.h33
-rw-r--r--gpxe/src/include/mii.h105
-rw-r--r--gpxe/src/include/nfs.h63
-rw-r--r--gpxe/src/include/nic.h272
-rw-r--r--gpxe/src/include/nmb.h22
-rw-r--r--gpxe/src/include/old_tcp.h37
-rw-r--r--gpxe/src/include/pc_kbd.h7
-rw-r--r--gpxe/src/include/pcmcia-opts.h23
-rw-r--r--gpxe/src/include/pcmcia.h156
-rw-r--r--gpxe/src/include/pxe.h151
-rw-r--r--gpxe/src/include/pxe_api.h1841
-rw-r--r--gpxe/src/include/pxe_types.h126
-rw-r--r--gpxe/src/include/readline/readline.h12
-rw-r--r--gpxe/src/include/stdarg.h10
-rw-r--r--gpxe/src/include/stddef.h18
-rw-r--r--gpxe/src/include/stdint.h24
-rw-r--r--gpxe/src/include/stdio.h45
-rw-r--r--gpxe/src/include/stdlib.h72
-rw-r--r--gpxe/src/include/string.h49
-rw-r--r--gpxe/src/include/strings.h63
-rw-r--r--gpxe/src/include/sys/time.h20
-rw-r--r--gpxe/src/include/sys_info.h33
-rw-r--r--gpxe/src/include/time.h22
-rw-r--r--gpxe/src/include/unistd.h31
-rw-r--r--gpxe/src/include/usr/aoeboot.h6
-rw-r--r--gpxe/src/include/usr/autoboot.h13
-rw-r--r--gpxe/src/include/usr/dhcpmgmt.h14
-rw-r--r--gpxe/src/include/usr/ifmgmt.h16
-rw-r--r--gpxe/src/include/usr/imgmgmt.h20
-rw-r--r--gpxe/src/include/usr/iscsiboot.h6
-rw-r--r--gpxe/src/include/usr/route.h12
-rw-r--r--gpxe/src/interface/pxe/pxe_errors.c103
-rw-r--r--gpxe/src/interface/pxe/pxe_file.c264
-rw-r--r--gpxe/src/interface/pxe/pxe_loader.c53
-rw-r--r--gpxe/src/interface/pxe/pxe_preboot.c353
-rw-r--r--gpxe/src/interface/pxe/pxe_tftp.c584
-rw-r--r--gpxe/src/interface/pxe/pxe_udp.c390
-rw-r--r--gpxe/src/interface/pxe/pxe_undi.c620
-rw-r--r--gpxe/src/libgcc/__divdi3.c26
-rw-r--r--gpxe/src/libgcc/__moddi3.c26
-rw-r--r--gpxe/src/libgcc/__udivdi3.c10
-rw-r--r--gpxe/src/libgcc/__udivmoddi4.c32
-rw-r--r--gpxe/src/libgcc/__umoddi3.c13
-rw-r--r--gpxe/src/libgcc/libgcc.h26
-rw-r--r--gpxe/src/libgcc/memcpy.c18
-rw-r--r--gpxe/src/net/aoe.c375
-rw-r--r--gpxe/src/net/arp.c294
-rw-r--r--gpxe/src/net/dhcpopts.c434
-rw-r--r--gpxe/src/net/dhcppkt.c172
-rw-r--r--gpxe/src/net/ethernet.c116
-rw-r--r--gpxe/src/net/fakedhcp.c205
-rw-r--r--gpxe/src/net/icmpv6.c128
-rw-r--r--gpxe/src/net/infiniband.c437
-rw-r--r--gpxe/src/net/iobpad.c66
-rw-r--r--gpxe/src/net/ipv4.c633
-rw-r--r--gpxe/src/net/ipv6.c380
-rw-r--r--gpxe/src/net/ndp.c180
-rw-r--r--gpxe/src/net/netdev_settings.c90
-rw-r--r--gpxe/src/net/netdevice.c513
-rw-r--r--gpxe/src/net/nullnet.c58
-rw-r--r--gpxe/src/net/rarp.c68
-rw-r--r--gpxe/src/net/retry.c184
-rw-r--r--gpxe/src/net/tcp.c1073
-rw-r--r--gpxe/src/net/tcp/ftp.c467
-rw-r--r--gpxe/src/net/tcp/http.c534
-rw-r--r--gpxe/src/net/tcp/https.c49
-rw-r--r--gpxe/src/net/tcp/iscsi.c1726
-rw-r--r--gpxe/src/net/tcpip.c145
-rw-r--r--gpxe/src/net/tls.c1731
-rw-r--r--gpxe/src/net/udp.c465
-rw-r--r--gpxe/src/net/udp/dhcp.c825
-rw-r--r--gpxe/src/net/udp/dns.c547
-rw-r--r--gpxe/src/net/udp/tftp.c1149
-rw-r--r--gpxe/src/proto/fsp.c243
-rw-r--r--gpxe/src/proto/igmp.c167
-rw-r--r--gpxe/src/proto/nfs.c616
-rw-r--r--gpxe/src/proto/nmb.c110
-rw-r--r--gpxe/src/proto/slam.c541
-rw-r--r--gpxe/src/tests/linebuf_test.c35
-rw-r--r--gpxe/src/tests/memcpy_test.c39
-rw-r--r--gpxe/src/tests/umalloc_test.c26
-rw-r--r--gpxe/src/tests/uri_test.c145
-rw-r--r--gpxe/src/usr/aoeboot.c73
-rw-r--r--gpxe/src/usr/autoboot.c204
-rw-r--r--gpxe/src/usr/dhcpmgmt.c48
-rw-r--r--gpxe/src/usr/ifmgmt.c69
-rw-r--r--gpxe/src/usr/imgmgmt.c127
-rw-r--r--gpxe/src/usr/iscsiboot.c69
-rw-r--r--gpxe/src/usr/route.c43
-rw-r--r--gpxe/src/util/.gitignore4
-rw-r--r--gpxe/src/util/Makefile22
-rwxr-xr-xgpxe/src/util/catrom.pl48
-rwxr-xr-xgpxe/src/util/disrom.pl114
-rwxr-xr-xgpxe/src/util/dskpad.pl12
-rwxr-xr-xgpxe/src/util/geniso56
-rwxr-xr-xgpxe/src/util/genliso85
-rwxr-xr-xgpxe/src/util/get-pci-ids135
-rw-r--r--gpxe/src/util/hijack.c628
-rwxr-xr-xgpxe/src/util/makerom.pl226
-rwxr-xr-xgpxe/src/util/mkconfig.pl188
-rwxr-xr-xgpxe/src/util/modrom.pl226
-rw-r--r--gpxe/src/util/mucurses_test.c63
-rw-r--r--gpxe/src/util/nrv2b.c1501
-rw-r--r--gpxe/src/util/parserom.pl64
-rwxr-xr-xgpxe/src/util/sortobjdump.pl40
-rwxr-xr-xgpxe/src/util/swapdevids.pl49
-rwxr-xr-xgpxe/src/util/symcheck.pl191
-rw-r--r--gpxe/src/util/zbin.c325
772 files changed, 218909 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 64307604..7e6088a9 100644
--- a/Makefile
+++ b/Makefile
@@ -74,7 +74,7 @@ BINFILES = bootsect_bin.c ldlinux_bin.c mbr_bin.c \
# mingw suite installed
BTARGET = kwdhash.gen version.gen version.h \
ldlinux.bss ldlinux.sys ldlinux.bin \
- pxelinux.0 isolinux.bin isolinux-debug.bin \
+ pxelinux.0 gpxelinux.0 isolinux.bin isolinux-debug.bin \
extlinux.bin extlinux.bss extlinux.sys
BOBJECTS = $(BTARGET) mbr/mbr.bin dos/syslinux.com win32/syslinux.exe \
memdisk/memdisk memdump/memdump.com
@@ -99,7 +99,7 @@ INSTALL_BIN = mtools/syslinux gethostip ppmtolss16 lss16toppm \
# Things to install in /sbin
INSTALL_SBIN = extlinux/extlinux
# Things to install in /usr/lib/syslinux
-INSTALL_AUX = pxelinux.0 isolinux.bin isolinux-debug.bin \
+INSTALL_AUX = pxelinux.0 gpxelinux.0 isolinux.bin isolinux-debug.bin \
dos/syslinux.com copybs.com memdisk/memdisk mbr/mbr.bin
INSTALL_AUX_OPT = win32/syslinux.exe
@@ -161,7 +161,11 @@ iso%.bin: iso%.asm kwdhash.gen version.gen
$(PERL) checkov.pl $(@:.bin=.map) $@
pxelinux.0: pxelinux.bin
- cp pxelinux.bin pxelinux.0
+ cp -f $< $@
+
+gpxelinux.0: pxelinux.0
+ $(MAKE) -C gpxe/src bin/undionly.kpxe
+ cp -f gpxe/src/bin/undionly.kpxe $@
ldlinux.bss: ldlinux.bin
dd if=$< of=$@ bs=512 count=1
@@ -229,6 +233,7 @@ local-tidy:
rm -f *.o *_bin.c stupid.* patch.offset
rm -f *.lsr *.lst *.map
rm -f $(OBSOLETE)
+ $(MAKE) -C gpxe/src veryclean
tidy: local-tidy
set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
diff --git a/gpxe/COPYING b/gpxe/COPYING
new file mode 100644
index 00000000..a43ea212
--- /dev/null
+++ b/gpxe/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gpxe/COPYRIGHTS b/gpxe/COPYRIGHTS
new file mode 100644
index 00000000..d686b435
--- /dev/null
+++ b/gpxe/COPYRIGHTS
@@ -0,0 +1,26 @@
+
+In general gPXE files are licensed under the GPL. GPLed files are in
+general either from Linux or have been explicitly put under GPL by the
+authors. The license for a file is usually documented at the top of
+the file.
+
+A few files are inherited from FreeBSD netboot and therefore can be
+used under BSD or GPL. Documented in this file are some of the
+non-GPL'ed files. If the internal documentation for a file disagrees
+with what is documented in this file, the internal documentation for
+the file shall be override this file.
+
+File Copyright status
+
+src/core/misc.c BSD
+src/drivers/net/3c509.c BSD
+src/drivers/net/3c509.h BSD
+src/drivers/net/3c595.c BSD
+src/drivers/net/3c595.h BSD
+src/drivers/net/3c90x.c Open Source
+src/drivers/net/epic100.c None
+src/drivers/net/epic100.h None
+src/drivers/net/ns8390.c BSD
+src/drivers/net/ns8390.h BSD
+src/arch/i386/include/bits/string.h None
+
diff --git a/gpxe/LOG b/gpxe/LOG
new file mode 100644
index 00000000..d29c8eba
--- /dev/null
+++ b/gpxe/LOG
@@ -0,0 +1,12 @@
+gPXE LOG file
+
++ Development for gPXE was moved from SourceForge CVS to a git
+ repository on git.etherboot.org in the first half of the year 2007.
+
++ The gitweb interface for gPXE is available at:
+
+ http://git.etherboot.org/?p=gpxe.git
+
++ The gitweb interface largely obsoletes the LOG file that used to be
+ distributed with Etherboot.
+
diff --git a/gpxe/README b/gpxe/README
new file mode 100644
index 00000000..b3ae2154
--- /dev/null
+++ b/gpxe/README
@@ -0,0 +1,53 @@
+gPXE README File
+
+gPXE is an implementation of the PXE specification for network
+booting, with extensions to allow additional features such as booting
+via HTTP, iSCSI, and AoE.
+
+In generally, gPXE is compatible with the industry-standard PXE
+specification, and also supports Etherboot .nbi file loading and some
+additional protocols and features.
+
+For more detailed information about gPXE, please visit our project
+website at: http://etherboot.org/
+
+BUILDING gPXE IMAGE FROM SOURCE
+
+If you don't want to install development tools, and have access to the
+Web, you can get gPXE and Etherboot ROM images made on demand from
+http://rom-o-matic.net/
+
+If you would like to compile gPXE images from source, here are some tips.
+
+We normally compile gPXE images on x86, 32-bit Linux machines. It is
+possible to also use x86-64 machines. We use gcc compiler options to
+create 32-bit output.
+
+It is important to have the necessary software packages installed. A gcc-based
+toolchain is required.
+
+The following packages (at least) are required:
+
+ - a gcc tool chain (gcc 3.x or gcc 4.x)
+ - binutils
+ - perl
+ - syslinux
+ - mtools
+
+To test your environment, cd to the "src" directory and type:
+
+ make
+
+You should see a lot of output, and when it stops, the "bin" directory
+should be populated with gPXE images and object files.
+
+To learn more about what to build and how to use gPXE, please visit our
+project website at http://etherboot.org/ , particularly the "howto" section.
+
+CONTACTING US
+
+Pointers to our project mailing lists are on http://etherboot.org/
+
+Real-time help is often available on IRC on the #etherboot channel of
+irc.freenode.net.
+
diff --git a/gpxe/VERSION b/gpxe/VERSION
new file mode 100644
index 00000000..e466de0c
--- /dev/null
+++ b/gpxe/VERSION
@@ -0,0 +1 @@
+0.9.3 2008-02-14
diff --git a/gpxe/contrib/3c90xutil/Makefile b/gpxe/contrib/3c90xutil/Makefile
new file mode 100644
index 00000000..1dd1723f
--- /dev/null
+++ b/gpxe/contrib/3c90xutil/Makefile
@@ -0,0 +1,9 @@
+FILES = cromutil bromutil
+
+INCLUDEDIR = /usr/include
+CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR)
+
+all: $(FILES)
+
+clean:
+ rm -f $(FILES) *~ core
diff --git a/gpxe/contrib/3c90xutil/README b/gpxe/contrib/3c90xutil/README
new file mode 100644
index 00000000..235530f6
--- /dev/null
+++ b/gpxe/contrib/3c90xutil/README
@@ -0,0 +1,31 @@
+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.
+
+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/gpxe/contrib/3c90xutil/bromutil.c b/gpxe/contrib/3c90xutil/bromutil.c
new file mode 100644
index 00000000..a736e5af
--- /dev/null
+++ b/gpxe/contrib/3c90xutil/bromutil.c
@@ -0,0 +1,169 @@
+/*
+ * 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>
+
+#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
+
+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|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], "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/gpxe/contrib/3c90xutil/cromutil.c b/gpxe/contrib/3c90xutil/cromutil.c
new file mode 100644
index 00000000..d4751fbf
--- /dev/null
+++ b/gpxe/contrib/3c90xutil/cromutil.c
@@ -0,0 +1,103 @@
+/*
+ * 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>
+
+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/gpxe/contrib/3c90xutil/romutil.txt b/gpxe/contrib/3c90xutil/romutil.txt
new file mode 100644
index 00000000..58074b9b
--- /dev/null
+++ b/gpxe/contrib/3c90xutil/romutil.txt
@@ -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/gpxe/contrib/Diskless-From-NT/Config.txt b/gpxe/contrib/Diskless-From-NT/Config.txt
new file mode 100644
index 00000000..60385fb7
--- /dev/null
+++ b/gpxe/contrib/Diskless-From-NT/Config.txt
@@ -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/gpxe/contrib/Diskless-From-NT/Diskless-From-NT.txt b/gpxe/contrib/Diskless-From-NT/Diskless-From-NT.txt
new file mode 100644
index 00000000..54c2b746
--- /dev/null
+++ b/gpxe/contrib/Diskless-From-NT/Diskless-From-NT.txt
@@ -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/gpxe/contrib/Diskless-From-NT/furtmayr.html b/gpxe/contrib/Diskless-From-NT/furtmayr.html
new file mode 100644
index 00000000..224632d5
--- /dev/null
+++ b/gpxe/contrib/Diskless-From-NT/furtmayr.html
@@ -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/gpxe/contrib/auto-default/mail b/gpxe/contrib/auto-default/mail
new file mode 100644
index 00000000..015c789a
--- /dev/null
+++ b/gpxe/contrib/auto-default/mail
@@ -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/gpxe/contrib/auto-default/main.c.patch b/gpxe/contrib/auto-default/main.c.patch
new file mode 100644
index 00000000..e707b63a
--- /dev/null
+++ b/gpxe/contrib/auto-default/main.c.patch
@@ -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/gpxe/contrib/award_plugin_roms/README b/gpxe/contrib/award_plugin_roms/README
new file mode 100644
index 00000000..5f657cf5
--- /dev/null
+++ b/gpxe/contrib/award_plugin_roms/README
@@ -0,0 +1,2 @@
+An Award BIOS ROM lister in Perl contributed by Eric W. Biederman
+<ebiederman@lnxi.com>.
diff --git a/gpxe/contrib/award_plugin_roms/award_plugin_roms.pl b/gpxe/contrib/award_plugin_roms/award_plugin_roms.pl
new file mode 100755
index 00000000..2b95eed1
--- /dev/null
+++ b/gpxe/contrib/award_plugin_roms/award_plugin_roms.pl
@@ -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/gpxe/contrib/baremetal/Makefile b/gpxe/contrib/baremetal/Makefile
new file mode 100644
index 00000000..df4de762
--- /dev/null
+++ b/gpxe/contrib/baremetal/Makefile
@@ -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/gpxe/contrib/baremetal/main.c b/gpxe/contrib/baremetal/main.c
new file mode 100644
index 00000000..7b0de44c
--- /dev/null
+++ b/gpxe/contrib/baremetal/main.c
@@ -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/gpxe/contrib/baremetal/marini.txt b/gpxe/contrib/baremetal/marini.txt
new file mode 100644
index 00000000..464f1488
--- /dev/null
+++ b/gpxe/contrib/baremetal/marini.txt
@@ -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/gpxe/contrib/baremetal/misc.c b/gpxe/contrib/baremetal/misc.c
new file mode 100644
index 00000000..924ccd6d
--- /dev/null
+++ b/gpxe/contrib/baremetal/misc.c
@@ -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/gpxe/contrib/baremetal/startmpcc.S b/gpxe/contrib/baremetal/startmpcc.S
new file mode 100644
index 00000000..07486ce5
--- /dev/null
+++ b/gpxe/contrib/baremetal/startmpcc.S
@@ -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/gpxe/contrib/bin2intelhex/Makefile b/gpxe/contrib/bin2intelhex/Makefile
new file mode 100644
index 00000000..74069688
--- /dev/null
+++ b/gpxe/contrib/bin2intelhex/Makefile
@@ -0,0 +1,9 @@
+
+CC=gcc
+CFLAGS=-Wall -O2
+
+bin2intelhex:
+
+
+clean:
+ rm -f bin2intelhex core *.o
diff --git a/gpxe/contrib/bin2intelhex/bin2intelhex.c b/gpxe/contrib/bin2intelhex/bin2intelhex.c
new file mode 100644
index 00000000..75b88c15
--- /dev/null
+++ b/gpxe/contrib/bin2intelhex/bin2intelhex.c
@@ -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/gpxe/contrib/bin2intelhex/bin2intelhex.c.simple b/gpxe/contrib/bin2intelhex/bin2intelhex.c.simple
new file mode 100644
index 00000000..3cb279a7
--- /dev/null
+++ b/gpxe/contrib/bin2intelhex/bin2intelhex.c.simple
@@ -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/gpxe/contrib/bochs/.gitignore b/gpxe/contrib/bochs/.gitignore
new file mode 100644
index 00000000..4e8f81ab
--- /dev/null
+++ b/gpxe/contrib/bochs/.gitignore
@@ -0,0 +1,7 @@
+bochsout.txt
+parport.out
+ne2k-tx.log
+ne2k-txdump.txt
+tunctl
+bochs
+qemu
diff --git a/gpxe/contrib/bochs/Makefile b/gpxe/contrib/bochs/Makefile
new file mode 100644
index 00000000..4a5b14ce
--- /dev/null
+++ b/gpxe/contrib/bochs/Makefile
@@ -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/gpxe/contrib/bochs/README b/gpxe/contrib/bochs/README
new file mode 100644
index 00000000..57c6f052
--- /dev/null
+++ b/gpxe/contrib/bochs/README
@@ -0,0 +1,94 @@
+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-pci --enable-pnic \
+ --enable-debugger --enable-magic-breakpoints \
+ --enable-disasm --enable-show-ips --enable-ne2000
+ 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/gpxe/contrib/bochs/README.qemu b/gpxe/contrib/bochs/README.qemu
new file mode 100644
index 00000000..ee20eec4
--- /dev/null
+++ b/gpxe/contrib/bochs/README.qemu
@@ -0,0 +1,87 @@
+Running Etherboot 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:
+ cvs -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/qemu \
+ login
+ cvs -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/qemu \
+ co qemu
+
+2a. Patch the qemu code. There is currently a bug that causes qemu to
+ execute Etherboot 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 --enable-system
+ popd
+
+ Note that qemu will not compile with gcc4; if your system's
+ default compiler is gcc4 then specify the path to gcc3 using
+ e.g. --cc=gcc-3.3.6
+
+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
+ 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 qemu. If not, then you're on
+ your own.
+
+7. As root, restart dhcpd
+ /etc/init.d/dhcpd restart
+
+8. Build Etherboot floppy disk images and pad to 1.44MB
+ pushd ../../src
+ make bin/rtl8139.pdsk
+ popd
+
+9. Start qemu
+ export SDL_VIDEO_X11_DGAMOUSE=0
+ ./qemu/i386-softmmu/qemu -L qemu/pc-bios \
+ -net nic,model=rtl8139 -net tap,ifname=tap0 \
+ -boot a -fda ../../src/bin/rtl8139.pdsk
+
+You should see qemu 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 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/gpxe/contrib/bochs/README.windows-ris b/gpxe/contrib/bochs/README.windows-ris
new file mode 100644
index 00000000..830db6a8
--- /dev/null
+++ b/gpxe/contrib/bochs/README.windows-ris
@@ -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/gpxe/contrib/bochs/bochsrc.txt b/gpxe/contrib/bochs/bochsrc.txt
new file mode 100644
index 00000000..bf99f4cd
--- /dev/null
+++ b/gpxe/contrib/bochs/bochsrc.txt
@@ -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/gpxe/contrib/bochs/qemu-patch b/gpxe/contrib/bochs/qemu-patch
new file mode 100644
index 00000000..5fb6c09e
--- /dev/null
+++ b/gpxe/contrib/bochs/qemu-patch
@@ -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/gpxe/contrib/bochs/serial-console b/gpxe/contrib/bochs/serial-console
new file mode 100755
index 00000000..cc4fd005
--- /dev/null
+++ b/gpxe/contrib/bochs/serial-console
@@ -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->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/gpxe/contrib/bochs/serial-console.1 b/gpxe/contrib/bochs/serial-console.1
new file mode 100644
index 00000000..210de550
--- /dev/null
+++ b/gpxe/contrib/bochs/serial-console.1
@@ -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/gpxe/contrib/bochs/tunctl.c b/gpxe/contrib/bochs/tunctl.c
new file mode 100644
index 00000000..6e439060
--- /dev/null
+++ b/gpxe/contrib/bochs/tunctl.c
@@ -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/gpxe/contrib/bootptodhcp/bootptodhcp.pl b/gpxe/contrib/bootptodhcp/bootptodhcp.pl
new file mode 100755
index 00000000..c8d6465a
--- /dev/null
+++ b/gpxe/contrib/bootptodhcp/bootptodhcp.pl
@@ -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/gpxe/contrib/compressor/COPYING b/gpxe/contrib/compressor/COPYING
new file mode 100644
index 00000000..e574f7cd
--- /dev/null
+++ b/gpxe/contrib/compressor/COPYING
@@ -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/gpxe/contrib/compressor/algorithm.doc b/gpxe/contrib/compressor/algorithm.doc
new file mode 100644
index 00000000..74a7646c
--- /dev/null
+++ b/gpxe/contrib/compressor/algorithm.doc
@@ -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/gpxe/contrib/compressor/loader.h b/gpxe/contrib/compressor/loader.h
new file mode 100644
index 00000000..20fa9af3
--- /dev/null
+++ b/gpxe/contrib/compressor/loader.h
@@ -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/gpxe/contrib/compressor/lzhuf.c b/gpxe/contrib/compressor/lzhuf.c
new file mode 100644
index 00000000..ea65b5e0
--- /dev/null
+++ b/gpxe/contrib/compressor/lzhuf.c
@@ -0,0 +1,764 @@
+/*
+----------------------------------------------------------------------------
+
+M. LZHuf Compression
+
+This is the LZHuf compression algorithm as used in DPBOX and F6FBB.
+
+----------------------------------------------------------------------------
+*/
+/**************************************************************
+ lzhuf.c
+ written by Haruyasu Yoshizaki 11/20/1988
+ some minor changes 4/6/1989
+ comments translated by Haruhiko Okumura 4/7/1989
+
+ minor beautifications and adjustments for compiling under Linux
+ by Markus Gutschke <gutschk@math.uni-muenster.de>
+ 1997-01-27
+
+ Modifications to allow use as a filter by Ken Yap <ken_yap@users.sourceforge.net>.
+ 1997-07-01
+
+ Small mod to cope with running on big-endian machines
+ by Jim Hague <jim.hague@acm.org)
+ 1998-02-06
+
+ Make compression statistics report shorter
+ by Ken Yap <ken_yap@users.sourceforge.net>.
+ 2001-04-25
+**************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr 0
+#else
+#define Fprintf(x) fprintf x
+#if defined(ENCODE) || defined(DECODE)
+static char wterr[] = "Can't write.";
+#ifdef ENCODE
+static unsigned long int codesize = 0;
+#endif
+static unsigned long int printcount = 0;
+#endif
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned long int textsize = 0;
+
+static __inline__ void Error(char *message)
+{
+ Fprintf((stderr, "\n%s\n", message));
+ exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+ unsigned long res = 0;
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ u.ul = ul;
+ for (i = 3; i >= 0; i--)
+ res = (res << 8) + u.c[i];
+ return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ for (i = 0; i < 4; i++)
+ {
+ u.c[i] = ul & 0xff;
+ ul >>= 8;
+ }
+ return u.ul;
+}
+#endif
+
+/********** LZSS compression **********/
+
+#define N 4096 /* buffer size */
+/* Attention: When using this file for f6fbb-type compressed data exchange,
+ set N to 2048 ! (DL8HBS) */
+#define F 60 /* lookahead buffer size */
+#define THRESHOLD 2
+#define NIL N /* leaf of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned char
+ text_buf[N + F - 1];
+#endif
+
+#ifdef ENCODE
+static int match_position, match_length,
+ lson[N + 1], rson[N + 257], dad[N + 1];
+
+static void InitTree(void) /* initialize trees */
+{
+ int i;
+
+ for (i = N + 1; i <= N + 256; i++)
+ rson[i] = NIL; /* root */
+ for (i = 0; i < N; i++)
+ dad[i] = NIL; /* node */
+}
+
+static void InsertNode(int r) /* insert to tree */
+{
+ int i, p, cmp;
+ unsigned char *key;
+ unsigned c;
+
+ cmp = 1;
+ key = &text_buf[r];
+ p = N + 1 + key[0];
+ rson[r] = lson[r] = NIL;
+ match_length = 0;
+ for ( ; ; ) {
+ if (cmp >= 0) {
+ if (rson[p] != NIL)
+ p = rson[p];
+ else {
+ rson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ } else {
+ if (lson[p] != NIL)
+ p = lson[p];
+ else {
+ lson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ }
+ for (i = 1; i < F; i++)
+ if ((cmp = key[i] - text_buf[p + i]) != 0)
+ break;
+ if (i > THRESHOLD) {
+ if (i > match_length) {
+ match_position = ((r - p) & (N - 1)) - 1;
+ if ((match_length = i) >= F)
+ break;
+ }
+ if (i == match_length) {
+ if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
+ match_position = c;
+ }
+ }
+ }
+ }
+ dad[r] = dad[p];
+ lson[r] = lson[p];
+ rson[r] = rson[p];
+ dad[lson[p]] = r;
+ dad[rson[p]] = r;
+ if (rson[dad[p]] == p)
+ rson[dad[p]] = r;
+ else
+ lson[dad[p]] = r;
+ dad[p] = NIL; /* remove p */
+}
+
+static void DeleteNode(int p) /* remove from tree */
+{
+ int q;
+
+ if (dad[p] == NIL)
+ return; /* not registered */
+ if (rson[p] == NIL)
+ q = lson[p];
+ else
+ if (lson[p] == NIL)
+ q = rson[p];
+ else {
+ q = lson[p];
+ if (rson[q] != NIL) {
+ do {
+ q = rson[q];
+ } while (rson[q] != NIL);
+ rson[dad[q]] = lson[q];
+ dad[lson[q]] = dad[q];
+ lson[q] = lson[p];
+ dad[lson[p]] = q;
+ }
+ rson[q] = rson[p];
+ dad[rson[p]] = q;
+ }
+ dad[q] = dad[p];
+ if (rson[dad[p]] == p)
+ rson[dad[p]] = q;
+ else
+ lson[dad[p]] = q;
+ dad[p] = NIL;
+}
+#endif
+
+/* Huffman coding */
+
+#define N_CHAR (256 - THRESHOLD + F)
+ /* kinds of characters (character code = 0..N_CHAR-1) */
+#define T (N_CHAR * 2 - 1) /* size of table */
+#define R (T - 1) /* position of root */
+#define MAX_FREQ 0x8000 /* updates tree when the */
+ /* root frequency comes to this value. */
+typedef unsigned char uchar;
+
+/* table for encoding and decoding the upper 6 bits of position */
+
+/* for encoding */
+
+#ifdef ENCODE
+static uchar p_len[64] = {
+ 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static uchar p_code[64] = {
+ 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
+ 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
+ 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
+ 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
+ 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
+ 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+#endif
+
+#ifdef DECODE
+/* for decoding */
+static uchar d_code[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+ 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+ 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+ 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
+ 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
+ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
+ 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+ 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
+ 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+};
+
+static uchar d_len[256] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+};
+#endif
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned freq[T + 1]; /* frequency table */
+
+static int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
+ /* elements [T..T + N_CHAR - 1] which are used to get */
+ /* the positions of leaves corresponding to the codes. */
+
+static int son[T]; /* pointers to child nodes (son[], son[] + 1) */
+#endif
+
+#ifdef DECODE
+static unsigned getbuf = 0;
+static uchar getlen = 0;
+
+static int GetBit(void) /* get one bit */
+{
+ int i;
+
+ while (getlen <= 8) {
+ if ((i = getc(infile)) < 0) i = 0;
+ getbuf |= i << (8 - getlen);
+ getlen += 8;
+ }
+ i = getbuf;
+ getbuf <<= 1;
+ getlen--;
+ return ((signed short)i < 0);
+}
+
+static int GetByte(void) /* get one byte */
+{
+ unsigned short i;
+
+ while (getlen <= 8) {
+ if ((signed short)(i = getc(infile)) < 0) i = 0;
+ getbuf |= i << (8 - getlen);
+ getlen += 8;
+ }
+ i = getbuf;
+ getbuf <<= 8;
+ getlen -= 8;
+ return i >> 8;
+}
+#endif
+
+#ifdef ENCODE
+static unsigned putbuf = 0;
+static uchar putlen = 0;
+
+static void Putcode(int l, unsigned c) /* output c bits of code */
+{
+ putbuf |= c >> putlen;
+ if ((putlen += l) >= 8) {
+ if (putc(putbuf >> 8, outfile) == EOF) {
+ Error(wterr);
+ }
+ if ((putlen -= 8) >= 8) {
+ if (putc(putbuf, outfile) == EOF) {
+ Error(wterr);
+ }
+#ifdef VERBOSE
+ codesize += 2;
+#endif
+ putlen -= 8;
+ putbuf = c << (l - putlen);
+ } else {
+ putbuf <<= 8;
+#ifdef VERBOSE
+ codesize++;
+#endif
+ }
+ }
+}
+#endif
+
+/* initialization of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static void StartHuff(void)
+{
+ int i, j;
+
+ for (i = 0; i < N_CHAR; i++) {
+ freq[i] = 1;
+ son[i] = i + T;
+ prnt[i + T] = i;
+ }
+ i = 0; j = N_CHAR;
+ while (j <= R) {
+ freq[j] = freq[i] + freq[i + 1];
+ son[j] = i;
+ prnt[i] = prnt[i + 1] = j;
+ i += 2; j++;
+ }
+ freq[T] = 0xffff;
+ prnt[R] = 0;
+}
+
+/* reconstruction of tree */
+
+static void reconst(void)
+{
+ int i, j, k;
+ unsigned f, l;
+
+ /* collect leaf nodes in the first half of the table */
+ /* and replace the freq by (freq + 1) / 2. */
+ j = 0;
+ for (i = 0; i < T; i++) {
+ if (son[i] >= T) {
+ freq[j] = (freq[i] + 1) / 2;
+ son[j] = son[i];
+ j++;
+ }
+ }
+ /* begin constructing tree by connecting sons */
+ for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
+ k = i + 1;
+ f = freq[j] = freq[i] + freq[k];
+ for (k = j - 1; f < freq[k]; k--);
+ k++;
+ l = (j - k) * 2;
+ memmove(&freq[k + 1], &freq[k], l);
+ freq[k] = f;
+ memmove(&son[k + 1], &son[k], l);
+ son[k] = i;
+ }
+ /* connect prnt */
+ for (i = 0; i < T; i++) {
+ if ((k = son[i]) >= T) {
+ prnt[k] = i;
+ } else {
+ prnt[k] = prnt[k + 1] = i;
+ }
+ }
+}
+
+/* increment frequency of given code by one, and update tree */
+
+static void update(int c)
+{
+ int i, j, k, l;
+
+ if (freq[R] == MAX_FREQ) {
+ reconst();
+ }
+ c = prnt[c + T];
+ do {
+ k = ++freq[c];
+
+ /* if the order is disturbed, exchange nodes */
+ if (k > freq[l = c + 1]) {
+ while (k > freq[++l]);
+ l--;
+ freq[c] = freq[l];
+ freq[l] = k;
+
+ i = son[c];
+ prnt[i] = l;
+ if (i < T) prnt[i + 1] = l;
+
+ j = son[l];
+ son[l] = i;
+
+ prnt[j] = c;
+ if (j < T) prnt[j + 1] = c;
+ son[c] = j;
+
+ c = l;
+ }
+ } while ((c = prnt[c]) != 0); /* repeat up to root */
+}
+#endif
+
+#ifdef ENCODE
+#if 0
+static unsigned code, len;
+#endif
+
+static void EncodeChar(unsigned c)
+{
+ unsigned i;
+ int j, k;
+
+ i = 0;
+ j = 0;
+ k = prnt[c + T];
+
+ /* travel from leaf to root */
+ do {
+ i >>= 1;
+
+ /* if node's address is odd-numbered, choose bigger brother node */
+ if (k & 1) i += 0x8000;
+
+ j++;
+ } while ((k = prnt[k]) != R);
+ Putcode(j, i);
+#if 0
+ code = i;
+ len = j;
+#endif
+ update(c);
+}
+
+static void EncodePosition(unsigned c)
+{
+ unsigned i;
+
+ /* output upper 6 bits by table lookup */
+ i = c >> 6;
+ Putcode(p_len[i], (unsigned)p_code[i] << 8);
+
+ /* output lower 6 bits verbatim */
+ Putcode(6, (c & 0x3f) << 10);
+}
+
+static void EncodeEnd(void)
+{
+ if (putlen) {
+ if (putc(putbuf >> 8, outfile) == EOF) {
+ Error(wterr);
+ }
+#ifdef VERBOSE
+ codesize++;
+#endif
+ }
+}
+#endif
+
+#ifdef DECODE
+static int DecodeChar(void)
+{
+ unsigned c;
+
+ c = son[R];
+
+ /* travel from root to leaf, */
+ /* choosing the smaller child node (son[]) if the read bit is 0, */
+ /* the bigger (son[]+1} if 1 */
+ while (c < T) {
+ c += GetBit();
+ c = son[c];
+ }
+ c -= T;
+ update(c);
+ return c;
+}
+
+static int DecodePosition(void)
+{
+ unsigned i, j, c;
+
+ /* recover upper 6 bits from table */
+ i = GetByte();
+ c = (unsigned)d_code[i] << 6;
+ j = d_len[i];
+
+ /* read lower 6 bits verbatim */
+ j -= 2;
+ while (j--) {
+ i = (i << 1) + GetBit();
+ }
+ return c | (i & 0x3f);
+}
+#endif
+
+#ifdef ENCODE
+/* compression */
+
+void Encode(void) /* compression */
+{
+ int i, c, len, r, s, last_match_length;
+ unsigned long tw;
+
+ fseek(infile, 0L, 2);
+ textsize = ftell(infile);
+#ifdef VERBOSE
+ if ((signed long)textsize < 0)
+ Fprintf((stderr, "Errno: %d", errno));
+#endif
+ tw = host_to_i86ul(textsize);
+ if (fwrite(&tw, sizeof tw, 1, outfile) < 1)
+ Error(wterr); /* output size of text */
+ if (textsize == 0)
+ return;
+ rewind(infile);
+ textsize = 0; /* rewind and re-read */
+ StartHuff();
+ InitTree();
+ s = 0;
+ r = N - F;
+ for (i = s; i < r; i++)
+ text_buf[i] = ' ';
+ for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
+ text_buf[r + len] = c;
+ textsize = len;
+ for (i = 1; i <= F; i++)
+ InsertNode(r - i);
+ InsertNode(r);
+ do {
+ if (match_length > len)
+ match_length = len;
+ if (match_length <= THRESHOLD) {
+ match_length = 1;
+ EncodeChar(text_buf[r]);
+ } else {
+ EncodeChar(255 - THRESHOLD + match_length);
+ EncodePosition(match_position);
+ }
+ last_match_length = match_length;
+ for (i = 0; i < last_match_length &&
+ (c = getc(infile)) != EOF; i++) {
+ DeleteNode(s);
+ text_buf[s] = c;
+ if (s < F - 1)
+ text_buf[s + N] = c;
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+ InsertNode(r);
+ }
+ if ((textsize += i) > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+ Fprintf((stderr, "%12ld\r", textsize));
+#endif
+ printcount += 1024;
+ }
+ while (i++ < last_match_length) {
+ DeleteNode(s);
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+ if (--len) InsertNode(r);
+ }
+ } while (len > 0);
+ EncodeEnd();
+#ifdef LONG_REPORT
+ Fprintf((stderr, "input size %ld bytes\n", codesize));
+ Fprintf((stderr, "output size %ld bytes\n", textsize));
+ Fprintf((stderr, "input/output %.3f\n", (double)codesize / textsize));
+#else
+ Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", codesize, textsize,
+ (double)codesize / textsize));
+#endif
+}
+#endif
+
+#ifdef DECODE
+void Decode(void) /* recover */
+{
+ int i, j, k, r, c;
+ unsigned long int count;
+ unsigned long tw;
+
+ if (fread(&tw, sizeof tw, 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ textsize = i86ul_to_host(tw);
+ if (textsize == 0)
+ return;
+ StartHuff();
+ for (i = 0; i < N - F; i++)
+ text_buf[i] = ' ';
+ r = N - F;
+ for (count = 0; count < textsize; ) {
+ c = DecodeChar();
+ if (c < 256) {
+ if (putc(c, outfile) == EOF) {
+ Error(wterr);
+ }
+ text_buf[r++] = c;
+ r &= (N - 1);
+ count++;
+ } else {
+ i = (r - DecodePosition() - 1) & (N - 1);
+ j = c - 255 + THRESHOLD;
+ for (k = 0; k < j; k++) {
+ c = text_buf[(i + k) & (N - 1)];
+ if (putc(c, outfile) == EOF) {
+ Error(wterr);
+ }
+ text_buf[r++] = c;
+ r &= (N - 1);
+ count++;
+ }
+ }
+ if (count > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+ Fprintf((stderr, "%12ld\r", count));
+#endif
+ printcount += 1024;
+ }
+ }
+ Fprintf((stderr, "%12ld\n", count));
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+ char *s;
+ FILE *f;
+ int c;
+
+ if (argc == 2) {
+ outfile = stdout;
+ if ((f = tmpfile()) == NULL) {
+ perror("tmpfile");
+ return EXIT_FAILURE;
+ }
+ while ((c = getchar()) != EOF)
+ fputc(c, f);
+ rewind(infile = f);
+ }
+ else if (argc != 4) {
+ Fprintf((stderr, "'lzhuf e file1 file2' encodes file1 into file2.\n"
+ "'lzhuf d file2 file1' decodes file2 into file1.\n"));
+ return EXIT_FAILURE;
+ }
+ if (argc == 4) {
+ if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+ || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
+ || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+ Fprintf((stderr, "??? %s\n", s));
+ return EXIT_FAILURE;
+ }
+ }
+ if (toupper(*argv[1]) == 'E')
+ Encode();
+ else
+ Decode();
+ fclose(infile);
+ fclose(outfile);
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/gpxe/contrib/dhcpdconfeg/dhcpd.conf b/gpxe/contrib/dhcpdconfeg/dhcpd.conf
new file mode 100644
index 00000000..4d13e0f9
--- /dev/null
+++ b/gpxe/contrib/dhcpdconfeg/dhcpd.conf
@@ -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/gpxe/contrib/dhcpdconfeg/vendorclassid.txt b/gpxe/contrib/dhcpdconfeg/vendorclassid.txt
new file mode 100644
index 00000000..7b1f3910
--- /dev/null
+++ b/gpxe/contrib/dhcpdconfeg/vendorclassid.txt
@@ -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/gpxe/contrib/dhcpid/dhcpid.txt b/gpxe/contrib/dhcpid/dhcpid.txt
new file mode 100644
index 00000000..e6b5d277
--- /dev/null
+++ b/gpxe/contrib/dhcpid/dhcpid.txt
@@ -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)) {
+ break;
+ }
+@@ -914,13 +1026,15 @@ int await_reply(int type, int ival, void
+ DECODE_RFC1533 - Decodes RFC1533 header
+ **************************************************************************/
+ int decode_rfc1533(p, block, len, eof)
+- register unsigned char *p;
+- int 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;
+-
++#ifdef SERVER_IDENT
++ char rcvd_server_ident[9] = {};
++#endif
+ if (block == 0) {
+ #ifdef IMAGE_MENU
+ memset(imagelist, 0, sizeof(imagelist));
+@@ -1002,11 +1116,16 @@ int decode_rfc1533(p, block, len, eof)
+ }
+ #endif
+ #ifdef MOTD
+- else if (c >= RFC1533_VENDOR_MOTD &&
++ else if (c >= RFC1533_VENDOR_MOTD &&
+ c < RFC1533_VENDOR_MOTD +
+ RFC1533_VENDOR_NUMOFMOTD)
+ motd[c - RFC1533_VENDOR_MOTD] = p;
+ #endif
++#ifdef SERVER_IDENT
++ else if (c == RFC1533_VENDOR_SERVER_IDENT) {
++ memcpy(rcvd_server_ident,p+2,TAG_LEN(p));
++ }
++#endif
+ else {
+ #if 0
+ unsigned char *q;
+@@ -1018,6 +1137,30 @@ int decode_rfc1533(p, block, len, eof)
+ }
+ p += TAG_LEN(p) + 2;
+ }
++#if defined(SERVER_IDENT) && defined(DBG_IDENT)
++ if (strcasecmp(rcvd_server_ident,server_ident)) {
++ char ip[16];
++
++ inet_ntoa(dhcp_server,ip);
++ printf("[%s]: Option %d (%s), invalid response. Wanted (%s).\n",
++ ip,
++ RFC1533_VENDOR_SERVER_IDENT,
++ rcvd_server_ident,
++ server_ident);
++ strcpy(rcvd_server_ident,"");
++ return(0);
++ }
++ else {
++ char ip[16];
++
++ inet_ntoa(dhcp_server,ip);
++ printf("[%s]: Option %d (%s), valid response.\n",
++ ip,
++ RFC1533_VENDOR_SERVER_IDENT,
++ rcvd_server_ident);
++ strcpy(rcvd_server_ident,"");
++ }
++#endif
+ extdata = extend = endp;
+ if (block == 0 && extpath != NULL) {
+ char fname[64];
+@@ -1103,3 +1246,4 @@ void cleanup(void)
+ * c-basic-offset: 8
+ * End:
+ */
++
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="misc.c.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="misc.c.diff"
+
+--- etherboot-4.6.0/src/misc.c Tue Apr 25 08:30:25 2000
++++ etherboot-4.5.6-new/src/misc.c Wed Apr 26 16:26:38 2000
+@@ -140,9 +140,11 @@ void printf(const char *fmt, ...)
+
+ #ifdef IMAGE_MENU
+ /**************************************************************************
+-INET_ATON - Convert an ascii x.x.x.x to binary form
++INET_NTOA - Convert an ascii x.x.x.x to binary form
+ **************************************************************************/
+-int inet_aton(char *p, in_addr *i)
++int inet_aton(p, i)
++ char *p;
++ in_addr *i;
+ {
+ unsigned long ip = 0;
+ int val;
+@@ -165,7 +167,19 @@ int inet_aton(char *p, in_addr *i)
+
+ #endif /* IMAGE_MENU */
+
+-int getdec(char **ptr)
++#if defined(CLIENT_IDENT) || defined (SERVER_IDENT)
++/**************************************************************************
++INET_NTOA - Convert a binary form to an ascii x.x.x.x form
++**************************************************************************/
++char *inet_ntoa(in_addr i, char *p)
++{
++ sprintf(p,"%d.%d.%d.%d",i.s_addr>>24,i.s_addr<<8>>24,i.s_addr<<16>>24,i.s_addr<<24>>24);
++ return p;
++}
++#endif
++
++int getdec(ptr)
++ char **ptr;
+ {
+ char *p = *ptr;
+ int ret=0;
+@@ -308,6 +322,45 @@ iskey(void)
+ return 0;
+ }
+ #endif /* ETHERBOOT32 */
++
++/**************************************************************************
++GETSTR - Read a string of size bytes from the keyboard
++(without echoing the final return)
++**************************************************************************/
++void getstr(char *s, int size)
++{
++ int i=0;
++ char c;
++
++ while(1) {
++ c = getc();
++
++
++ if (c == 13)
++ {
++ s[i]='\0';
++ break;
++ }
++ else if (
++ ((c >= 'a') && (c <='z')) ||
++ ((c >= 'A') && (c <='Z')) ||
++ ((c >= '0') && (c <='9'))
++ ) {
++ if (i==8) {
++ putchar(8);
++ putchar(s[i-1]=c);
++ }
++ else
++ putchar(s[i++]=c);
++ }
++ else if ( c == 8 ) {
++ if (i != 0) {
++ --i;
++ s[i]='\0';
++ putchar(8);
++ putchar(32);
++ putchar(8);
++ }
++ }
++ }
++}
+
+ /*
+ * Local variables:
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="Config.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="Config.diff"
+
+--- etherboot-4.6.0/src/Config Tue Apr 25 08:30:57 2000
++++ etherboot-4.5.6-new/src/Config Wed Apr 26 15:55:57 2000
+@@ -59,6 +59,27 @@
+ # may no longer be appropriate. You might need to set
+ # MAX_ARP_RETRIES, MAX_BOOTP_RETRIES, MAX_TFTP_RETRIES
+ # and MAX_RPC_RETRIES to a larger value.
++# -DDEFAULT_CLIENT_IDENT
++# The default client identifier that is sent to the
++# DHCP server to identify itself.
++# -DDEFAULT_SERVER_IDENT
++# The expected response that the client will wait
++# for when a DHCP server responds to the the initial
++# client discovery.
++# -DASK_CLIENT_IDENT
++# -DASK_SERVER_IDENT
++# If these are set, the boot process will include
++# a question period where you can manualy specify
++# the client and/or server identifiers.
++# -DSHIFTED_IDENT_INPUT
++# If this is set then the boot process will only
++# ask for the identifiers if one of the shift keys
++# is pressed. Else it will send the default identifiers
++# automatically
++# -DDBG_IDENT
++# This will give show all the DHCP responses with
++# their identifiers.
++#
+ #
+ # Etherboot/32 only options:
+ # -DAOUT_IMAGE - Add a.out kernel boot support (generic)
+@@ -147,6 +168,14 @@ CFLAGS32+= -DASK_BOOT=3 -DANS_DEFAULT=AN
+
+ # Change download protocol to NFS. Only available for Etherboot/32 for now.
+ # CFLAGS32+= -DDOWNLOAD_PROTO_NFS
++
++# If you have more than one DHCP server you might want to
++# enable these to be able to sort out which one you want to
++# respond to.
++CFLAGS32+= -DDEFAULT_CLIENT_IDENT=\"BOOT\" -DDEFAULT_SERVER_IDENT=\"BOOT\"
++CFLAGS32+= -DASK_CLIENT_IDENT -DASK_SERVER_IDENT
++CFLAGS32+= -DSHIFTED_IDENT_INPUT
++CFLAGS32+= -DDBG_IDENT
+
+ # These flags affect the loader that is prepended to the Etherboot image
+ LCONFIG+= -DMOVEROM
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="etherboot.h.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="etherboot.h.diff"
+
+--- etherboot-4.6.0/src/etherboot.h Tue Apr 25 08:30:55 2000
++++ etherboot-4.5.6-new/src/etherboot.h Wed Apr 26 16:07:16 2000
+@@ -8,6 +8,14 @@ Author: Martin Renters
+
+ #include "osdep.h"
+
++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_CLIENT_IDENT) || defined(DEFAULT_CLIENT_IDENT))
++# define CLIENT_IDENT
++#endif
++
++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_SERVER_IDENT) || defined(DEFAULT_SERVER_IDENT))
++# define SERVER_IDENT
++#endif
++
+ /* These could be customised for different languages perhaps */
+ #define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? "
+ #define ANS_NETWORK 'N'
+@@ -224,6 +232,12 @@ Author: Martin Renters
+ #ifdef IMAGE_FREEBSD
+ #define RFC1533_VENDOR_HOWTO 132
+ #endif
++#ifdef CLIENT_IDENT
++#define RFC1533_VENDOR_CLIENT_IDENT 208
++#endif
++#ifdef SERVER_IDENT
++#define RFC1533_VENDOR_SERVER_IDENT 208
++#endif
+ #define RFC1533_VENDOR_MNUOPTS 160
+ #define RFC1533_VENDOR_SELECTION 176
+ #define RFC1533_VENDOR_MOTD 184
+@@ -477,11 +491,13 @@ extern int getdec P((char **));
+ extern void printf P((const char *, ...));
+ extern char *sprintf P((char *, const char *, ...));
+ extern int inet_aton P((char *p, in_addr *i));
++extern char *inet_ntoa P((in_addr i, char *p));
+ extern void gateA20_set P((void));
+ extern void gateA20_unset P((void));
+ extern void putchar P((int));
+ extern int getchar P((void));
+ extern int iskey P((void));
++extern void getstr P((char *s, int size));
+
+ /* start*.S */
+ extern int getc P((void));
+@@ -528,8 +544,10 @@ extern int hostnamelen;
+ extern unsigned long netmask;
+ extern int jmp_bootmenu[10];
+ extern struct arptable_t arptable[MAX_ARP];
+-#ifdef IMAGE_MENU
++#ifdef MOTD
+ extern char *motd[RFC1533_VENDOR_NUMOFMOTD];
++#endif
++#ifdef IMAGE_MENU
+ extern int menutmo,menudefault;
+ extern unsigned char *defparams;
+ extern int defparams_max;
+
+--------------4734FDA0BF2F2FBDF8EB8DF6--
+
diff --git a/gpxe/contrib/eepro100notes/flash-1.txt b/gpxe/contrib/eepro100notes/flash-1.txt
new file mode 100644
index 00000000..61579b4c
--- /dev/null
+++ b/gpxe/contrib/eepro100notes/flash-1.txt
@@ -0,0 +1,73 @@
+Date: Tue, 18 May 1999 15:45:55 +0200 (MEST)
+From: Erik Starback <erik@math.uu.se>
+To: netboot@baghira.han.de
+Subject: Netboot with Intel EEPRO100+ Management
+Message-ID: <Pine.LNX.3.96.990518154313.3875A-100000@anarchy.math.uu.se>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-1
+Content-Transfer-Encoding: 8BIT
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+X-UIDL: 6ca8453c19c46d622813e9be8ada9517
+Status: O
+X-Status:
+
+Hello!
+
+When Intel eepro100+ NIC disappeared from the market, I didn't know
+what to do. I didn't find any information if anyone has used the
+new eepro100+ Management Adapter to netboot linux.
+
+I thought that the card should netboot with the same configuration as
+the old card when I read Donald Beckers comment:
+> The driver should "just work" with the '559. It's not supposed to be
+> substantially different than the '558. (I don't have a datasheet
+> or sample card to confirm this statement.)
+
+The problem was now only to put the netboot-program to the built in
+flash memory on the NIC. With the old card I used a flash memory (Intel
+N28F020 [N28010 didn't work])) and the program FUTIL.EXE from Intel to
+flash it. FUTIL did't recognize the memory on the management card
+and did not work therefore.
+
+I found the intel program FBOOT.EXE that was made to upgrade the built
+in Intel BOOT agent. I did: Boot dos from floppy, Run FBOOT (choose
+adapter), choose (u)pdate, choose Create restore image, rename the
+backup file (in my case 2743BE52.FLS [the eight last hex digits from
+the MAC address]), rename your netboot code (in my case netboot 0.8.1)
+to the backup files original name (in my case 2743BE52.FLS), run
+FBOOT, choose (r)estore.
+
+Voila!
+
+A shorter way (if you don't need the backup of the old Intel BOOT
+agent code) is of course: rename netboot file to [the eight last hex
+digits from the MAC address].FLS, run FBOOT, choose restore.
+
+Caution: I think it is possible to make a NIC unusable if you have
+made the netboot (or etherboot) file with "wrong" parameters. A couple
+of month ago I did a etherboot boot file and put it on an old
+EEPRO100+ card. It worked fine, but it was impossible to boot local
+with it. So I could not boot dos and with FUTIL or FBOOT erase the
+flash memory! To erase the chip I had to take out the memory chip,
+boot dos and then put in the memory chip. This isn't possible when the
+memory chip is build in.
+
+Links:
+<http://support.intel.com/support/landesk/configmgr/LSA1_193.HTM>
+FUTIL.EXE is a part of LSA1_193.ZIP
+
+<http://support.intel.com/support/etherexpress/pro100/100pboot.htm>
+FBOOT.EXE is a part of 100pboot.exe
+
+/Erik S
+
+-------------------------------------------------------------------------
+Erik Starbäck, System administrator E-mail address: erik@math.uu.se
+Uppsala University Telephone (o): +46 18 4713277
+Department of Mathematics Cellular phone: +46 70 4250260
+P. O. Box 480 Fax (o): +46 18 4713201
+SE-751 06 UPPSALA
+Sweden
diff --git a/gpxe/contrib/eepro100notes/flash-2.txt b/gpxe/contrib/eepro100notes/flash-2.txt
new file mode 100644
index 00000000..1128c30e
--- /dev/null
+++ b/gpxe/contrib/eepro100notes/flash-2.txt
@@ -0,0 +1,149 @@
+Subject: Look Mom, no PROM burner! (eepro100b flashing instructions) :-)
+Date: Sun, 23 Jan 2000 01:53:08 -0500
+x-sender: mdc%thinguin.org@cdi.entity.com
+x-mailer: Claris Emailer 2.0v3, January 22, 1998
+From: Marty Connor <mdc@thinguin.org>
+To: "Netboot List" <netboot@baghira.han.de>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="US-ASCII"
+Message-ID: <1263512144-341319205@entity.com>
+
+Continuing the Etherboot World Domination theme, I noticed that there was
+a PCI ethernet card on my bookshelf that still contained the original
+vendor's code in its flash memory. The card virtually cried out to be
+flashed with Etherboot 4.4.1. :-)
+
+After having figured out how to flash the 3C905C last week, and owing to
+the fact that the temperature here in Cambridge, Massachusetts (USA) has
+dropped well below freezing, I decided to explore the possibility of
+flashing the Intel eepro100b that was sitting on my bookcase.
+
+After determining that it was unlikely that one could flash the chip in
+user mode under linux like the 3C509C, I turned to other options. (the
+reason is that the flash is memory mapped to a place that causes a core
+dump if accessed. i suppose one could to patch the kernel to flash the
+card, or add a linux device driver, but... :-)
+
+By the way, If you are ever looking for Linux utilities for Ethernet
+cards, you may want to check out:
+
+ http://cesdis.gsfc.nasa.gov/linux/diag/
+
+which is a treasure trove of tools for manipulating and testing Ethernet
+cards, all with source, courtesy of Donald Becker.
+
+At this point, I felt it was time to make a virtual trip to the Intel
+site (http://www.intel.com/), and search for utilities that might work
+with the eepro100B. I found two candidates: FUTIL and FBOOT. I
+downloaded, decompressed, and transferred them to a DOS formatted floppy.
+Next I determined (after a few tries) that F8 will let me get to DOS
+instead of booting windows. (I tend to avoid Windows when I can).
+
+I first tried FUTIL.EXE. No good. It told me it didn't recognize the
+flash on my eepro100B. how unfortunate. and I had such hopes :-)
+
+Next I tested FBOOT.EXE (available at
+http://support.intel.com/support/network/adapter/pro100/100PBOOT.htm)
+This program did in fact recognize my eepro100b card.
+
+The thing about FBOOT however, is that it thinks it only can load certain
+files. I of course needed to load an Etherboot image. It appeared to
+have no option for doing that. Things looked grim.
+
+Then I noticed that FBOOT was kind enough to do the following dialog:
+
+ Select Option (U)pdate or (R)estore: U
+
+I chose Update and it then offered to back up my flash rom for later
+restore:
+
+ Create Restore Image (Y)es or (N)o: Y
+
+I chose "Y" and it proceeded to write a file of my flash memory, which
+contained the Intel code.
+
+ Writing FLASH image to file... 100%
+
+It then erased the device:
+
+ Erasing FLASH Device... 100%
+
+and then programmed it with fresh code (stored inside the program, no
+doubt):
+
+ Programming FLASH Device... 100%
+
+So now I had a backup of the Intel boot code in a file strangely called:
+
+ 2794FC60.FLS
+
+Hmmmm, interesting name. The MAC address of the card is 09902794FC60.
+They just name the file with the last 4 octets of the MAC address and
+.FLS. The file is exactly 65536 bytes, which would make sense for a 64K
+Flash Memory device.
+
+Then I got to thinking, I wonder how carefully the "restore" part of
+FBOOT looks at what it is loading? What if I took an Etherboot .rom
+file, padded it with 48K of 0xFFs and named it 2794FC60.FLS. What if I
+then told FBOOT.EXE to "restore" that?
+
+Well, I guess by now, you know it worked :-)
+
+The card came up with the delightful Etherboot banner, Did DHCP, tftp,
+and started a kernel.
+
+The only unfortunate part is that you need to do this under DOS because
+you seem to need to be in real mode to program the card. Oh well,
+sacrifices have to be made :-)
+
+So, in summary, to prepare Etherboot image for flashing into the Intel
+EEPRO100B card with FBOOT, you need to first make an eepro100.rom file,
+as usual.
+
+Then, see how large it is, with an "ls -l eepro100.rom". the answer will
+probably be 16,384. You need to pad it with hex FFs to make it 64K for
+FBOOT. I used the following two lines to create the flash image file.
+
+ $ perl -e 'print "\xFF" x 49152' > 48kpad.bin
+ $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS
+
+Next write it to a DOS Floppy:
+
+ $ mount -t msdos /dev/fd0 /mnt/floppy
+ $ cp 2794FC60.FLS /mnt/floppy
+ $ umount /mnt/floppy
+
+Now you need to get to DOS. You could actually use a bootable DOS floppy
+with FBOOT.EXE and 2794FC60.FLS on it. I started a Windows box and hit
+F8 right before Windows started, and chose option 5, "Command Prompt
+Only", which gives you DOS. This program can't run in a DOS window under
+Windows or anything like that. You need to be in real DOS.
+
+Next it's time to run FBOOT. It will detect your ethernet card(s), ask
+you which one you want to program, and let you choose it from a menu.
+
+now the fun part:
+
+ Select Option (U)pdate or (R)estore: R
+ Erasing FLASH Device... 100%
+ Writing FLASH image from file... 100%
+
+Time to reboot and let Etherboot take over.
+
+So there you go, a way to make Intel EEPRO100Bs play nicely with
+Etherboot. Maybe we should put these instructions in the Etherboot
+contrib directory so people who have eepro100b cards will be able to
+avoid 3C905C envy :-)
+
+I hope this helps a few people out.
+
+Regards,
+
+Marty
+
+---
+ Name: Martin D. Connor
+US Mail: Entity Cyber, Inc.; P.O. Box 391827; Cambridge, MA 02139; USA
+ Voice: (617) 491-6935, Fax: (617) 491-7046
+ Email: mdc@thinguin.org
+ Web: http://www.thinguin.org/
diff --git a/gpxe/contrib/eepro100notes/flash-3.txt b/gpxe/contrib/eepro100notes/flash-3.txt
new file mode 100644
index 00000000..1a865a44
--- /dev/null
+++ b/gpxe/contrib/eepro100notes/flash-3.txt
@@ -0,0 +1,57 @@
+Date: Sun, 23 Jan 2000 09:47:15 +0100 (MET)
+From: Erik Starbäck <erik@math.uu.se>
+To: Netboot List <netboot@baghira.han.de>
+Subject: Re: Look Mom, no PROM burner! (eepro100b flashing instructions) :-)
+In-Reply-To: <1263512144-341319205@entity.com>
+Message-ID: <Pine.LNX.3.96.1000123094505.28562A-100000@anarchy.math.uu.se>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-1
+Content-Transfer-Encoding: 8BIT
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+
+
+Hello!
+
+In <http://www.han.de/~gero/netboot/archive/msg01718.html> I wrote what I
+did know about futil and fboot then. It is about the same as Martys
+instructions, but I have a few comments now.
+
+> Then, see how large it is, with an "ls -l eepro100.rom". the answer will
+> probably be 16,384. You need to pad it with hex FFs to make it 64K for
+> FBOOT. I used the following two lines to create the flash image file.
+
+> $ perl -e 'print "\xFF" x 49152' > 48kpad.bin
+> $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS
+
+It worked for me without any padding. When I burned a smaller image
+the program printed 50% instead of 100% and then it
+stopped. Everything worked anyway.
+
+
+I also did a brutal way of install etherboot or netboot on a
+EEPRO100+Mng without creating a file of type "2794FC60.FLS" for
+every card. It was necessary for me when I installed 70 clients...
+
+I chopped the binary file fboot.exe (my version was 99811 bytes, I
+don't remember the version name) in three parts:
+
+fboot1 30096 bytes
+fboot2 65536 bytes
+fboot3 4179 bytes
+
+Then you cat put them together again, but with a different part 2 and
+save it as fbootown.exe and execute it. It worked for me anyway. Of
+course you have to use padding to get a 64k part instead of fboot2.
+
+/Erik S
+
+-------------------------------------------------------------------------
+Erik Starbäck, System administrator E-mail address: erik@math.uu.se
+Uppsala University Telephone (o): +46 18 4713277
+Department of Mathematics Cellular phone: +46 70 4250260
+P. O. Box 480 Fax (o): +46 18 4713201
+SE-751 06 UPPSALA
+Sweden
diff --git a/gpxe/contrib/flashimg/Makefile b/gpxe/contrib/flashimg/Makefile
new file mode 100644
index 00000000..39f58e23
--- /dev/null
+++ b/gpxe/contrib/flashimg/Makefile
@@ -0,0 +1,29 @@
+CPPFLAGS = -x assembler-with-cpp
+AS86 = as86
+LD86 = ld86
+OBJDUMP = objdump
+
+.SUFFIXES: .s86 .asm .aout .img
+
+all: flashimg.img
+
+clean:
+ rm -rf *.o *.s86 *.aout *.img
+
+realclean: clean
+ rm -rf *.img
+
+.asm.s86: $*.asm $*.inc
+ $(CPP) $(CPPFLAGS) -o $@ $*.asm
+
+.s86.img: $*.s86
+ $(AS86) -0 -b $@ $*.s86
+
+# .s86.o: $*.s86
+# $(AS86) -0 -a -o $@ $*.s86
+#
+# .o.aout: $*.o
+# $(LD86) -0 -s -o $@ $*.o
+#
+# .aout.img:
+# dd if=$*.aout of=$@ bs=32 skip=1
diff --git a/gpxe/contrib/flashimg/flashimg.asm b/gpxe/contrib/flashimg/flashimg.asm
new file mode 100644
index 00000000..7a37ed54
--- /dev/null
+++ b/gpxe/contrib/flashimg/flashimg.asm
@@ -0,0 +1,497 @@
+; Copyright (C) 1997 Markus Gutschke <gutschk@uni-muenster.de>
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+; Prepend this image file to an arbitrary ROM image. The resulting binary
+; can be loaded from any BOOT-Prom that supports the "nbi" file format.
+; When started, the image will reprogram the flash EPROM on the FlashCard
+; ISA card. The flash EPROM has to be an AMD 29F010, and the programming
+; algorithm is the same as that suggested by AMD in the appropriate data
+; sheets.
+
+
+#define SEGLOW 0xC800 /* lower range for EPROM segment */
+#define SEGHIGH 0xE800 /* upper range for EPROM segment */
+#define AMD_ID 0x2001 /* flash EPROM ID, only support AMD */
+#define ERASE1_CMD 0x80 /* first cmd for erasing full chip */
+#define ERASE2_CMD 0x10 /* second cmd for erasing full chip */
+#define READID_CMD 0x90 /* cmd to read chip ID */
+#define PROG_CMD 0xA0 /* cmd to program a byte */
+#define RESET_CMD 0xF0 /* cmd to reset chip state machine */
+
+;----------------------------------------------------------------------------
+
+
+ .text
+ .org 0
+
+; .globl _main
+_main: mov ax,#0x0FE0
+ mov ds,ax
+ mov ax,magic ; verify that we have been loaded by
+ cmp ax,#0xE4E4 ; boot prom
+ jnz lderr
+ jmpi 0x200,0x0FE0 ; adjust code segment
+lderr: mov si,#loaderr
+ cld
+lderrlp:seg cs
+ lodsb ; loop over all characters of
+ or al,al ; string
+ jnz lderrnx
+ xor ah,ah
+ int 0x16 ; wait for keypress
+ jmpi 0x0000,0xFFFF ; reboot!
+lderrnx:mov ah,#0x0E ; print it
+ mov bl,#0x07
+ xor bh,bh
+ int 0x10
+ jmp lderrlp
+
+loaderr:.ascii "The flash EPROM utility has to be loaded from a BOOT-Prom"
+ .byte 0xa,0xd
+ .ascii "that knows about the 'nbi' file format!"
+ .byte 0xa,0xd
+ .ascii "Reboot to proceed..."
+ .byte 0
+
+ .org 510
+ .byte 0x55,0xAA
+
+!----------------------------------------------------------------------------
+
+start: mov ax,cs
+ mov ds,ax
+ mov ax,romdata ; verify that there is an Prom image
+ cmp ax,#0xAA55 ; attached to the utility
+ jnz resmag
+ mov al,romdata+2
+ or al,al ; non-zero size is required
+ jnz magicok
+resmag: mov si,#badmagic ; print error message
+reset: call prnstr
+ xor ah,ah
+ int 0x16 ; wait for keypress
+ jmpi 0x0000,0xFFFF ; reboot!
+magicok:mov di,#clrline1
+ mov si,#welcome ; print welcome message
+inpnew: call prnstr
+inprest:xor bx,bx
+ mov cl,#0xC ; expect 4 nibbles input data
+inploop:xor ah,ah
+ int 0x16
+ cmp al,#0x8 ; <Backspace>
+ jnz inpnobs
+ or bx,bx ; there has to be at least one input ch
+ jz inperr
+ mov si,#delchar ; wipe out char from screen
+ call prnstr
+ add cl,#4 ; compute bitmask for removing input
+ mov ch,cl
+ mov cl,#0xC
+ sub cl,ch
+ mov ax,#0xFFFF
+ shr ax,cl
+ not ax
+ and bx,ax
+ mov cl,ch
+inploop1:jmp inploop
+inpnobs:cmp al,#0x0D ; <Return>
+ jnz inpnocr
+ or bx,bx ; zero input -> autoprobing
+ jz inpdone
+ cmp cl,#-4 ; otherwise there have to be 4 nibbles
+ jz inpdone
+inperr: mov al,#7 ; ring the console bell
+ jmp inpecho
+inpnocr:cmp al,#0x15 ; <CTRL-U>
+ jnz inpnokl
+ mov si,di
+ call prnstr ; clear entire input and restart
+ jmp inprest
+inpnokl:cmp cl,#-4 ; cannot input more than 4 nibbles
+ jz inperr
+ cmp al,#0x30 ; '0'
+ jb inperr
+ ja inpdig
+ or bx,bx ; leading '0' is not allowed
+ jz inperr
+inpdig: cmp al,#0x39 ; '9'
+ ja inpnodg
+ mov ch,al
+ sub al,#0x30
+inpnum: xor ah,ah ; compute new input value
+ shl ax,cl
+ add ax,bx
+ test ax,#0x1FF ; test for 8kB boundary
+ jnz inperr
+ cmp ax,#SEGHIGH ; input has to be below E800
+ jae inperr
+ cmp ax,#SEGLOW ; and above/equal C800
+ jae inpok
+ cmp cl,#0xC ; if there is just one nibble, yet,
+ jnz inperr ; then the lower limit ix C000
+ cmp ax,#0xC000
+ jb inperr
+inpok: mov bx,ax ; adjust bitmask
+ sub cl,#4
+ mov al,ch
+inpecho:call prnchr ; output new character
+ jmp inploop1
+inpnodg:and al,#0xDF ; lower case -> upper case
+ cmp al,#0x41 ; 'A'
+ jb inperr
+ cmp al,#0x46 ; 'F'
+ ja inperr
+ mov ch,al
+ sub al,#0x37
+ jmp inpnum
+inpdone:or bx,bx ; zero -> autoprobing
+ jnz probe
+ mov si,#automsg
+ call prnstr
+ mov cx,#0x10
+ mov bx,#SEGHIGH ; scan from E800 to C800
+autoprb:sub bx,#0x0200 ; stepping down in 8kB increments
+ mov di,bx
+ call readid
+ cmp ax,#AMD_ID
+ jz prbfnd
+ loop autoprb
+ mov si,#failmsg
+nofnd: mov di,#clrline2
+ jmp near inpnew ; failure -> ask user for new input
+probe: mov di,bx
+ test bx,#0x07FF ; EPROM might have to be aligned to
+ jz noalign ; 32kB boundary
+ call readid
+ cmp ax,#AMD_ID ; check for AMDs id
+ jz prbfnd
+ mov si,#alignmsg
+ call prnstr
+ and bx,#0xF800 ; enforce alignment of hardware addr
+noalign:call readid ; check for AMDs id
+ cmp ax,#AMD_ID
+ jz prbfnd
+ mov si,#nofndmsg ; could not find any EPROM at speci-
+ call prnstr ; fied location --- even tried
+ mov si,#basemsg ; aligning to 32kB boundary
+ jmp nofnd ; failure -> ask user for new input
+prbfnd: mov si,#fndmsg
+ call prnstr ; we found a flash EPROM
+ mov ax,bx
+ call prnwrd
+ mov si,#ersmsg
+ call prnstr
+ call erase ; erase old contents
+ jnc ersdone
+ mov si,#failresmsg ; failure -> reboot machine
+ jmp near reset
+ersdone:mov si,#prg1msg ; tell user that we are about
+ call prnstr ; to program the new data into
+ mov ax,di ; the specified range
+ call prnwrd
+ mov si,#prg2msg
+ call prnstr
+ xor dh,dh
+ mov dl,romdata+2
+ shl dx,#1
+ mov ah,dh
+ mov cl,#4
+ shl ah,cl
+ xor al,al
+ add ax,di
+ call prnwrd
+ mov al,#0x3A ; ':'
+ call prnchr
+ mov ah,dl
+ xor al,al
+ dec ax
+ call prnwrd
+ mov al,#0x20
+ call prnchr
+ mov dh,romdata+2 ; number of 512 byte blocks
+ push ds
+ mov ax,ds
+ add ax,#romdata>>4 ; adjust segment descriptor, so that
+ mov ds,ax ; we can handle images which are
+prgloop:mov cx,#0x200 ; larger than 64kB
+ xor si,si
+ xor bp,bp
+ call program ; program 512 data bytes
+ jc prgerr ; check error condition
+ mov ax,ds
+ add ax,#0x20 ; increment segment descriptors
+ mov ds,ax
+ add di,#0x20
+ dec dh ; decrement counter
+ jnz prgloop
+ pop ds
+ mov si,#donemsg ; success -> reboot
+prgdone:call prnstr
+ mov si,#resetmsg
+ jmp near reset
+prgerr: pop ds ; failure -> reboot
+ mov si,#failresmsg
+ jmp prgdone
+
+
+;----------------------------------------------------------------------------
+
+; READID -- read EPROM id number, base address is passed in BX
+; ======
+;
+; changes: AX, DL, ES
+
+readid: mov dl,#RESET_CMD ; reset chip
+ call sendop
+ mov dl,#READID_CMD
+ call sendop ; send READID command
+ mov es,bx
+ seg es
+ mov ax,0x00 ; read manufacturer ID
+ mov dl,#RESET_CMD
+ jmp sendop ; reset chip
+
+
+;----------------------------------------------------------------------------
+
+; ERASE -- erase entire EPROM, base address is passed in BX
+; =====
+;
+; changes: AL, CX, DL, ES, CF
+
+erase: mov dl,#ERASE1_CMD
+ call sendop ; send ERASE1 command
+ mov dl,#ERASE2_CMD
+ call sendop ; send ERASE2 command
+ xor bp,bp
+ mov al,#0xFF
+ push di
+ mov di,bx
+ call waitop ; wait until operation finished
+ pop di
+ jnc erfail
+ mov dl,#RESET_CMD
+ call sendop ; reset chip
+ stc
+erfail: ret
+
+
+;----------------------------------------------------------------------------
+
+; PROGRAM -- write data block at DS:SI of length CX into EPROM at DI:BP
+; =======
+;
+; changes: AX, CX, DL, BP, ES, CF
+
+program:mov dl,#PROG_CMD
+ call sendop ; send programming command
+ lodsb ; get next byte from buffer
+ mov es,di
+ seg es
+ mov byte ptr [bp],al ; write next byte into flash EPROM
+ call waitop ; wait until programming operation is
+ jc progdn ; completed
+ inc bp
+ loop program ; continue with next byte
+ clc ; return without error
+progdn: ret
+
+
+;----------------------------------------------------------------------------
+
+; SENDOP -- send command in DL to EPROM, base address is passed in BX
+; ======
+;
+; changes: ES
+
+sendop: mov es,bx
+ seg es
+ mov byte ptr 0x5555,#0xAA ; write magic data bytes into
+ jcxz so1 ; magic locations. This unlocks
+so1: jcxz so2 ; the flash EPROM. N.B. that the
+so2: seg es ; magic locations are mirrored
+ mov byte ptr 0x2AAA,#0x55 ; every 32kB; the hardware address
+ jcxz so3 ; might have to be adjusted to a
+so3: jcxz so4 ; 32kB boundary
+so4: seg es
+ mov byte ptr 0x5555,dl
+ ret
+
+
+;----------------------------------------------------------------------------
+
+; WAITOP -- wait for command to complete, address is passed in DI:BP
+; ======
+;
+; for details on the programming algorithm, c.f. http://www.amd.com
+;
+; changes: AX, DL, ES, CF
+
+waitop: and al,#0x80 ; monitor bit 7
+ mov es,di
+wait1: seg es ; read contents of EPROM cell that is
+ mov ah,byte ptr [bp] ; being programmed
+ mov dl,ah
+ and ah,#0x80
+ cmp al,ah ; bit 7 indicates sucess
+ je waitok
+ test dl,#0x20 ; bit 5 indicates timeout/error
+ jz wait1 ; otherwise wait for cmd to complete
+ seg es
+ mov ah,byte ptr [bp] ; check error condition once again,
+ and ah,#0x80 ; because bits 7 and 5 can change
+ cmp al,ah ; simultaneously
+ je waitok
+ stc
+ ret
+waitok: clc
+ ret
+
+;----------------------------------------------------------------------------
+
+; PRNSTR -- prints a string in DS:SI onto the console
+; ======
+;
+; changes: AL
+
+prnstr: push si
+ cld
+prns1: lodsb ; loop over all characters of
+ or al,al ; string
+ jz prns2
+ call prnchr ; print character
+ jmp prns1
+prns2: pop si
+ ret
+
+
+;----------------------------------------------------------------------------
+
+; PRNWRD, PRNBYT, PRNNIB, PRNCHR -- prints hexadezimal values, or ASCII chars
+; ====== ====== ====== ======
+;
+; changes: AX
+
+prnwrd: push ax
+ mov al,ah
+ call prnbyt ; print the upper byte
+ pop ax
+prnbyt: push ax
+ shr al,1 ; prepare upper nibble
+ shr al,1
+ shr al,1
+ shr al,1
+ call prnnib ; print it
+ pop ax
+prnnib: and al,#0x0F ; prepare lower nibble
+ add al,#0x30
+ cmp al,#0x39 ; convert it into hex
+ jle prnchr
+ add al,#7
+prnchr: push bx
+ mov ah,#0x0E ; print it
+ mov bl,#0x07
+ xor bh,bh
+ int 0x10
+ pop bx
+ ret
+
+
+;----------------------------------------------------------------------------
+
+magic: .byte 0xE4,0xE4
+
+badmagic:.byte 0xa,0xd
+ .ascii "There does not appear to be a ROM image attached to the"
+ .ascii "flash EPROM utility;"
+ .byte 0xa,0xd
+resetmsg:.ascii "Reboot to proceed..."
+ .byte 0
+
+welcome:.byte 0xa,0xd
+ .ascii "Flash EPROM programming utility V1.0"
+ .byte 0xa,0xd
+ .ascii "Copyright (c) 1997 by M. Gutschke <gutschk@uni-muenster.de>"
+ .byte 0xa,0xd
+ .ascii "==========================================================="
+ .byte 0xa,0xd
+prompt: .byte 0xa,0xd
+ .ascii "Enter base address for AMD29F010 flash EPROM on FlashCard or"
+ .byte 0xa,0xd
+ .ascii "press <RETURN> to start autoprobing; the base address has"
+ .byte 0xa
+clrline1:.byte 0xd
+ .ascii "to be in the range C800..E600: "
+ .ascii " "
+ .byte 0x8,0x8,0x8,0x8
+ .byte 0
+
+delchar:.byte 0x8,0x20,0x8
+ .byte 0
+
+automsg:.ascii "autoprobing... "
+ .byte 0
+
+failmsg:.ascii "failed!"
+basemsg:.byte 0xa
+clrline2:.byte 0xd
+ .ascii "Enter base address: "
+ .ascii " "
+ .byte 0x8,0x8,0x8,0x8
+ .byte 0
+
+fndmsg: .byte 0xa,0xd
+ .ascii "Found flash EPROM at: "
+ .byte 0
+
+alignmsg:.byte 0xa,0xd
+ .ascii "FlashCard requires the hardware address to be aligned to a"
+ .byte 0xa,0xd
+ .ascii "32kB boundary; automatically adjusting..."
+ .byte 0
+
+nofndmsg:.byte 0xa,0xd
+ .ascii "No AMD29F010 flash EPROM found"
+ .byte 0
+
+ersmsg: .byte 0xa,0xd
+ .ascii "Erasing old contents... "
+ .byte 0
+
+prg1msg:.ascii "done"
+ .byte 0xa,0xd
+ .ascii "Programming from "
+ .byte 0
+
+prg2msg:.ascii ":0000 to "
+ .byte 0
+
+donemsg:.ascii "done!"
+ .byte 0xa,0xd
+ .byte 0
+
+failresmsg:
+ .ascii "failed!"
+ .byte 0xa,0xd
+ .byte 0
+
+
+;----------------------------------------------------------------------------
+
+ .align 16
+ .org *-1
+ .byte 0x00
+romdata:
diff --git a/gpxe/contrib/flashimg/flashimg.img b/gpxe/contrib/flashimg/flashimg.img
new file mode 100644
index 00000000..263d3392
--- /dev/null
+++ b/gpxe/contrib/flashimg/flashimg.img
Binary files differ
diff --git a/gpxe/contrib/hdload/Makefile b/gpxe/contrib/hdload/Makefile
new file mode 100644
index 00000000..9ed750de
--- /dev/null
+++ b/gpxe/contrib/hdload/Makefile
@@ -0,0 +1,15 @@
+# Use nasm or as86
+ASM=nasm
+# ASM=as86
+
+hdload.bin: hdload.S
+ifeq ($(ASM),as86)
+ gcc $(CFLAGS) -DUSE_AS86 -E -traditional -o hdload.s hdload.S
+ as86 -0 -b hdload.bin hdload.s
+else
+ gcc $(CFLAGS) -DUSE_NASM -E -traditional -o hdload.s hdload.S
+ nasm -f bin hdload.s -o hdload.bin
+endif
+
+clean:
+ $(RM) -f hdload.s hdload.bin
diff --git a/gpxe/contrib/hdload/hdload.S b/gpxe/contrib/hdload/hdload.S
new file mode 100644
index 00000000..3bb5649b
--- /dev/null
+++ b/gpxe/contrib/hdload/hdload.S
@@ -0,0 +1,162 @@
+#if !defined(USE_NASM) && !defined(USE_AS86)
+#define USE_AS86
+#endif
+
+#ifdef USE_AS86
+#define CON(x) *x
+#define BCON(x) *x
+#define WCON(x) *x
+#define LOC(x) x
+#define BLOC(x) byte ptr x
+#define WLOC(x) word ptr x
+#define JMP(x) jmp x
+#define STRDECL(s) .ascii s
+#define SEGCS seg cs
+#define SEGES seg es
+#define ALIGN(x) .align x
+#define SPACE(x) .space x
+#endif
+
+#ifdef USE_NASM
+#define CON(x) x
+#define BCON(x) byte x
+#define WCON(x) word x
+#define LOC(x) [x]
+#define BLOC(x) byte [x]
+#define WLOC(x) word [x]
+#define JMP(x) jmp short x
+#define STRDECL(s) db s
+#define SEGCS cs
+#define SEGES es
+#define ALIGN(x) align x, db 0
+#define SPACE(x) times x db 0
+#endif
+
+ROMLOAD equ 0x5000
+
+start:
+ cli
+ xor ax, ax
+ mov ss, ax
+ mov sp, CON(0x7C00)
+ mov si, sp
+ mov es, ax
+ mov ds, ax
+ sti
+ cld
+ mov di, CON(0x600)
+ mov cx, CON(0x100)
+ rep
+ movsw
+ db 0xEA
+ dw jump
+ dw 0
+jump:
+ mov si, CON(Hlaska)
+ call print
+
+ ; rozmery prvniho HD
+ mov ah, CON(8)
+ mov dl, CON(0x80)
+ int 0x13
+ jc chyba
+ ; dh - H, cx - CS
+
+ ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM
+ mov ah, CON(2)
+ mov al, cl
+ and al, CON(0x3F)
+ dec al
+ mov dx, CON(0x80)
+ mov cx, CON(2)
+ mov bx, CON(ROMLOAD)
+ mov es, bx
+ xor bx, bx
+ int 0x13
+ jc chyba
+
+ ; hromada kodu podle zdrojaku netboot
+ xor di, di
+ mov es, di
+ mov di, CON(0x380)
+ push di
+ mov cx, CON(10)
+ cld
+ rep
+ stosw
+ pop di
+#ifdef USE_AS86
+ mov word ptr [ di ], CON(0x5a5a)
+ mov byte ptr [ di + 2 ], CON(0x50)
+ mov word ptr [ di + 0x10 ], CON(0xFFFF)
+ mov word ptr [ di + 0x12 ], CON(0xFFFF)
+#endif
+#ifdef USE_NASM
+ mov word [ di ], CON(0x5a5a)
+ mov byte [ di + 2 ], CON(0x50)
+ mov word [ di + 10h ], CON(0xFFFF)
+ mov word [ di + 12h ], CON(0xFFFF)
+#endif
+
+ ; navratova adresa, kdyby nezabrala ROM
+ SEGCS
+ mov WLOC(OfsErr), CON(RomErr)
+ push cs
+ push WCON(chyba)
+ mov ax, CON(ROMLOAD)
+ mov es, ax
+ push es
+ ; kouzelny jump....
+ SEGES
+ mov si, [ 0x1a ]
+ SEGES
+#ifdef USE_AS86
+ push word ptr [ si + 0x1a ] ; ...do bootrom v RAM
+#endif
+#ifdef USE_NASM
+ push word [ si + 0x1a ] ; ...do bootrom v RAM
+#endif
+ retf
+
+chyba:
+ SEGCS
+ mov si, LOC(OfsErr)
+ call print
+ mov si, CON(CRLF)
+ call print
+ JMP(chyba)
+
+print:
+ lodsb
+ cmp al,CON(0)
+ je navrat
+ push si
+ mov bx,CON(7)
+ mov ah,CON(0x0E)
+ int 0x10
+ pop si
+ JMP(print)
+
+navrat:
+ ret
+
+Hlaska: db 13, 10
+ STRDECL('HD Net Loader v1.0 (c) poli 1999')
+ db 13, 10, 0
+CRLF: db 13, 10, 0
+OfsErr: dw Error
+Error: STRDECL('Error load from HD !')
+ db 0
+RomErr: STRDECL('ROM Error !')
+ db 0
+
+mbrend:
+ ret
+
+#ifdef USE_AS86
+ org 510
+#endif
+#ifdef USE_NASM
+ times 510-($-$$) db 0
+#endif
+ dw 0xAA55
diff --git a/gpxe/contrib/hdload/petr.msg b/gpxe/contrib/hdload/petr.msg
new file mode 100644
index 00000000..a3134d04
--- /dev/null
+++ b/gpxe/contrib/hdload/petr.msg
@@ -0,0 +1,175 @@
+From netboot-owner@baghira.han.de Thu Sep 16 12:08:44 1999
+Return-Path: <netboot-owner@baghira.han.de>
+Received: (from factotum@localhost)
+ by baghira.han.de (8.9.3/8.9.3) id NAA23838
+ for netboot-outgoing; Wed, 15 Sep 1999 13:12:44 +0200
+X-Authentication-Warning: baghira.han.de: factotum set sender to owner-netboot using -f
+Received: from hathi.han.de (root@hathi.han.de [192.109.225.1])
+ by baghira.han.de (8.9.3/8.9.3) with ESMTP id NAA23785
+ for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:02 +0200
+Received: from vsb.cz (root@decsys.vsb.cz [158.196.149.9])
+ by hathi.han.de (8.9.3/8.9.3) with ESMTP id NAA04707
+ for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:00 +0200
+Received: from nwfei1.vsb.cz (nwfei1.vsb.cz [158.196.146.13])
+ by vsb.cz (8.9.3/8.9.1) with ESMTP id NAA22363
+ for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:10:52 +0200 (MET DST)
+Received: from FEI1/SpoolDir by nwfei1.vsb.cz (Mercury 1.44);
+ 15 Sep 99 13:10:50 +0100
+Received: from SpoolDir by FEI1 (Mercury 1.44); 15 Sep 99 13:10:27 +0100
+Received: from pcd403z.vsb.cz (158.196.146.9) by nwfei1.vsb.cz (Mercury 1.44) with ESMTP;
+ 15 Sep 99 13:10:25 +0100
+Received: from oli10 by pcd403z.vsb.cz with local-esmtp (Exim 2.05 #1 (Debian))
+ id 11RCxI-0000oT-00; Wed, 15 Sep 1999 13:10:28 +0200
+Date: Wed, 15 Sep 1999 13:10:28 +0200 (CEST)
+From: Petr Olivka <Petr.Olivka@vsb.cz>
+To: netboot@baghira.han.de
+Subject: netboot image on hard disk - it is easy
+In-Reply-To: <37DF4BD4.E8FFF8FC@gsmbox.com>
+Message-ID: <Pine.LNX.4.10.9909151247430.2936-100000@pcd403z.vsb.cz>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=US-ASCII
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+
+It is good joke, at this moment I have only simple version of MBR to load
+image from HD, but only from track 0. HD have to have enough sectors per
+track for rom image.
+And small program in turbo-pascal to download image to HD.
+
+below is assembler code for MBR. Is writen for tasm and tlink.
+If you have 512 bytes binary file with MBR code, then concat it with
+rom-image and download to hda. BUT NOT DIRECTLY !!!! You have to copy
+partition table ( and NT signature ) to MBR and then download. BUT ONLY tO
+TRACK 0.
+
+Everything in your own risk.
+
+If I will have some free time, I will write some code directly to netboot.
+
+poli
+
+.model large, pascal
+
+.code
+.386
+ public mbrasm, mbrend
+
+ROMLOAD equ 5000h
+
+ org 600h
+
+mbrasm proc
+
+ cli
+ xor ax, ax
+ mov ss, ax
+ mov sp, 7C00h
+ mov si, sp
+ mov es, ax
+ mov ds, ax
+ sti
+ cld
+ mov di, 600h
+ mov cx, 100h
+ rep movsw
+ db 0EAh
+ dw offset @@jump
+ dw 0
+@@jump:
+ mov si, offset Hlaska
+ call @@print
+
+ ; rozmery prvniho HD
+ mov ah, 8
+ mov dl, 80h
+ int 13h
+ jc @@chyba
+ ; dh - H, cx - CS
+
+ ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM
+ mov ah, 2
+ mov al, cl
+ and al, 3Fh
+ dec al
+ mov dx, 80h
+ mov cx, 2
+ mov bx, ROMLOAD
+ mov es, bx
+ xor bx, bx
+ int 13h
+ jc @@chyba
+
+ ; hromada kodu podle zdrojaku netboot
+ xor di, di
+ mov es, di
+ mov di, 380h
+ push di
+ mov cx, 10
+ cld
+ rep stosw
+ pop di
+ mov word ptr [ di ], 5a5ah
+ mov byte ptr [ di + 2 ], 50h
+ mov word ptr [ di + 10h ], 0FFFFh
+ mov word ptr [ di + 12h ], 0FFFFh
+
+ ; navratova adresa, kdyby nezabrala ROM
+ mov OfsErr, offset RomErr
+ push cs
+ push offset @@chyba
+
+ mov ax, ROMLOAD
+ mov es, ax
+ push es
+ ; kouzelny jump....
+ mov si, es:[ 1ah ]
+ push word ptr es:[ si + 1ah ] ; ...do bootrom v RAM
+ retf
+
+@@chyba:
+ mov si, OfsErr
+ call @@print
+ mov si, offset CRLF
+ call @@print
+ jmp @@chyba
+
+@@print:
+ lodsb
+ cmp al,0
+ je @@navrat
+ push si
+ mov bx,7
+ mov ah,0Eh
+ int 10h
+ pop si
+ jmp @@print
+
+@@navrat:
+ retn
+
+Hlaska db 13, 10, 'HD Net Loader v1.0 (c) poli 1999', 13, 10, 0
+CRLF db 13, 10, 0
+OfsErr dw offset Error
+Error db 'Error load from HD !', 0
+RomErr db 'ROM Error !', 0
+
+mbrasm endp
+
+mbrend proc
+ ret
+mbrend endp
+
+ org 800h - 2
+ dw 0AA55h
+
+end
+
+===========================================================================
+This Mail was sent to netboot mailing list by:
+Petr Olivka <Petr.Olivka@vsb.cz>
+To get help about this list, send a mail with 'help' as the only string in
+it's body to majordomo@baghira.han.de. If you have problems with this list,
+send a mail to netboot-owner@baghira.han.de.
+
diff --git a/gpxe/contrib/initrd/ChangeLog b/gpxe/contrib/initrd/ChangeLog
new file mode 100644
index 00000000..94f8f6aa
--- /dev/null
+++ b/gpxe/contrib/initrd/ChangeLog
@@ -0,0 +1,46 @@
+mkinitrd-net ChangeLog
+
+Last Modified: Fri Jul 26 23:08:28 2002
+
+$Log$
+Revision 1.1 2005/05/17 16:45:02 mcb30
+Initial revision
+
+Revision 1.1 2002/11/06 06:31:06 ken_yap
+Contributed by Michael Brown.
+
+Revision 1.10 2002/07/26 23:09:13 mcb30
+Support for new binary etherboot.nic-dev-id structure
+Added --kernel option patch from Stew Benedict at MandrakeSoft
+Only try to use sudo if we are not already root
+
+Revision 1.9 2002/06/05 13:31:50 mcb30
+Modifications to allow DHCP, TFTP and NFS servers to be separate machines.
+
+Revision 1.8 2002/05/30 11:41:18 mcb30
+/tftpboot symlinked to /var/lib/tftpboot
+Has ability to be quiet if "quiet" specified on kernel cmdline
+
+Revision 1.7 2002/05/26 11:15:04 mcb30
+PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include
+
+Revision 1.6 2002/05/24 02:05:11 mcb30
+Bugfixes, migrated /tftpboot to /var/lib/tftpboot
+
+Revision 1.5 2002/05/23 21:29:58 mcb30
+Now includes dhcpd.conf.etherboot.include
+Automatically scans for all network modules in the pcimap file
+
+Revision 1.4 2002/05/08 09:04:31 mcb30
+Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities
+
+Revision 1.3 2002/05/04 21:44:13 mcb30
+During %make, LIBDIR must be set for mknbi
+Added %post scriptlet since %trigger seems not to be being triggered...
+
+Revision 1.2 2002/05/04 21:20:32 mcb30
+Added extra sources instead of requiring "make" to download them
+
+Revision 1.1 2002/05/04 13:19:40 mcb30
+First attempt at an RPM package
+
diff --git a/gpxe/contrib/initrd/Makefile b/gpxe/contrib/initrd/Makefile
new file mode 100644
index 00000000..f18b73f6
--- /dev/null
+++ b/gpxe/contrib/initrd/Makefile
@@ -0,0 +1,187 @@
+UCLIBC_VERSION = 0.9.11
+UCLIBC = uClibc-$(UCLIBC_VERSION)
+$(UCLIBC)_SOURCE = http://www.uclibc.org/downloads/$(UCLIBC).tar.bz2
+UCLIBC_INSTALL = $(CURDIR)/uClibc
+
+UDHCP_VERSION = 0.9.7
+UDHCP = udhcp-$(UDHCP_VERSION)
+$(UDHCP)_SOURCE = http://udhcp.busybox.net/source/$(UDHCP).tar.gz
+
+BUSYBOX_VERSION = 0.60.3
+BUSYBOX = busybox-$(BUSYBOX_VERSION)
+$(BUSYBOX)_SOURCE = http://www.busybox.net/downloads/$(BUSYBOX).tar.bz2
+
+LINUX_WLAN_VERSION = 0.1.13
+LINUX_WLAN = linux-wlan-ng-$(LINUX_WLAN_VERSION)
+$(LINUX_WLAN)_SOURCE = ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/$(LINUX_WLAN).tar.gz
+
+MKNBI_VERSION = 1.2
+MKNBI = mknbi-$(MKNBI_VERSION)
+$(MKNBI)_SOURCE = http://belnet.dl.sourceforge.net/sourceforge/etherboot/$(MKNBI).tar.gz
+
+export PATH := $(UCLIBC_INSTALL)/bin:$(PATH)
+
+all : utils initrd-skel mknbi mknbi-linux
+ # Run "make tftpboot/initrd-kernel_module.img" to generate a suitable initrd
+ # Run "make tftpboot/boot-kernel_module.nbi" to generate a suitable NBI
+ # Run "make all-nbi" to generate a complete set of NBIs
+
+%.tar.bz2 :
+ [ -d $* ] || wget $($*_SOURCE)
+ [ -f $*.t*gz ] && ( gunzip $*.t*gz ; bzip2 -9 $*.tar ) || true
+
+UTILS = udhcpc busybox wlanctl
+
+utils : $(UTILS)
+
+clean : partlyclean
+ rm -rf uClibc
+ rm -rf $(UCLIBC)
+ rm -rf tftpboot/*
+
+partlyclean :
+ rm -rf $(UDHCP)
+ rm -rf $(BUSYBOX)
+ rm -rf $(LINUX_WLAN)
+ rm -rf $(MKNBI)
+ rm -rf initrd-skel
+ rm -f *.img *.ird *.nbi insert-modules
+ rm -f $(UTILS) mknbi-linux
+ rm -f *.uClibc *.busybox *.udhcpc *.wlanctl
+
+.PHONY : all utils clean partlyclean
+
+uClibc : $(UCLIBC)
+ rm -rf $@
+ $(MAKE) -C $(UCLIBC) install
+
+$(UCLIBC) : $(UCLIBC).tar.bz2
+ [ -d $@ ] || tar xvjf $<
+ [ -f $(UCLIBC)/Config ] || perl -pe 's/^(INCLUDE_RPC).*/$$1 = true/ ;' \
+ -e 's{^(DEVEL_PREFIX).*}{$$1 = $(UCLIBC_INSTALL)} ;' \
+ -e 's{^(SHARED_LIB_LOADER_PATH).*}{$$1 = /lib} ;' \
+ $(UCLIBC)/extra/Configs/Config.i386 > $(UCLIBC)/Config
+ # Stripping out spurious CVS directories (screws up local cvs update)
+ rm -rf `find $(UCLIBC) -name CVS`
+ $(MAKE) -C $(UCLIBC)
+ install -m 644 $(UCLIBC)/COPYING.LIB COPYING.uClibc
+
+udhcpc : $(UDHCP)
+ install -m 755 -s $(UDHCP)/$@ $@
+
+$(UDHCP) : $(UDHCP).tar.bz2 uClibc
+ [ -d $@ ] || tar xvjf $<
+ if [ ! -f $@/.script.c.patch ]; then \
+ patch -d $@ -b -z .orig < script.c.patch ; \
+ touch $@/.script.c.patch ; \
+ fi
+ $(MAKE) LDFLAGS+=-static -C $(UDHCP)
+ install -m 644 $(UDHCP)/AUTHORS AUTHORS.udhcpc
+ install -m 644 $(UDHCP)/COPYING COPYING.udhcpc
+
+busybox : $(BUSYBOX)
+ install -m 755 -s $(BUSYBOX)/$@ $@
+
+$(BUSYBOX) : $(BUSYBOX).tar.bz2 uClibc
+ [ -d $@ ] || tar xvjf $<
+ perl -pi.orig -e \
+ 's/^.*(#define BB_(FEATURE_NFSMOUNT|INSMOD|PIVOT_ROOT|IFCONFIG|ROUTE)).*/$$1/' \
+ $(BUSYBOX)/Config.h
+ perl -pi.orig -e \
+ 's/^(DOSTATIC).*$$/$$1 = true/' \
+ $(BUSYBOX)/Makefile
+ $(MAKE) -C $(BUSYBOX)
+ install -m 644 $(BUSYBOX)/AUTHORS AUTHORS.busybox
+ install -m 644 $(BUSYBOX)/LICENSE LICENSE.busybox
+
+wlanctl : $(LINUX_WLAN)
+ install -m 755 -s $(LINUX_WLAN)/src/wlanctl/$@ $@
+
+$(LINUX_WLAN) : $(LINUX_WLAN).tar.bz2 uClibc linux-wlan.cfg
+ [ -d $@ ] || tar xvjf $<
+ cd $(LINUX_WLAN) ; ./Configure -d ../linux-wlan.cfg
+ perl -pi.orig -e \
+ 's/(-o wlanctl)/-static $$1/' \
+ $(LINUX_WLAN)/src/wlanctl/Makefile
+ $(MAKE) -C $(LINUX_WLAN)/src/wlanctl
+ install -m 644 $(LINUX_WLAN)/COPYING COPYING.wlanctl
+ install -m 644 $(LINUX_WLAN)/LICENSE LICENSE.wlanctl
+ install -m 644 $(LINUX_WLAN)/THANKS THANKS.wlanctl
+
+mknbi-linux : $(MKNBI)
+
+mknbi : $(MKNBI)
+
+$(MKNBI) : $(MKNBI).tar.bz2
+ [ -d $@ ] || tar xvjf $<
+ if [ ! -f $@/.mknbi-encap.patch ]; then \
+ patch -d $@ -b -z .orig < mknbi-encap.patch ; \
+ touch $@/.mknbi-encap.patch ; \
+ fi
+ make -C $(MKNBI) LIBDIR=`pwd`/$(MKNBI) mknbi
+ install -m 755 $(MKNBI)/mknbi mknbi-linux
+ make -C $(MKNBI) clean
+ make -C $(MKNBI)
+
+initrd-skel : $(UTILS) linuxrc udhcpc-post include-modules
+ rm -rf $@
+ mkdir -p $@
+ mkdir -p $@/dev
+ mkdir -p $@/etc
+ mkdir -p $@/bin
+ mkdir -p $@/lib
+ mkdir -p $@/lib/modules
+ mkdir -p $@/proc
+ mkdir -p $@/sysroot
+ ln -s bin $@/sbin
+ install -m 755 busybox $@/bin/
+ install -m 755 udhcpc $@/bin/
+ install -m 755 wlanctl $@/bin/
+ ln -s busybox $@/bin/sh
+ ln -s busybox $@/bin/echo
+ ln -s busybox $@/bin/mknod
+ ln -s busybox $@/bin/chmod
+ ln -s busybox $@/bin/insmod
+ ln -s busybox $@/bin/ifconfig
+ ln -s busybox $@/bin/route
+ ln -s busybox $@/bin/mount
+ ln -s busybox $@/bin/pivot_root
+ ln -s busybox $@/bin/umount
+ ln -s busybox $@/bin/[
+ ln -s busybox $@/bin/sleep
+ ln -s busybox $@/bin/grep
+
+ install -m 755 linuxrc $@/linuxrc
+ install -m 755 udhcpc-post $@/bin/udhcpc-post
+
+tftpboot/initrd-%.img : initrd-skel
+ ./mkinitrd-net -l `echo $* | tr . " "`
+
+tftpboot/boot-%.nbi : tftpboot/initrd-%.img mknbi-linux
+ ./mknbi-linux --format=nbi --target=linux /boot/vmlinuz $< > $@
+ sudo cp $@ $(tftpbootdir)
+
+all-nbi : all
+ ./mknbi-set -l -v
+ ls tftpboot
+
+prefix = /usr
+sysconfdir = /etc
+bindir = $(prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/share/man
+docdir = $(prefix)/share/doc
+tftpbootdir = /var/lib/tftpboot
+initrdskeldir = $(prefix)/lib/mkinitrd-net/initrd-skel
+
+install :
+ mkdir -p $(libdir)/mknbi
+ mkdir -p $(bindir)
+ mkdir -p $(sysconfdir)
+ mkdir -p $(tftpbootdir)
+ mkdir -p $(initrdskeldir)
+ install -m 755 mkinitrd-net include-modules mknbi-set $(bindir)/
+ cp -a initrd-skel/* $(initrdskeldir)/
+ install -m 644 mknbi-set.conf dhcpd.conf.etherboot.include $(sysconfdir)
+ make -C $(MKNBI) INSTPREFIX=$(prefix) MANDIR=$(mandir)/man1 \
+ DOCDIR=$(docdir)/$(MKNBI) install
diff --git a/gpxe/contrib/initrd/Manifest b/gpxe/contrib/initrd/Manifest
new file mode 100644
index 00000000..b41e7255
--- /dev/null
+++ b/gpxe/contrib/initrd/Manifest
@@ -0,0 +1,15 @@
+initrd/ChangeLog
+initrd/Makefile
+initrd/Manifest
+initrd/README
+initrd/dhcpd.conf.etherboot.include
+initrd/include-modules
+initrd/linux-wlan.cfg
+initrd/linuxrc
+initrd/mkinitrd-net
+initrd/mkinitrd-net.spec
+initrd/mknbi-encap.patch
+initrd/mknbi-set
+initrd/mknbi-set.conf
+initrd/script.c.patch
+initrd/udhcpc-post
diff --git a/gpxe/contrib/initrd/README b/gpxe/contrib/initrd/README
new file mode 100644
index 00000000..5152425a
--- /dev/null
+++ b/gpxe/contrib/initrd/README
@@ -0,0 +1,37 @@
+README for mkinitrd-net
+
+mkinitrd-net enables you to use your distribution's stock kernel for
+diskless workstations, without having to compile in support for the
+relevant network card(s). It creates an initial ramdisk image containing
+the required network-card kernel modules and bootstrap scripts to load the
+module, obtain an IP address via DHCP and mount the root filesystem via
+NFS.
+
+mkinitrd-net also generates a dhcpd.conf file fragment that can be used to
+automate the process of mapping NBI files to clients, based on the PCI IDs
+of their network cards. Etherboot will send the PCI ID of the network
+card to the DHCP server in the etherboot-encapsulated-options field
+(Etherboot 5.0.7 and newer) and the DHCP server can use this to identify
+the correct NBI to point the client towards.
+
+The end result is that:
+
+a) You can avoid the hassle of compiling custom kernels for diskless
+ workstations.
+
+b) Diskless workstations will automatically download the correct
+ kernel+initrd.
+
+c) You have an easier life! :-)
+
+
+
+mkinitrd-net is Copyright Fen Systems Ltd. 2001. mkinitrd-net itself is
+licensed under the GNU GPL. It incorporates code from the uClibc,
+busybox, udhcpc and Etherboot projects, each of which has its own licence
+terms. Standard disclaimers apply.
+
+The copy of mkinitrd-net in the Etherboot contribs is not the
+authoritative copy of mkinitrd-net; please do not make modifications to
+this copy. Patches should be sent to Michael Brown
+<mbrown@fensystems.co.uk>.
diff --git a/gpxe/contrib/initrd/dhcpd.conf.etherboot.include b/gpxe/contrib/initrd/dhcpd.conf.etherboot.include
new file mode 100644
index 00000000..9cec1dc1
--- /dev/null
+++ b/gpxe/contrib/initrd/dhcpd.conf.etherboot.include
@@ -0,0 +1,207 @@
+# dhcpd.conf include file for Etherboot
+#
+# Include this file from your /etc/dhcpd.conf
+# $Id$
+
+# Definition of Etherboot options
+# (taken from vendortags.html)
+
+# We use an encapsulated option space to avoid polluting the site-local DHCP option space
+#
+option space etherboot;
+option etherboot-encapsulated-options code 150 = encapsulate etherboot;
+
+# Definition of option codes within the etherboot-encapsulated-options space
+#
+option etherboot.extensions-path code 18 = string;
+option etherboot.magic code 128 = string;
+option etherboot.kernel-cmdline code 129 = string;
+option etherboot.menu-opts code 160 = string;
+option etherboot.nic-dev-id code 175 = string;
+option etherboot.menu-selection code 176 = unsigned integer 8;
+option etherboot.motd-1 code 184 = string;
+option etherboot.motd-2 code 185 = string;
+option etherboot.motd-3 code 186 = string;
+option etherboot.motd-4 code 187 = string;
+option etherboot.motd-5 code 188 = string;
+option etherboot.motd-6 code 189 = string;
+option etherboot.motd-7 code 190 = string;
+option etherboot.motd-8 code 191 = string;
+option etherboot.image-1 code 192 = string;
+option etherboot.image-2 code 193 = string;
+option etherboot.image-3 code 194 = string;
+option etherboot.image-4 code 195 = string;
+option etherboot.image-5 code 196 = string;
+option etherboot.image-6 code 197 = string;
+option etherboot.image-7 code 198 = string;
+option etherboot.image-8 code 199 = string;
+option etherboot.image-9 code 200 = string;
+option etherboot.image-10 code 201 = string;
+option etherboot.image-11 code 202 = string;
+option etherboot.image-12 code 203 = string;
+option etherboot.image-13 code 204 = string;
+option etherboot.image-14 code 205 = string;
+option etherboot.image-15 code 206 = string;
+option etherboot.image-16 code 207 = string;
+option etherboot.kmod code 254 = string;
+
+# Legacy support for Etherboot options as site-local options (i.e. non-encapsulated)
+# Note: options defined after the switch to encapsulated options should not be defined here
+#
+option legacy-etherboot-magic code 128 = string;
+option legacy-etherboot-kernel-cmdline code 129 = string;
+option legacy-etherboot-menu-opts code 160 = string;
+option legacy-etherboot-menu-selection code 176 = unsigned integer 8;
+option legacy-etherboot-motd-1 code 184 = string;
+option legacy-etherboot-motd-2 code 185 = string;
+option legacy-etherboot-motd-3 code 186 = string;
+option legacy-etherboot-motd-4 code 187 = string;
+option legacy-etherboot-motd-5 code 188 = string;
+option legacy-etherboot-motd-6 code 189 = string;
+option legacy-etherboot-motd-7 code 190 = string;
+option legacy-etherboot-motd-8 code 191 = string;
+option legacy-etherboot-image-1 code 192 = string;
+option legacy-etherboot-image-2 code 193 = string;
+option legacy-etherboot-image-3 code 194 = string;
+option legacy-etherboot-image-4 code 195 = string;
+option legacy-etherboot-image-5 code 196 = string;
+option legacy-etherboot-image-6 code 197 = string;
+option legacy-etherboot-image-7 code 198 = string;
+option legacy-etherboot-image-8 code 199 = string;
+option legacy-etherboot-image-9 code 200 = string;
+option legacy-etherboot-image-10 code 201 = string;
+option legacy-etherboot-image-11 code 202 = string;
+option legacy-etherboot-image-12 code 203 = string;
+option legacy-etherboot-image-13 code 204 = string;
+option legacy-etherboot-image-14 code 205 = string;
+option legacy-etherboot-image-15 code 206 = string;
+option legacy-etherboot-image-16 code 207 = string;
+
+# Apply Etherboot options only for Etherboot clients
+#
+if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" {
+
+ # We must specify this value for etherboot-magic, or Etherboot will
+ # ignore all other options.
+ #
+ option etherboot.magic E4:45:74:68:00:00;
+
+ # Bootfile name: derive from etherboot.kmod (calculated below)
+ # Use boot.nbi if no NIC_DEV_ID option present
+ # (i.e. if etherboot.kmod doesn't get set)
+ # Also pass filename back in filename field
+ #
+ option bootfile-name = pick-first-value ( concat ( "boot-",
+ config-option etherboot.kmod,
+ ".nbi" ),
+ "boot.nbi" ) ;
+ filename = config-option bootfile-name;
+
+ # "Sensible" default values for some options
+
+ # Mount devfs (will probably be needed for a network-boot)
+ option etherboot.kernel-cmdline " devfs=mount";
+
+ # Info message (includes client IP address, MAC address, hardware ID string,
+ # server IP address and name of boot file)
+ option etherboot.motd-4 = concat ( "Using Etherboot to boot ",
+ binary-to-ascii ( 10, 8, ".", leased-address ),
+ " [",
+ binary-to-ascii ( 16, 8, ":", suffix ( hardware, 6 ) ),
+ "] [",
+ pick-first-value ( option etherboot.nic-dev-id, "unknown card" ),
+ "]", 0d:0a, " from ",
+ binary-to-ascii ( 10, 8, ".", option dhcp-server-identifier ),
+ " with file ",
+ config-option tftp-server-name,
+ ":",
+ config-option bootfile-name,
+ " [",
+ pick-first-value ( config-option etherboot.kmod, "unknown module" ),
+ "]", 0d:0a );
+
+ # Legacy site-local option support
+ # If client does not include an etherboot-encapsulated-options field in its DHCPREQUEST, then
+ # it will not understand etherboot-encapsulated-options in the DHCPACK and so we must send
+ # back the options as site-local options (i.e. not encapsulated).
+ # Note: we need do this only for options that existed prior to the switch to encapsulation.
+ #
+ if not exists etherboot-encapsulated-options {
+ option legacy-etherboot-magic = config-option etherboot.magic;
+ option legacy-etherboot-kernel-cmdline = config-option etherboot.kernel-cmdline;
+ option legacy-etherboot-menu-opts = config-option etherboot.menu-opts;
+ option legacy-etherboot-menu-selection = config-option etherboot.menu-selection;
+ option legacy-etherboot-motd-1 = config-option etherboot.motd-1;
+ option legacy-etherboot-motd-2 = config-option etherboot.motd-2;
+ option legacy-etherboot-motd-3 = config-option etherboot.motd-3;
+ option legacy-etherboot-motd-4 = config-option etherboot.motd-4;
+ option legacy-etherboot-motd-5 = config-option etherboot.motd-5;
+ option legacy-etherboot-motd-6 = config-option etherboot.motd-6;
+ option legacy-etherboot-motd-7 = config-option etherboot.motd-7;
+ option legacy-etherboot-motd-8 = config-option etherboot.motd-8;
+ option legacy-etherboot-image-1 = config-option etherboot.image-1;
+ option legacy-etherboot-image-2 = config-option etherboot.image-2;
+ option legacy-etherboot-image-3 = config-option etherboot.image-3;
+ option legacy-etherboot-image-4 = config-option etherboot.image-4;
+ option legacy-etherboot-image-5 = config-option etherboot.image-5;
+ option legacy-etherboot-image-6 = config-option etherboot.image-6;
+ option legacy-etherboot-image-7 = config-option etherboot.image-7;
+ option legacy-etherboot-image-8 = config-option etherboot.image-8;
+ option legacy-etherboot-image-9 = config-option etherboot.image-9;
+ option legacy-etherboot-image-10 = config-option etherboot.image-10;
+ option legacy-etherboot-image-11 = config-option etherboot.image-11;
+ option legacy-etherboot-image-12 = config-option etherboot.image-12;
+ option legacy-etherboot-image-13 = config-option etherboot.image-13;
+ option legacy-etherboot-image-14 = config-option etherboot.image-14;
+ option legacy-etherboot-image-15 = config-option etherboot.image-15;
+ option legacy-etherboot-image-16 = config-option etherboot.image-16;
+ }
+}
+
+# Some options should be set for both Etherboot and the udhcpc client
+#
+if ( ( substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" )
+ or ( substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" ) ) {
+
+ # TFTP server defaults to DHCP server and is specified in both
+ # next-server field and tftp-server-name option field
+ #
+ option tftp-server-name = binary-to-ascii ( 10, 8, ".", config-option dhcp-server-identifier );
+ server-name = config-option tftp-server-name;
+ next-server = config-option dhcp-server-identifier;
+
+ # Root path defaults to root of TFTP server
+ option root-path = concat ( config-option tftp-server-name, ":/" );
+
+ # A fallback hostname, generated from the IP address
+ option host-name = concat ( "client_", binary-to-ascii ( 10, 8, "_", leased-address ) );
+}
+
+# Force some items onto parameter request list for udhcp
+#
+if substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" {
+ # Forcibly add root-path to list
+ option dhcp-parameter-request-list = concat ( option dhcp-parameter-request-list, 11 );
+}
+
+# Etherboot sends a string to identify the NIC in etherboot.nic-dev-id.
+# For PCI NICs, this string is of the form "PCI:vvvv:dddd" where vvvv is the
+# vendor identifier and dddd the device identifier, in lower-case ASCII hex.
+# For ISA NICs, the format of the string is "ISA:..." where ... is not yet
+# decided upon.
+#
+# We use the identifier to select the NBI image that will be specified via
+# the "bootfile-name" option.
+#
+# PCI NICs - use PCI vendor and device IDs
+# Listed in file generated by mknbi-set
+#
+include "/etc/dhcpd.conf.etherboot-pcimap.include";
+
+# ISA NICs
+#
+if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" {
+ if exists etherboot.nic-dev-id {
+
+ }
+}
diff --git a/gpxe/contrib/initrd/include-modules b/gpxe/contrib/initrd/include-modules
new file mode 100755
index 00000000..60e76fc6
--- /dev/null
+++ b/gpxe/contrib/initrd/include-modules
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+#
+# Retrieve modules required for an initrd image
+# $Id$
+
+unless ( @ARGV ) {
+ die "Syntax: $0 [ -d target_directory ] module_1 module_2 module_3\n"
+}
+
+# Parse command line arguments
+my @requested_modules = ();
+my $target_dir = "";
+my $kernel_ver;
+my $quiet;
+chomp ( my $current_kernel_ver = `uname -r` );
+while ( $_ = shift ) {
+ if ( /-d/ ) { $target_dir = shift }
+ elsif ( /-k/ ) { $kernel_ver = shift }
+ elsif ( /-q/ ) { $quiet = 1 }
+ else { push @requested_modules, $_ };
+}
+
+# Create target directory if required
+if ( $target_dir ) {
+ print STDERR "Target directory is $target_dir\n" unless $quiet;
+ system ( "mkdir -p $target_dir" );
+ chdir $target_dir;
+}
+
+# Use modprobe -nav to retrieve locations of modules and their dependencies
+print STDERR "Requested modules ". join (' ', @requested_modules)."\n" unless $quiet;
+my @modules_dups;
+foreach my $module ( @requested_modules ) {
+ my @module_list = map { /^\S+\s+(.*)$/ ; $1 } `/sbin/modprobe -nva $module`;
+ die "Cannot find any modules matching $module\n" unless @module_list;
+ push @modules_dups, @module_list;
+}
+
+# Remove duplicates from list
+my %module_basenames = ();
+my @modules = ();
+foreach my $module ( @modules_dups ) {
+ # Ugly hack : assume that dependencies are independent of kernel version
+ # This seems to be necessary because we can't run modprobe and specify
+ # an alternate modules.dep file; it refuses to understand lines of the
+ # form "depfile=XXX" as documented in modules.conf(5)
+ $module =~ s/$current_kernel_ver/$kernel_ver/ if $kernel_ver;
+ push @modules, $module unless $module_basenames{$module};
+ ( my $basename ) = ( $module =~ /([^\/]+)\.o/ );
+ $module_basenames{$module} = $basename;
+}
+
+# Process module list
+print "#!/bin/sh\n";
+foreach my $module ( @modules ) {
+ my $basename = $module_basenames{$module};
+ # Report via stdout
+ print STDERR "Using module $basename from $module\n" unless $quiet;
+ # Copy uncompressed module to current directory
+ system ("gunzip -c $module > $basename.o");
+ # Print insmod line to stdout
+ print "insmod $basename\n";
+}
diff --git a/gpxe/contrib/initrd/linux-wlan.cfg b/gpxe/contrib/initrd/linux-wlan.cfg
new file mode 100644
index 00000000..7df4a059
--- /dev/null
+++ b/gpxe/contrib/initrd/linux-wlan.cfg
@@ -0,0 +1,7 @@
+# Dummy config file for building only wlanctl
+# $Id$
+
+PRISM2_PLX=n
+PRISM2_PCMCIA=n
+PRISM2_PCI=n
+PRISM2_USB=n
diff --git a/gpxe/contrib/initrd/linuxrc b/gpxe/contrib/initrd/linuxrc
new file mode 100644
index 00000000..24bdb0df
--- /dev/null
+++ b/gpxe/contrib/initrd/linuxrc
@@ -0,0 +1,76 @@
+#!/bin/sh
+# $Id$
+
+PATH=/sbin:/bin
+
+echo Busybox /linuxrc starting
+
+echo Mounting /proc filesystem
+mount -t proc none /proc
+
+echo=echo
+if grep '\bquiet\b' /proc/cmdline > /dev/null; then
+ echo=true
+ quiet=1
+fi
+
+$echo Creating root device
+mknod /dev/root b 1 0 2>/dev/null
+chmod 700 /dev/root
+echo 0x100 > /proc/sys/kernel/real-root-dev
+
+$echo Inserting modules
+if [ -z "$quiet" ]; then
+ /bin/insert-modules
+else
+ /bin/insert-modules >/dev/null
+fi
+
+$echo Bringing up loopback interface
+ifconfig lo 127.0.0.1 up
+route add -net 127.0.0.0 netmask 255.0.0.0 lo
+
+# Hack required for prism2 cards
+# It is not yet possible to use iwconfig to configure these cards,
+# so we need wlanctl.
+if ifconfig wlan0 down 2> /dev/null; then
+ $echo Setting up wireless link
+ wlanctl wlan0 lnxreq_ifstate ifstate=enable
+ wlanctl wlan0 lnxreq_autojoin ssid= authtype=opensystem
+fi
+
+$echo Obtaining IP address via DHCP
+$echo Trying to obtain IP address via wired link [eth0]
+if udhcpc -i eth0 -f -n -q -s /bin/udhcpc-post; then
+ $echo Successfully obtained IP address via wired link [eth0]
+else
+ $echo Failed to obtain IP address via wired link [eth0]
+ $echo Trying to obtain IP address via wireless link [wlan0]
+ udhcpc -i wlan0 -f -n -q -s /bin/udhcpc-post
+fi
+
+if [ -d /sysroot/initrd ]; then
+ $echo Unmounting /proc prior to pivot_root
+ umount /proc
+
+ $echo Pivoting root to /sysroot
+ pivot_root /sysroot /sysroot/initrd
+ cd /
+
+ $echo Remounting devfs at correct place
+ mount -t devfs none /dev
+
+ $echo Releasing locks on old devfs
+ exec 0</dev/null
+ exec 1>/dev/console
+ exec 2>/dev/console
+
+ $echo Unmounting old devfs
+ umount /initrd/dev
+else
+ # Failed to mount root: report error and hang
+ echo FATAL ERROR: Failed to mount root filesystem
+ echo Press Alt-SysRq-B or hit the reset switch to reboot
+ while : ; do sleep 6000 ; done
+fi
+
diff --git a/gpxe/contrib/initrd/mkinitrd-net b/gpxe/contrib/initrd/mkinitrd-net
new file mode 100755
index 00000000..0c95ebd1
--- /dev/null
+++ b/gpxe/contrib/initrd/mkinitrd-net
@@ -0,0 +1,165 @@
+#!/bin/sh
+#
+# $Id$
+# initrd builder for network booting
+
+# Utility function to determine whether or not a filesystem is usable for
+# loopback mounts. Lifted verbatim from Erik Troan's mkinitrd script.
+#
+is_good_fs() {
+ local parttype= tmpname=
+ local dir=$1
+ [[ -d $dir ]] || return 1
+ [[ -w $dir ]] || return 1
+ [[ $dir == */ ]] && dir=${dir%/}
+ parttype=$(awk "{if (\$2 == \""$dir"\") print \$3 }" /proc/mounts)
+
+ while tmpname=${dir%/*} && [[ -z $parttype ]];do
+ [[ -z $tmpname ]] && tmpname=/
+ parttype=$(awk "{if (\$2 == \""$tmpname"\") print \$3 }" /proc/mounts)
+ dir=$tmpname
+ done
+
+ case $parttype in
+ nfs|tmpfs) return 1;;
+ *) return 0;
+ esac
+}
+
+# Find a suitable temporary directory (i.e. not tmpfs or nfs)
+if is_good_fs $TMPDIR; then
+ tmpdir=$TMPDIR
+elif is_good_fs /tmp; then
+ tmpdir=/tmp
+elif is_good_fs /var/tmp; then
+ tmpdir=/var/tmp
+elif is_good_fs /root/tmp; then
+ tmpdir=/root/tmp
+else
+ echo "Cannot use a tmp directory" >&2
+ exit 1
+fi
+
+# Default settings (some can be overridden by command-line options)
+include_modules=include-modules
+initrd_skel=/usr/lib/mkinitrd-net/initrd-skel
+kernel_ver=`uname -r`
+use_sudo=y
+keep=n
+output_dir=/var/lib/tftpboot
+make_link=y
+quiet=
+
+# No need to use sudo if we are root
+if [ $UID -eq 0 ]; then
+ use_sudo=n
+fi
+
+USAGE="Usage: $0 [-k|--kernel <kernel_ver>] [-n|--nolink] [-q|--quiet] [-l|--local] [--nosudo] [--keep] [--help] module_list ..."
+
+# Parse command-line options
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -l|--local)
+ shift
+ use_local=y ;;
+ -k|--kernel)
+ shift
+ kernel_ver=$1
+ shift ;;
+ --nosudo) shift ; use_sudo=n ;;
+ --keep) shift ; keep=y ;;
+ --n|--nolink)
+ shift ; make_link=n ;;
+ -q|--quiet) shift ; quiet=-q ;;
+ --help) shift ; do_help=y ;;
+ --) shift ; break ;;
+ -*) echo "${0}: ${1}: invalid option" >&2
+ echo $USAGE >& 2
+ exit 2 ;;
+ *) break ;;
+ esac
+done
+
+# Build list of requested modules
+modules="$*"
+requested_modules="$modules"
+modules="$modules nfs" # Always require nfs for nfs mount
+modules="$modules af_packet" # Always require af_packet for udhcpc
+
+# --help => Print help message
+if [ "$do_help" == "y" ]; then
+ echo $USAGE
+ echo " -k, --kernel Specify kernel version"
+ echo " -n, --nolink Do not create a matching symbolic link"
+ echo " -l, --local Run locally from CVS (for developers only)"
+ echo " --nosudo Do not use sudo (i.e. must run as root instead)"
+ echo " --keep Keep temporary files instead of deleting them"
+ exit 0;
+fi
+
+# --local => we are running directly from CVS, rather than
+# from an installed copy, so use local files and directories
+if [ "$use_local" == "y" ]; then
+ include_modules=./include-modules
+ initrd_skel=initrd-skel
+ output_dir=tftpboot
+fi
+
+# If use_sudo is set, check that sudo exists
+sudo=/usr/bin/sudo
+if [ "$use_sudo" == "y" ]; then
+ if [ ! -x $sudo ]; then
+ use_sudo=n
+ echo "WARNING: --nosudo not specified but $sudo not found"
+ fi
+fi
+if [ "$use_sudo" == "n" ]; then
+ sudo=
+fi
+
+# Create temporary working files
+initrd=`mktemp -d ${tmpdir}/initrd.XXXXXX`
+initrdimg=`mktemp ${tmpdir}/initrd.img.XXXXXX`
+initrdmnt=`mktemp -d ${tmpdir}/initrd.mnt.XXXXXX`
+
+# Copy skeleton into temporary area
+cp -a $initrd_skel/* $initrd/
+mkdir -p $initrd/lib/modules/$kernel_ver
+$include_modules $quiet -k $kernel_ver -d $initrd/lib/modules/$kernel_ver $modules > $initrd/bin/insert-modules || exit 1
+chmod 755 $initrd/bin/insert-modules
+
+# Create empty ext2fs image file
+dd if=/dev/zero bs=1k of=$initrdimg count=$((`du -sk $initrd | cut -f1` * 7 / 6)) 2> /dev/null
+/sbin/mke2fs -q -F $initrdimg 2> /dev/null
+
+# Mount image file, copy files on, create /dev entries, display free space, umount
+$sudo mount -o loop $initrdimg $initrdmnt
+cp -a $initrd/* $initrdmnt/
+$sudo mknod $initrdmnt/dev/console c 5 1
+$sudo mknod $initrdmnt/dev/null c 1 3
+$sudo mknod $initrdmnt/dev/ram b 1 1
+$sudo mknod $initrdmnt/dev/systty c 4 0
+for i in 1 2 3 4; do $sudo mknod $initrdmnt/dev/tty$i c 4 $i; done
+if [ "$quiet" == "n" ]; then
+ df -h $initrdmnt
+fi
+$sudo umount $initrdmnt
+
+# Create output file
+initrd_suffix=`echo $requested_modules | tr " " .`
+gzip -9 -n -c $initrdimg > $output_dir/initrd-$initrd_suffix.$kernel_ver.img
+
+# Create symlink
+if [ "$make_link" == "y" ]; then
+ link=$output_dir/initrd-$initrd_suffix.img
+ [ -L $link ] && rm -f $link
+ ln -s initrd-$initrd_suffix.$kernel_ver.img $link
+fi
+
+# Remove temporary files
+if [ "$keep" == "n" ]; then
+ rm -rf $initrd
+ rm -f $initrdimg
+ rmdir $initrdmnt
+fi
diff --git a/gpxe/contrib/initrd/mkinitrd-net.spec b/gpxe/contrib/initrd/mkinitrd-net.spec
new file mode 100644
index 00000000..94f5d9db
--- /dev/null
+++ b/gpxe/contrib/initrd/mkinitrd-net.spec
@@ -0,0 +1,112 @@
+%define name mkinitrd-net
+%define version 1.10
+%define release 1fs
+
+Summary: Network-booting initrd builder
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Source0: %{name}-%{version}.tar.bz2
+Source1: http://belnet.dl.sourceforge.net/sourceforge/etherboot/mknbi-1.2.tar.bz2
+Source2: http://www.busybox.net/downloads/busybox-0.60.3.tar.bz2
+Source3: http://www.uclibc.org/downloads/uClibc-0.9.11.tar.bz2
+Source4: ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/linux-wlan-ng-0.1.13.tar.bz2
+Source5: http://udhcp.busybox.net/source/udhcp-0.9.7.tar.bz2
+Copyright: GPL/LGPL/MPL
+Group: System/Kernel and hardware
+BuildRoot: %{_tmppath}/%{name}-buildroot
+Prefix: %{_prefix}
+Requires: tftp-server
+
+%description
+mkinitrd-net allows you to build initial ramdisk images (initrds) suitable
+for use with Etherboot and other network-booting software. This package
+contains two main utilities: mkinitrd-net (to build an initrd containing a
+specified set of network-card modules) and mknbi (to generate
+Etherboot-usable NBI images from a given kernel and initrd). It also
+contains a helper script mknbi-set which will maintain sets of initrds to
+match all your currently-installed kernels.
+
+mkinitrd-net uses code from the uClibc, busybox, udhcp and Etherboot
+projects.
+
+%prep
+%setup -n initrd -a1 -a2 -a3 -a4 -a5
+
+%build
+%make LIBDIR=%{_libdir}/mknbi
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%makeinstall tftpbootdir=$RPM_BUILD_ROOT%{_localstatedir}/tftpboot
+touch $RPM_BUILD_ROOT%{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include
+ln -s %{_localstatedir}/tftpboot $RPM_BUILD_ROOT/tftpboot
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+%{_bindir}/mknbi-set
+
+%triggerin -- kernel kernel-smp kernel-secure kernel-enterprise
+%{_bindir}/mknbi-set
+
+%files
+%defattr(-,root,root)
+%config(noreplace) %{_sysconfdir}/mknbi-set.conf
+%config(noreplace) %{_sysconfdir}/dhcpd.conf.etherboot.include
+%ghost %{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include
+%{_bindir}/mknbi-*
+%{_bindir}/mkelf-*
+%{_bindir}/dis*
+%{_bindir}/mkinitrd-net
+%{_bindir}/include-modules
+%{_libdir}/mknbi
+%{_libdir}/mkinitrd-net
+%{_mandir}/man*/*
+/tftpboot
+%{_localstatedir}/tftpboot
+%doc README
+%doc AUTHORS.busybox LICENSE.busybox
+%doc AUTHORS.udhcpc COPYING.udhcpc
+%doc COPYING.wlanctl LICENSE.wlanctl THANKS.wlanctl
+%doc COPYING.uClibc
+%docdir %{_docdir}/mknbi*
+%{_docdir}/mknbi*
+
+%changelog
+* Fri Jul 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.10-1fs
+- Support for new binary etherboot.nic-dev-id structure
+- Added --kernel option patch from Stew Benedict at MandrakeSoft
+- Only try to use sudo if we are not already root
+
+* Wed Jun 05 2002 Michael Brown <mbrown@fensystems.co.uk> 1.9-1fs
+- Modifications to allow DHCP, TFTP and NFS servers to be separate machines.
+
+* Thu May 30 2002 Michael Brown <mbrown@fensystems.co.uk> 1.8-1fs
+- /tftpboot symlinked to /var/lib/tftpboot
+- Has ability to be quiet if "quiet" specified on kernel cmdline
+
+* Sun May 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.7-1fs
+- PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include
+
+* Fri May 24 2002 Michael Brown <mbrown@fensystems.co.uk> 1.6-1fs
+- Bugfixes, migrated /tftpboot to /var/lib/tftpboot
+
+* Thu May 23 2002 Michael Brown <mbrown@fensystems.co.uk> 1.5-1fs
+- Now includes dhcpd.conf.etherboot.include
+- Automatically scans for all network modules in the pcimap file
+
+* Wed May 08 2002 Michael Brown <mbrown@fensystems.co.uk> 1.4-1fs
+- Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.3-1fs
+- During %make, LIBDIR must be set for mknbi
+- Added %post scriptlet since %trigger seems not to be being triggered...
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.2-1fs
+- Added extra sources instead of requiring "make" to download them
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.1-1fs
+- First attempt at an RPM package
+
diff --git a/gpxe/contrib/initrd/mknbi-set b/gpxe/contrib/initrd/mknbi-set
new file mode 100755
index 00000000..e61acac9
--- /dev/null
+++ b/gpxe/contrib/initrd/mknbi-set
@@ -0,0 +1,200 @@
+#!/usr/bin/perl -w
+#
+# $Id$
+# Maintains set of NBIs based on currently-installed kernels
+# Network card module sets are taken from /etc/mknbi-set.conf
+
+use strict;
+use vars qw($verbosity);
+
+use constant EB_PCI_DEVICE => 1;
+
+# Utility function: calculate output id given a kernel file name and
+# space-separated list of modules
+sub calc_output_id ($$) {
+ my $kernel = shift;
+ my $moduleset = shift;
+ my $kernel_ver = "";
+ ( $kernel_ver ) = ( $kernel =~ /vmlinuz-(.*)$/ );
+ ( my $output_id = "$moduleset".( $kernel_ver ? ".$kernel_ver" : "" ) ) =~ tr/,/./;
+ return ( $kernel_ver, $output_id );
+}
+
+# Utility function: read modules.pcimap-style file
+# Add modules to modulesets hash, write out dhcpd.conf fragment
+sub read_config_file ($$$$) {
+ my $configfile = shift;
+ my $modulesets = shift;
+ my $dhcpfh = shift;
+ my $alwaysuse = shift;
+
+ print "Scanning through $configfile for network modules...\n" if $verbosity >= 1;
+ open CF, $configfile or die "Could not open $configfile: $!\n";
+ chomp ( my $tempmodule = `mktemp /tmp/mknbi-set.XXXXXX` );
+ chomp ( my $cwd = `pwd` ); chdir '/'; # Modprobe searches the current directory...
+ print $dhcpfh " \# Generated from $configfile\n";
+ while (<CF>) {
+ chomp;
+ next if /^[\#;]/ or /^\s*$/;
+ ( my $module, undef, my $vendor, my $device ) = /^(\S+)(\s+(\S+)\s+(\S+))?/ ;
+ $modulesets->{$module} = 1 if $alwaysuse;
+ if ( ! exists $modulesets->{$module} ) {
+ # Check to see if module is a network module
+ # Only do this the first time we encounter a module
+ my @modulepaths = `/sbin/modprobe -l $module.o*` ;
+ chomp ( my $modulepath = $modulepaths[0] );
+ if ( $modulepath ) {
+ if ( $modulepath =~ /.o.gz$/ ) {
+ system ( "zcat $modulepath > $tempmodule" );
+ } else {
+ system ( "cp $modulepath $tempmodule" );
+ }
+ $modulesets->{$module} = 0;
+ foreach ( `nm $tempmodule` ) {
+ chomp;
+ $modulesets->{$module} = 1 if /(ether|wlan)/ ;
+ }
+ unlink $tempmodule;
+ } else {
+ print STDERR "Cannot locate module $module specified in $configfile\n";
+ }
+ }
+ if ( $modulesets->{$module} ) {
+ if ( $vendor ) {
+ print "$module ($vendor,$device) listed in $configfile\n" if $verbosity >= 2;
+ printf $dhcpfh ( " if option etherboot.nic-dev-id = %02x:%02x:%02x:%02x:%02x { option etherboot.kmod \"%s\"; }\n",
+ EB_PCI_DEVICE,
+ ( hex($vendor) >> 8 ) & 0xff, hex($vendor) & 0xff,
+ ( hex($device) >> 8 ) & 0xff, hex($device) & 0xff,
+ $module );
+ } else {
+ print "$module (without PCI IDs) listed in $configfile\n" if $verbosity >= 2;
+ }
+ }
+ }
+ close CF;
+ print $dhcpfh "\n";
+ chdir $cwd;
+}
+
+my $conffile = '/etc/mknbi-set.conf';
+my $mkinitrd_net = 'mkinitrd-net';
+my $mknbi = 'mknbi-linux';
+my $output_dir = '/var/lib/tftpboot';
+my $dhcpfile = '/etc/dhcpd.conf.etherboot-pcimap.include';
+my $use_local;
+our $verbosity = 1;
+my $modulesets = {};
+my $kernel = '';
+my @kernels = ();
+
+my $usage="Usage: $0 [-l|--local] [-q] [-v] [-r|--refresh module[,module...]] [--help]";
+
+# Parse command-line options
+while ( $_ = shift ) {
+ if ( /-l|--local/ ) {
+ $conffile = 'mknbi-set.conf';
+ $mkinitrd_net = './mkinitrd-net';
+ $mknbi = './mknbi-linux --format=nbi --target=linux';
+ $output_dir = 'tftpboot';
+ $dhcpfile = 'tftpboot/dhcpd.conf.etherboot-pcimap.include';
+ $use_local = 1;
+ } elsif ( /-r|--refresh/ ) {
+ my $moduleset = shift;
+ $modulesets->{$moduleset} = 1;
+ } elsif ( /-k|--kernel/ ) {
+ $kernel = shift;
+ } elsif ( /-v|--verbose/ ) {
+ $verbosity++;
+ } elsif ( /-q|--quiet/ ) {
+ $verbosity--;
+ } elsif ( /--help/ ) {
+ die "$usage\n".
+ " -k, --kernel Build NBIs for a particular kernel\n".
+ " -l, --local Run locally from CVS (for developers only)\n".
+ " -r, --refresh Refresh NBI for a particular module\n".
+ " -v, --verbose Be more verbose\n".
+ " -q, --quiet Be less verbose\n";
+ } else {
+ die "$usage\n";
+ }
+}
+
+# Get set of current kernels
+if ($kernel) {
+ @kernels = ( $kernel );
+} else {
+ @kernels = glob('/boot/vmlinuz*');
+}
+die "Could not find any kernels in /boot\n" unless @kernels;
+
+# If modules have been specified via --refresh, do not scan for modules or rewrite the
+# dhcpd.conf fragment file
+unless ( %$modulesets ) {
+ # Write dhcpd.conf fragment file
+ open my $dhcpfh, ">$dhcpfile" or die "Could not open $dhcpfile for writing: $!\n";
+ print $dhcpfh "# Etherboot PCI ID -> Linux kernel module mapping file\n";
+ print $dhcpfh "# Generated by mknbi-set on ".(scalar localtime)."\n";
+ print $dhcpfh "#\n";
+ print $dhcpfh "if substring ( option vendor-class-identifier, 0, 9 ) = \"Etherboot\" {\n";
+ print $dhcpfh " if exists etherboot.nic-dev-id {\n";
+ print $dhcpfh " \# Legacy nic-dev-id mechanism: there are some DLink DFE538 cards in circulation that\n";
+ print $dhcpfh " \# predated the change to the new nic-dev-id binary structure\n";
+ print $dhcpfh " if option etherboot.nic-dev-id = \"PCI:1186:1300\" { option etherboot.kmod \"8139too\"; }\n";
+ print $dhcpfh "\n";
+
+ # Get set of network modules to build NBIs for
+ # Read explicitly-specified module sets from $conffile
+ read_config_file($conffile, $modulesets, $dhcpfh, 1);
+ # Obtain list of all network modules from pcimap file
+ my $pcimap;
+ foreach ( `/sbin/modprobe -c` ) {
+ $pcimap = $1 if /^pcimap.*?=(.*)$/;
+ }
+ if ( $pcimap ) {
+ read_config_file($pcimap, $modulesets, $dhcpfh, 0);
+ } else {
+ print STDERR "Could not identify pcimap file\n";
+ }
+ # Finish off dhcpd.conf fragment file
+ print $dhcpfh " }\n}\n";
+ close $dhcpfh;
+}
+
+# Build initrd and nbi for each kernel-moduleset combination
+foreach my $moduleset ( sort keys %$modulesets ) {
+ next unless $modulesets->{$moduleset}; # Ignore if value is 0
+ print "Building NBIs for module set $moduleset\n" if $verbosity >= 1;
+ foreach my $kernel ( @kernels ) {
+ ( my $kernel_ver, my $output_id ) = calc_output_id ( $kernel, $moduleset );
+ if ( -l $kernel ) {
+ # Symbolic link; create matching symlink
+ my $real_kernel = readlink ( $kernel );
+ ( my $real_kernel_ver, my $real_output_id ) = calc_output_id ( $real_kernel, $moduleset );
+ print "Symlinking $output_id to $real_output_id\n" if $verbosity >= 2;
+ my $initrd_file = "$output_dir/initrd-$output_id.img";
+ unlink ( $initrd_file ) if -l $initrd_file;
+ system ( "ln -s initrd-$real_output_id.img $initrd_file" ) == 0 or print STDERR "Could not symlink $initrd_file to initrd-$real_output_id.img: $!\n";
+ my $nbi_file = "$output_dir/boot-$output_id.nbi";
+ unlink ( $nbi_file ) if -l $nbi_file;
+ system ( "ln -s boot-$real_output_id.nbi $nbi_file" ) == 0 or print STDERR "Could not symlink $nbi_file to boot-$real_output_id.nbi: $!\n";
+ } else {
+ # Real file: create initrd and nbi
+ print "Creating initrd and nbi for $output_id\n" if $verbosity >= 2;
+ ( my $moduleset_spaces = $moduleset ) =~ tr/,/ /;
+ my $initrd_cmd = "$mkinitrd_net --nolink ".
+ ( $use_local ? "--local " : "" ).
+ ( $kernel_ver ? "--kernel $kernel_ver " : "" ).
+ ( $verbosity >= 2 ? "" : "-q " ).
+ $moduleset_spaces;
+ print "$initrd_cmd\n" if $verbosity >= 3;
+ if ( system ( $initrd_cmd ) == 0 ) {
+ my $mknbi_cmd = "$mknbi $kernel $output_dir/initrd-$output_id.img > $output_dir/boot-$output_id.nbi";
+ print "$mknbi_cmd\n" if $verbosity >= 3;
+ system ( $mknbi_cmd ) == 0 or print STDERR "mknbi failed: $!\n";
+ } else {
+ print STDERR "$initrd_cmd failed: $!\n";
+ }
+ }
+ }
+}
diff --git a/gpxe/contrib/initrd/mknbi-set.conf b/gpxe/contrib/initrd/mknbi-set.conf
new file mode 100644
index 00000000..f24846ca
--- /dev/null
+++ b/gpxe/contrib/initrd/mknbi-set.conf
@@ -0,0 +1,27 @@
+# This file specifies the network cards for which NBI images should be built
+# Each line contains a list of kernel modules to be used, separated by commas
+# You can optionally specify PCI vendor and device IDs that should be automatically
+# mapped to this module.
+#
+# The format is similar to modutils' modules.pcimap file.
+#
+# Examples:
+# RTL8139-based ethernet card
+; 8139too
+# RTL8139-based ethernet card with PCI IDs vendor=0x1186, device=0x1300
+; 8139too 0x1186 0x1300
+# RTL8139 and Prism2_pci in same image
+; 8139too,prism2_pci
+
+# Some modules do not include the MODULE_DEVICE_TABLE macro, and so end up not
+# being listed in the pcimap file. These modules are included here to force
+# the creation of corresponding initrds.
+prism2_pci 0x1260 0x3873
+prism2_plx 0x1638 0x1100
+prism2_plx 0x16ab 0x1101
+prism2_plx 0x16ab 0x1102
+prism2_plx 0x1385 0x4100
+prism2_plx 0x15e8 0x0130
+prism2_plx 0x16ec 0x3685
+prism2_plx 0x16ab 0x1102
+prism2_plx 0x15e8 0x0131
diff --git a/gpxe/contrib/initrd/script.c.patch b/gpxe/contrib/initrd/script.c.patch
new file mode 100644
index 00000000..127b881c
--- /dev/null
+++ b/gpxe/contrib/initrd/script.c.patch
@@ -0,0 +1,11 @@
+--- script.c.orig Tue Apr 2 23:49:33 2002
++++ script.c Wed Jun 5 14:17:22 2002
+@@ -179,7 +179,7 @@
+ }
+ if (packet->siaddr) {
+ envp[j] = malloc(sizeof("siaddr=255.255.255.255"));
+- sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->yiaddr);
++ sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);
+ }
+ if (!(over & FILE_FIELD) && packet->file[0]) {
+ /* watch out for invalid packets */
diff --git a/gpxe/contrib/initrd/udhcpc-post b/gpxe/contrib/initrd/udhcpc-post
new file mode 100644
index 00000000..395d6c59
--- /dev/null
+++ b/gpxe/contrib/initrd/udhcpc-post
@@ -0,0 +1,25 @@
+#!/bin/sh
+# $Id$
+
+if [ "$1" = "deconfig" ]; then
+ ifconfig $interface 0.0.0.0 up
+else if [ "$1" = "bound" ] ; then
+ echo UDHCPC: I am $ip [$hostname], booting from $serverid
+ [ -n "$hostname" ] && echo $hostname > /proc/sys/kernel/hostname
+ [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+ [ -n "$subnet" ] && NETMASK="netmask $subnet"
+ ifconfig $interface $ip $BROADCAST $NETMASK
+ route add default gw $router dev $interface
+ echo -n > /etc/resolv.conf
+ for i in $dns; do
+ echo nameserver $i >> /etc/resolv.conf
+ done
+ [ -n "$siaddr" ] || siaddr=$serverid
+ [ -n "$rootpath" ] || rootpath=$siaddr:/
+ echo Mounting root filesystem $rootpath at /sysroot
+ echo If this appears to hang, check that the server of $rootpath is able to
+ echo reverse-map my IP address $ip to obtain my hostname $hostname
+ mount -t nfs -o nolock,rsize=8192,wsize=8192 $rootpath /sysroot
+ fi
+fi
+
diff --git a/gpxe/contrib/linux-2.0-transname.lsm b/gpxe/contrib/linux-2.0-transname.lsm
new file mode 100644
index 00000000..4a590968
--- /dev/null
+++ b/gpxe/contrib/linux-2.0-transname.lsm
@@ -0,0 +1,93 @@
+Xref: news.nsw.CSIRO.AU comp.os.linux.announce:2827
+Path: news.nsw.CSIRO.AU!metro!metro!munnari.OZ.AU!news.ecn.uoknor.edu!news.wildstar.net!news.ececs.uc.edu!newsrelay.netins.net!newsfeed.dacom.co.kr!arclight.uoregon.edu!feed1.news.erols.com!howland.erols.net!newsfeed.internetmci.com!in3.uu.net!liw.clinet.fi!usenet
+From: schoebel@informatik.uni-stuttgart.de (Thomas Schoebel-Theuer)
+Newsgroups: comp.os.linux.announce
+Subject: linux-2.0.21-transname - Patch for easier pool administration
+Followup-To: comp.os.linux.misc
+Date: 30 Oct 1996 10:53:38 GMT
+Organization: Informatik, Uni Stuttgart, Germany
+Lines: 76
+Approved: linux-announce@news.ornl.gov (Lars Wirzenius)
+Message-ID: <pgpmoose.199610301253.4416@liw>
+NNTP-Posting-Host: liw
+X-Auth: PGPMoose V1.1 PGP comp.os.linux.announce
+ iQBVAwUBMnczrjiesvPHtqnBAQEO6gH/WRtFpTPyVtwi0cFVPZ1Xhn8cvfb6i3mk
+ LQY2kgpAPquP2TeXYWb5Ta3HxqK15pR1AgaEy5BmPS6+66ixZFvKRQ==
+ =hhea
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+linux-2.0.21-transname.patch enables diskless clients, X-terminals etc to
+mount the *root filesystem* of the server. This makes administration of
+large pools *a lot* easier.
+
+Currently different diskless clients must have their root "/" on different
+directories on the server, beause each client has _some_ different
+configuration files. However, most administration files (typically about 99%)
+have the same contents on the clients and on the server, but have to be
+(and maintained separately) just because of the 1% differences.
+
+This duplication causes very large efforts in practice, since at least
+the /etc directory has to be duplicated for every client. Even in /etc
+many files are identical, for example sendmail.cf, initrc scripts and
+others. Maintaining a large pool means to ensure coherence amoung the
+duplicates. Classical methods like symlinks are unconvenient
+for this task because they have to be valid in the view of mounted
+filesystems at the client, not at the server.
+
+linux-2.0-transname.patch overcomes this problem by allowing filenames
+to be context-dependend. For example, if you have a file "/etc/config"
+that should differ on the hosts "myserver" and "myclient", you just
+create two different files named "/etc/config#host=myserver#" and
+"/etc/config#host=myclient#". On host "myserver", the file
+"/etc/config#host=myserver#" will appear as if it were hardlinked to
+file "/etc/config" (without the #...=...# suffix). On host "myclient",
+the corresponding other file will appear as "/etc/config". So you
+can access the right file contents under the same name, depending
+on which host you are.
+
+As a result, you may use different contexts for e.g. /etc/fstab, but
+have one shared /etc/passwd for all pool machines. So you don't need
+yp or NYS any more.
+
+The kernel patch was developped for and is used at our Linux pool at the
+University of Stuttgart with good results. Maintainance of the pool is
+at a minimum, and adding new clients is a child's play. No worry with
+keeping up mail configurations, newly installed tools, changed /etc/services,
+/etc/shells, /etc/resolv.conf and many, many others. In contrast to a
+sophisticated symlink solution, adding a new file to the /etc directory
+is seen immediately by all clients. I never had less trouble with
+administration before.
+
+I just uploaded the patch to
+ ftp://ftp.lmh.ox.ac.uk
+ where it should appear in /pub/linux-kernel-patch-archive/
+and also to
+ ftp://sunsite.unc.edu/pub/Linux/Incoming/
+ where it should be moved to /pub/Linux/kernel/patches/misc/ soon.
+
+More details can be found in the README there, and also in the
+configure-help.
+
+Enjoy,
+
+- -- Thomas
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.3i
+Charset: noconv
+
+iQCVAwUBMnczhYQRll5MupLRAQHzuwP9HGYa4I3bZpt22Y3oQIwEKZGfvnaS5AaD
+fVG8wOQ/T7Nrant9JtTktsTVlxGVlYVnziRY4c0ew2qExapK9FqY/ItN0NJXy5aT
+a4eSkn86rp6Un7m90RK1xVY5AyVAq49Rdw2StGxr7uj+davnmg3Np+U0MiAILq91
+52jKGaR3fvc=
+=LSD6
+-----END PGP SIGNATURE-----
+
+--
+This article has been digitally signed by the moderator, using PGP.
+http://www.iki.fi/liw/lars-public-key.asc has PGP key for validating signature.
+Send submissions for comp.os.linux.announce to: linux-announce@news.ornl.gov
+PLEASE remember a short description of the software and the LOCATION.
+This group is archived at http://www.iki.fi/liw/linux/cola.html
diff --git a/gpxe/contrib/linux-3c503-patch/3c503.patch b/gpxe/contrib/linux-3c503-patch/3c503.patch
new file mode 100644
index 00000000..b27ff1fc
--- /dev/null
+++ b/gpxe/contrib/linux-3c503-patch/3c503.patch
@@ -0,0 +1,24 @@
+diff -Naur linux.orig/drivers/net/3c503.c linux/drivers/net/3c503.c
+--- linux.orig/drivers/net/3c503.c Thu Feb 19 23:14:04 1998
++++ linux/drivers/net/3c503.c Thu Feb 19 23:16:24 1998
+@@ -179,7 +179,8 @@
+ for both the old and new 3Com prefix */
+ outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
+ vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2);
+- if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
++ if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID) &&
++ (vendor_id != BULL_3COM_ID)) {
+ /* Restore the register we frobbed. */
+ outb(saved_406, ioaddr + 0x406);
+ return ENODEV;
+diff -Naur linux.orig/drivers/net/3c503.h linux/drivers/net/3c503.h
+--- linux.orig/drivers/net/3c503.h Thu Feb 19 23:14:05 1998
++++ linux/drivers/net/3c503.h Mon Feb 16 11:41:56 1998
+@@ -11,6 +11,7 @@
+
+ #define OLD_3COM_ID 0x02608c
+ #define NEW_3COM_ID 0x0020af
++#define BULL_3COM_ID 0x000062
+
+ /* Shared memory management parameters. NB: The 8 bit cards have only
+ one bank (MB1) which serves both Tx and Rx packet space. The 16bit
diff --git a/gpxe/contrib/linux-3c503-patch/README b/gpxe/contrib/linux-3c503-patch/README
new file mode 100644
index 00000000..109094ff
--- /dev/null
+++ b/gpxe/contrib/linux-3c503-patch/README
@@ -0,0 +1,7 @@
+As part of determining whether a 3c503 is present, the Linux driver
+examines the first 3 bytes of the ethernet address (the vendor ID)
+to see if it corresponds to a known 3Com vendor ID.
+
+The Bull discless 386 workstation I have (don't laugh) has an
+unknown vendor ID 0x000062. This trivial patch adds it to those
+known to the driver.
diff --git a/gpxe/contrib/mini-slamd/COPYING b/gpxe/contrib/mini-slamd/COPYING
new file mode 100644
index 00000000..a43ea212
--- /dev/null
+++ b/gpxe/contrib/mini-slamd/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present