diff options
author | Michael Brown | 2005-05-17 18:44:57 +0200 |
---|---|---|
committer | Michael Brown | 2005-05-17 18:44:57 +0200 |
commit | 1097cf8685cd81f0003bd6f17d050e5174a85b90 (patch) | |
tree | 47a39f2a1e980cca43c28c4d1a6dfdf431b910b2 /contrib/baremetal | |
parent | Quickly hacked to use a buffer rather than a processor. (diff) | |
download | ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.gz ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.xz ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.zip |
Initial revision
Diffstat (limited to 'contrib/baremetal')
-rw-r--r-- | contrib/baremetal/Makefile | 475 | ||||
-rw-r--r-- | contrib/baremetal/main.c | 1119 | ||||
-rw-r--r-- | contrib/baremetal/marini.txt | 52 | ||||
-rw-r--r-- | contrib/baremetal/misc.c | 351 | ||||
-rw-r--r-- | contrib/baremetal/startmpcc.S | 756 |
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 */ |