summaryrefslogtreecommitdiffstats
path: root/contrib/baremetal
diff options
context:
space:
mode:
authorMichael Brown2005-05-17 18:44:57 +0200
committerMichael Brown2005-05-17 18:44:57 +0200
commit1097cf8685cd81f0003bd6f17d050e5174a85b90 (patch)
tree47a39f2a1e980cca43c28c4d1a6dfdf431b910b2 /contrib/baremetal
parentQuickly hacked to use a buffer rather than a processor. (diff)
downloadipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.gz
ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.xz
ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.zip
Initial revision
Diffstat (limited to 'contrib/baremetal')
-rw-r--r--contrib/baremetal/Makefile475
-rw-r--r--contrib/baremetal/main.c1119
-rw-r--r--contrib/baremetal/marini.txt52
-rw-r--r--contrib/baremetal/misc.c351
-rw-r--r--contrib/baremetal/startmpcc.S756
5 files changed, 2753 insertions, 0 deletions
diff --git a/contrib/baremetal/Makefile b/contrib/baremetal/Makefile
new file mode 100644
index 00000000..df4de762
--- /dev/null
+++ b/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/contrib/baremetal/main.c b/contrib/baremetal/main.c
new file mode 100644
index 00000000..7b0de44c
--- /dev/null
+++ b/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/contrib/baremetal/marini.txt b/contrib/baremetal/marini.txt
new file mode 100644
index 00000000..464f1488
--- /dev/null
+++ b/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/contrib/baremetal/misc.c b/contrib/baremetal/misc.c
new file mode 100644
index 00000000..924ccd6d
--- /dev/null
+++ b/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/contrib/baremetal/startmpcc.S b/contrib/baremetal/startmpcc.S
new file mode 100644
index 00000000..07486ce5
--- /dev/null
+++ b/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 */