summaryrefslogtreecommitdiff
path: root/sys/arch/i386/netboot
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /sys/arch/i386/netboot
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/i386/netboot')
-rw-r--r--sys/arch/i386/netboot/Makefile73
-rw-r--r--sys/arch/i386/netboot/README183
-rw-r--r--sys/arch/i386/netboot/arp.c459
-rw-r--r--sys/arch/i386/netboot/arp.h64
-rw-r--r--sys/arch/i386/netboot/asm.h161
-rw-r--r--sys/arch/i386/netboot/asm.s231
-rw-r--r--sys/arch/i386/netboot/assert.h19
-rw-r--r--sys/arch/i386/netboot/bootp.c20
-rw-r--r--sys/arch/i386/netboot/bootp.h106
-rw-r--r--sys/arch/i386/netboot/cga.c220
-rw-r--r--sys/arch/i386/netboot/config.h23
-rw-r--r--sys/arch/i386/netboot/dp8390.h166
-rw-r--r--sys/arch/i386/netboot/ether.h77
-rw-r--r--sys/arch/i386/netboot/genprom.c33
-rw-r--r--sys/arch/i386/netboot/inet.h59
-rw-r--r--sys/arch/i386/netboot/kbd.c363
-rw-r--r--sys/arch/i386/netboot/lance.h114
-rw-r--r--sys/arch/i386/netboot/main.c639
-rw-r--r--sys/arch/i386/netboot/misc.c225
-rw-r--r--sys/arch/i386/netboot/nbtypes.h95
-rw-r--r--sys/arch/i386/netboot/ne2100.c328
-rw-r--r--sys/arch/i386/netboot/packet.c59
-rw-r--r--sys/arch/i386/netboot/packet.h27
-rw-r--r--sys/arch/i386/netboot/param.h26
-rw-r--r--sys/arch/i386/netboot/proto.h146
-rw-r--r--sys/arch/i386/netboot/start.s292
-rw-r--r--sys/arch/i386/netboot/tftp.c484
-rw-r--r--sys/arch/i386/netboot/tftp.h43
-rw-r--r--sys/arch/i386/netboot/wd80x3.c432
29 files changed, 5167 insertions, 0 deletions
diff --git a/sys/arch/i386/netboot/Makefile b/sys/arch/i386/netboot/Makefile
new file mode 100644
index 00000000000..2e920904008
--- /dev/null
+++ b/sys/arch/i386/netboot/Makefile
@@ -0,0 +1,73 @@
+# $NetBSD: Makefile,v 1.4 1994/10/27 04:20:59 cgd Exp $
+
+# uncomment one of these as appropriate for the board being used
+#ETH_OBJ = ne2100.o
+ETH_OBJ = wd80x3.o
+
+# set this to the size of the eprom (decimal)
+ROM_SIZE = 16384
+
+.SUFFIXES: .s .c .o .list
+.c.list:
+ $(CC) $(CFLAGS) $(INC) -S $<
+ $(AS) $*.s -a -o /dev/null > $@
+ rm $*.s
+
+.s.o:
+ @echo $(AS) -o $*.o $< [$(DEFINES)]
+ -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \
+ /bin/rm -f X$*.c; \
+ ln $*.s X$*.c; \
+ $(CC) -E $(CFLAGS) X$*.c > $*.i; \
+ if [ $$? != 0 ]; then :; \
+ else \
+ $(AS) $*.i -o $@; \
+ fi
+.s.list:
+ @echo $(AS) -o $*.o $< [$(DEFINES)]
+ -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \
+ /bin/rm -f X$*.c; \
+ ln $*.s X$*.c; \
+ $(CC) -E $(CFLAGS) X$*.c > $*.i; \
+ if [ $$? != 0 ]; then :; \
+ else \
+ $(AS) $*.i -a -o /dev/null > $@; \
+ fi
+
+# the relocation address (hex)
+RELOC = 98000
+CFLAGS = -O $(DEFINES) -nostdinc
+DEFINES = -DRELOC=0x$(RELOC) -DROM_SIZE=$(ROM_SIZE) -DTRACE=0 -Dprinte=printf \
+ -DDEBUG -DUSE_BOOTP -DUSE_RARP #-DPhysBcopy=bcopy -DPhysBzero=bzero
+
+OBJS = start.o main.o cga.o kbd.o packet.o tftp.o arp.o \
+ $(ETH_OBJ) misc.o asm.o
+
+all: boot.bin
+
+boot.bin: $(OBJS) genprom
+ ${LD} -e _start -N -T ${RELOC} $(OBJS)
+ cp a.out boot.sym
+ rm -f $@
+ strip a.out
+ dd if=a.out of=boot.v ibs=32 skip=1 obs=1024b
+ genprom <boot.v >$@
+ rm -f a.out boot.v
+
+genprom: genprom.c
+ $(CC) -o $@ -DROM_SIZE=$(ROM_SIZE) genprom.c
+
+# copy to dos floppy for testing (faster than burning an eprom)
+dostest: boot.bin
+ mcopy -n boot.bin a:
+
+TAGS: main.c cga.c kbd.c packet.c tftp.c arp.c wd80x3.c misc.c proto.h
+ etags main.c cga.c kbd.c packet.c tftp.c arp.c wd80x3.c misc.c proto.h
+
+clean:
+ rm -f *.o *.list *~ genprom
+
+cleandir: clean
+ rm -f boot.bin boot.sym
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/i386/netboot/README b/sys/arch/i386/netboot/README
new file mode 100644
index 00000000000..5f58b127648
--- /dev/null
+++ b/sys/arch/i386/netboot/README
@@ -0,0 +1,183 @@
+$NetBSD: README,v 1.2 1994/10/27 04:21:00 cgd Exp $
+
+Ethernet boot prom code.
+
+This is code that can be burned into an eprom and installed in an
+ethernet card. It uses the extension facilities of the bios to to boot
+a kernel via the network.
+
+Netboot uses bootp or rarp to determine its ip address and tftps a
+designated kernel from a server. You should be running a daemon for
+either bootp or rarp to service requests from this client. If you are
+using bootp, the boot file name and the gateway (if necessary) will
+also be transmitted to the client. If you use rarpd, the boot file
+name is synthesized by this boot code from the eight hexadecimal
+digits that comprise the IP address of the client and an extension of
+"386bsd". If you use rarp, the rarp server must also be the tftp
+server.
+
+If you have configured both bootp and rarpd into the boot prom, the
+response from the first host to respond via either protocol will be
+used.
+
+This code was developed using GNU as 2.1 and GNU cc version 2.3.3,
+running under 386bsd. Pre 2.0 versions of GNU as might have trouble
+with some syntax. Testing was done with a SMC Elite16 and 16k eproms.
+
+
+Installation instructions:
+
+Check the configurable parameters in Makefile.
+
+Check the configurable parameters in the ethernet driver source for
+the card you are using:
+- in wd80x3.c: WD_BASEREG, WD_BASEMEM (irqs not used)
+
+Make.
+
+If you wish, you can test the binary (boot.bin) by copying it to a
+floppy with the dosload.exe program and execute the boot code from the
+floppy.
+
+Burn the resultant binary (boot.bin) into an eprom and install it in
+the ethernet card.
+
+Decide which protocol (bootp or rarp) to use on a server; set up that
+server.
+
+Setting up a bootp server entails creating a bootpd client
+configuration file. The format is similar to that of printcap. An
+entry looks something like:
+
+sams-1:\
+ :bf=diskless_kernel.386bsd:\
+ :gw=139.88.30.4:\
+ :ht=ethernet:\
+ :ha=0000c025e35b:\
+ :ip=139.88.30.39:\
+ :sm=255.255.255.0:\
+ :to=18000:
+
+Setting up a rarpd server entails creating an ethernet/ip address
+resolution file '/etc/ethers' with a line for each netboot client in
+the form:
+
+00:00:c0:25:e3:5b sams-1.lerc.nasa.gov
+
+If you don't know the ethernet address, boot the client with the eprom
+installed; the ethernet address of the card will be displayed.
+
+Set up tftpd on a server. Check '/etc/inetd.conf'; there should be a
+line that starts something like:
+
+tftp dgram udp wait root ...
+
+perhaps commented out.
+
+Build a kernel that is capable of operating via NFS. Martin Renters
+released some patches and a kernel configuration program that work
+nicely (comp.os.386bsd.development around March 22, 1993); they should
+be around somewhere. If you can't find them, I can email you a copy.
+
+Make the kernel available via tftp under one of the names which this
+code will use to look for the kernel. If you are using bootp, you can
+specify the name as a bootp client configuration parameter. If you
+don't specify the name, or if you are using rarp the this code will
+synthesize the name using its client's IP address. The hexadecimal
+version of the client's IP address with the extension '.386bsd' is the
+default choice.
+
+Create the exportable nfs mount points for which this kernel will use
+and load them with necessary files (the base distribution, ...).
+Export them so they can be mounted by this kernel when it boots from
+the client IP address.
+
+
+Usage instructions:
+
+At any time the escape key can be struck to gain entrance to the
+interactive monitor. There is a menu of monitor commands that can be
+invoked to customize a boot operation.
+
+
+Notes:
+
+When Martin Renter's patches are applied to netbsd 0.8, there will be
+one failure (pmap.c). Ignore it, the relevant code has already been
+fixed.
+
+I had some small problems with getfh(2) as used in the nfs configuring
+program - I suspect the problem is a bug in SunOS 4.1.1 - if you have
+similar problems, I can email you my gross hack workaround.
+
+As noted by Mr. Renters, advisory flock()ing is not supported - this
+breaks some programs. The first broken utility you will likely
+encounter is vipw(1). The others: passwd, dump, ar, mail, tip, lpr,
+sendmail.
+
+You should examine your rc script and make appropriate changes to the
+boot up sequence.
+
+Here are the steps I took to bring netbsd 0.8 up for the client sams-1
+using the host dinah in the domain lerc.nasa.gov.
+
+- Create the /dev/vga device.
+
+- Create some ptys.
+
+- Create /etc/fstab to contain:
+ dinah:/home/386bsd-root / nfs rw
+ dinah:/home/386bsd-swap none swap rw
+in it for the root and swap.
+
+- Edit /etc/rc; the line 'mount -a -t nonfs' is changed to:
+ mount -a -t nonfs,swap
+
+- Edit /etc/myname to contain
+ sams-1
+
+- Edit /etc/hosts to contain:
+ 127.0.0.1 localhost loghost
+ 139.88.30.39 sams-1
+and delete the other stuff in it.
+
+- Create /etc/resolv.conf to contain:
+ domain lerc.nasa.gov
+ nameserver 128.156.1.43
+ nameserver 139.88.76.3
+where the two addresses are those of some name servers in my domain.
+There are, of course, the two alternatives of using just the /etc/hosts
+file, or using named.
+
+- Create /etc/mygate to contain:
+ 139.88.30.4
+which is the IP address of my gateway.
+
+- Re-symlink /etc/localtime to the correct zone.
+
+
+TBD:
+-linux
+-ne2100
+-handle small memory configuration
+-USE_BIOS version
+-return to bios correctly
+-remove old Phys... stuff; relics of real mode prom version
+-accept bootd extension items & pass as args, modify kernel to
+ init nfs_diskless from args. Need:
+ myif [local] [bootp]
+ mygateway [bootp]
+ swap_args [local]
+ swap_fh [bootp]
+ swap_saddr [local] [bootp]
+ swap_hostname [bootp]
+ root_args [local]
+ root_fh [bootp]
+ root_saddr [local] [bootp]
+ root_hostnam [bootp]
+ A tight squeeze, passing all necessary info in one bootp packet.
+
+Please send me any improvements you make to this code. It will be
+appreciated.
+
+Jim McKim (mckim@lerc.nasa.gov)
diff --git a/sys/arch/i386/netboot/arp.c b/sys/arch/i386/netboot/arp.c
new file mode 100644
index 00000000000..53285cb1966
--- /dev/null
+++ b/sys/arch/i386/netboot/arp.c
@@ -0,0 +1,459 @@
+/* $NetBSD: arp.c,v 1.4 1994/10/27 04:21:01 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
+ * No doubt this code is overkill, but I had it lying around.
+ *
+ * Copyright (c) 1992 by Leendert van Doorn
+ */
+
+#include "proto.h"
+#include "assert.h"
+#include "param.h"
+#include "packet.h"
+#include "ether.h"
+#include "inet.h"
+#include "arp.h"
+#include "bootp.h"
+#include "tftp.h"
+
+static u_char bcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static arptab_t arptab[ARPTAB_SIZE];
+
+extern u_char vendor_area[64];
+ipaddr_t ip_myaddr = IP_ANYADDR;
+ipaddr_t ip_gateway = IP_ANYADDR;
+
+#ifdef USE_RARP
+/*
+ * Broadcast a RARP request (i.e. who knows who I am)
+ */
+static void
+RarpWhoAmI(void) {
+ arphdr_t *ap;
+ packet_t *pkt;
+ pkt = PktAlloc(sizeof(ethhdr_t));
+ pkt->pkt_len = sizeof(arphdr_t);
+ ap = (arphdr_t *) pkt->pkt_offset;
+ ap->arp_hrd = htons(ARPHRD_ETHER);
+ ap->arp_pro = htons(ETHTYPE_IP);
+ ap->arp_hln = ETH_ADDRSIZE;
+ ap->arp_pln = sizeof(ipaddr_t);
+ ap->arp_op = htons(REVARP_REQUEST);
+ bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
+ bcopy((char *)eth_myaddr, (char *)ap->arp_tha, ETH_ADDRSIZE);
+ EtherSend(pkt, ETHTYPE_RARP, bcastaddr);
+ PktRelease(pkt);
+}
+#endif
+
+
+#ifdef USE_BOOTP
+static int saved_bootp_xid; /* from last bootp req */
+extern int time_zero;
+/*
+ * Broadcast a BOOTP request (i.e. who knows who I am)
+ */
+static void
+BootpWhoAmI(void) {
+ struct bootp *bp;
+ packet_t *pkt;
+ udphdr_t *up;
+ pkt = PktAlloc(sizeof(ethhdr_t)+sizeof(iphdr_t));
+ pkt->pkt_len = sizeof(ethhdr_t) + sizeof(iphdr_t) +
+ sizeof(udphdr_t) +sizeof(struct bootp);
+ up = (udphdr_t *) pkt->pkt_offset;
+ bp = (struct bootp *) ((char *)up + sizeof(udphdr_t));
+ up->uh_dport = htons(IPPORT_BOOTPS);
+ up->uh_len = htons(sizeof(udphdr_t) + sizeof(struct bootp));
+ bp->bp_op = BOOTREQUEST;
+ bp->bp_htype = 1;
+ bp->bp_hlen = ETH_ADDRSIZE;
+ bp->bp_xid = saved_bootp_xid = rand();
+ bp->bp_secs = htons(timer() - time_zero);
+ bcopy((char *)eth_myaddr, (char *)bp->bp_chaddr, ETH_ADDRSIZE);
+ IpSend(pkt, IP_BCASTADDR, IP_ANYADDR);
+ PktInit();
+}
+#endif
+
+extern ipaddr_t tftp_gateway;
+extern ipaddr_t tftp_server;
+
+#ifdef USE_RARP
+/*
+ * Called when packet containing RARP is received
+ */
+static inline ipaddr_t
+RarpInput(packet_t *pkt, ipaddr_t *server) {
+ ipaddr_t ipaddr;
+ ethhdr_t *ep;
+ ep = (ethhdr_t *)pkt->pkt_offset;
+
+ /* is rarp? */
+ if (pkt->pkt_len >= sizeof(arphdr_t) &&
+ ntohs(ep->eth_proto) == ETHTYPE_RARP) {
+ ipaddr_t ipa;
+ arphdr_t *ap;
+ ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
+ if (ntohs(ap->arp_op) != REVARP_REPLY ||
+ ntohs(ap->arp_pro) != ETHTYPE_IP)
+ return 0;
+ if (bcmp(ap->arp_tha, eth_myaddr, ETH_ADDRSIZE))
+ return 0;
+
+ bcopy((char *)ap->arp_tpa, (char *)&ipaddr, sizeof(ipaddr_t));
+ printf("From RARP server ");
+ bcopy((char *)ap->arp_spa, (char *)&ipa, sizeof(ipaddr_t));
+ IpPrintAddr(ipa);
+ printf(": using IP address ");
+ IpPrintAddr(ipaddr);
+
+ if (server) {
+ bcopy((char *)ap->arp_spa, (char *)server, sizeof(ipaddr_t));
+ printf(",\n tftp server ");
+ IpPrintAddr(*server);
+ }
+
+ printf("\n");
+ return ipaddr;
+ }
+ return 0;
+}
+#endif
+
+#ifdef USE_BOOTP
+static inline ipaddr_t
+BootpInput(packet_t *pkt, ipaddr_t *server, ipaddr_t *gateway, char *filename) {
+ ipaddr_t ipaddr;
+ ethhdr_t *ep;
+ ep = (ethhdr_t *)pkt->pkt_offset;
+
+
+ if (pkt->pkt_len < sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp))
+ return 0;
+ if (ntohs(ep->eth_proto) == ETHTYPE_IP) {
+ iphdr_t *ip;
+ udphdr_t *up;
+ struct bootp *bp;
+ ip = (iphdr_t *) ((char *)ep + sizeof(ethhdr_t));
+ up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t));
+ bp = (struct bootp *) ((char *)up + sizeof(udphdr_t));
+
+#if 0
+DUMP_STRUCT("eboot", ep, 100);
+printf("pktlen %d of %d\n\n", pkt->pkt_len, sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp));
+#endif
+
+ if (ip->ip_p != IP_PROTO_UDP) {
+ return 0;
+ }
+
+ if (up->uh_dport != htons(IPPORT_BOOTPC)) {
+ return 0;
+ }
+
+ if (bp->bp_xid != saved_bootp_xid) {
+ return 0;
+ }
+
+ /* passed all checks - is the packet we expected */
+ ipaddr = bp->bp_yiaddr;
+ printf("From BOOTP server ");
+ IpPrintAddr(ip->ip_src);
+ printf(": using IP address ");
+ IpPrintAddr(bp->bp_yiaddr);
+
+ if (server) {
+ *server = bp->bp_siaddr;
+ printf(",\n tftp server ");
+ IpPrintAddr(bp->bp_siaddr);
+ }
+
+ if (bp->bp_giaddr) {
+ *gateway = bp->bp_giaddr;
+ printf(",\n gateway ");
+ IpPrintAddr(bp->bp_giaddr);
+ }
+
+ if (*bp->bp_file) {
+ bcopy((char *)bp->bp_file, filename, MAX_FILE_NAME_LEN-1);
+ printf(",\n file '%s'", bp->bp_file);
+ }
+
+ bcopy((char *)bp->bp_vend, (char *)vendor_area, sizeof(vendor_area));
+
+ printf("\n");
+
+ PktInit();
+ return ipaddr;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * Using the BOOTP and/or RARP request/reply exchange we try to obtain our
+ * internet address (see RFC 903).
+ */
+ipaddr_t
+GetIpAddress(ipaddr_t *serv_addr, ipaddr_t *myaddr, ipaddr_t *gateway, char *filename) {
+ u_long time, current, timeout;
+ int retry;
+ packet_t *pkt;
+ int spin = 0;
+
+#if TRACE > 0
+ printe("GetIpAddress: Requesting IP address for ");
+ EtherPrintAddr(eth_myaddr);
+ printe("\n");
+#endif
+
+ timeout = 4; /* four seconds */
+ for (retry = 0; retry < NRETRIES; retry++) {
+#ifdef USE_RARP
+ RarpWhoAmI();
+#endif
+#ifdef USE_BOOTP
+ BootpWhoAmI();
+#endif
+ printf("%c\b", "-\\|/"[spin++ % 4]);
+
+ time = timer() + timeout;
+ do {
+ pkt = EtherReceive();
+ if (pkt) {
+ *myaddr = 0;
+#ifdef USE_RARP
+ *myaddr = RarpInput(pkt, serv_addr);
+#endif
+#ifdef USE_BOOTP
+ if (!*myaddr)
+ *myaddr = BootpInput(pkt, serv_addr, gateway, filename);
+#endif
+ PktRelease(pkt);
+ if (*myaddr) {
+ return 1;
+ }
+ }
+ HandleKbdAttn();
+ current = timer();
+ } while (current < time);
+ EtherReset();
+ timeout <<= 1;
+ }
+ printf("No response for "
+#ifdef USE_BOOTP
+ "BOOTP "
+#endif
+#ifdef USE_RARP
+ "RARP "
+#endif
+ "request\n");
+ return IP_ANYADDR;
+}
+
+/*
+ * Broadcast an ARP packet (i.e. ask who has address "addr")
+ */
+static void
+ArpWhoHas(ipaddr_t addr) {
+ arphdr_t *ap;
+ packet_t *pkt;
+
+ pkt = PktAlloc(sizeof(ethhdr_t));
+ pkt->pkt_len = sizeof(arphdr_t);
+ ap = (arphdr_t *) pkt->pkt_offset;
+ ap->arp_hrd = htons(ARPHRD_ETHER);
+ ap->arp_pro = htons(ETHTYPE_IP);
+ ap->arp_hln = ETH_ADDRSIZE;
+ ap->arp_pln = sizeof(ipaddr_t);
+ ap->arp_op = htons(ARPOP_REQUEST);
+ bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
+ bcopy((char *)&ip_myaddr, (char *)ap->arp_spa, sizeof(ipaddr_t));
+ bcopy((char *)&addr, (char *)ap->arp_tpa, sizeof(ipaddr_t));
+#if TRACE > 0
+printe("ArpWhoHas:\n");
+DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t));
+#endif
+ EtherSend(pkt, ETHTYPE_ARP, bcastaddr);
+ PktRelease(pkt);
+}
+
+/*
+ * Free an arptab entry
+ */
+static void
+ArpTfree(arptab_t *at) {
+ if (at->at_hold)
+ PktRelease(at->at_hold);
+ at->at_hold = (packet_t *)0;
+ at->at_timer = at->at_flags = 0;
+ at->at_ipaddr = 0;
+}
+
+/*
+ * Enter a new address in arptab, pushing out the oldest entry
+ * from the bucket if there is no room.
+ */
+static arptab_t *
+ArpTnew(ipaddr_t addr) {
+ u_short n;
+ u_long oldest;
+ arptab_t *at, *ato;
+
+ oldest = ~0;
+ ato = at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ];
+ for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
+ if (at->at_flags == 0)
+ goto out; /* found an empty entry */
+ if (at->at_timer < oldest) {
+ oldest = at->at_timer;
+ ato = at;
+ }
+ }
+ at = ato;
+ ArpTfree(at);
+ out:
+ at->at_ipaddr = addr;
+ at->at_flags = ATF_INUSE;
+ return at;
+}
+
+/*
+ * Resolve an IP address into a hardware address. If success,
+ * destha is filled in and 1 is returned. If there is no entry
+ * in arptab, set one up and broadcast a request
+ * for the IP address; return 0. Hold onto this packet and
+ * resend it once the address is finally resolved.
+ */
+int
+ArpResolve(packet_t *pkt, ipaddr_t destip, u_char *destha) {
+ arptab_t *at;
+ u_long lna = ntohl(destip) & 0xFF;
+
+ if (lna == 0xFF || lna == 0x0) { /* broadcast address */
+ bcopy((char *)bcastaddr, (char *)destha, ETH_ADDRSIZE);
+ return 1;
+ }
+
+ ARPTAB_LOOK(at, destip);
+ if (at == 0) {
+ at = ArpTnew(destip);
+ at->at_hold = pkt;
+ ArpWhoHas(destip);
+ return 0;
+ }
+
+ at->at_timer = timer(); /* restart the timer */
+ if (at->at_flags & ATF_COM) { /* entry is complete */
+ bcopy((char *)at->at_eaddr, (char *)destha, ETH_ADDRSIZE);
+ return 1;
+ }
+
+ /*
+ * There is an arptab entry, but no hardware address
+ * response yet. Replace the held packet with this
+ * latest one.
+ */
+ if (at->at_hold)
+ PktRelease(at->at_hold);
+ at->at_hold = pkt;
+ ArpWhoHas(destip);
+ return 0;
+}
+
+
+/*
+ * Called when packet containing ARP is received.
+ * Algorithm is that given in RFC 826.
+ */
+void
+ArpInput(packet_t *pkt) {
+ arphdr_t *ap;
+ arptab_t *at;
+ packet_t *phold;
+ ipaddr_t isaddr, itaddr;
+
+#if 0
+T(ArpInput);
+#endif
+ if (pkt->pkt_len < sizeof(arphdr_t)) {
+#if 0
+ printf("ArpInput: bad packet size %d\n", pkt->pkt_len);
+#endif
+ return;
+ }
+
+ ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
+#if 0
+DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t));
+#endif
+ if (ntohs(ap->arp_pro) != ETHTYPE_IP) {
+#if 0
+ printf("ArpInput: incorrect proto addr %x\n", ap->arp_pro);
+#endif
+ return;
+ }
+
+ bcopy((char *)ap->arp_spa, (char *)&isaddr, sizeof(ipaddr_t));
+ bcopy((char *)ap->arp_tpa, (char *)&itaddr, sizeof(ipaddr_t));
+ if (!bcmp(ap->arp_sha, eth_myaddr, ETH_ADDRSIZE)) {
+#if 0
+ printf("ArpInput: incorrect sender h/w addr ");
+ EtherPrintAddr(ap->arp_sha);
+ printf("/n");
+#endif
+ return;
+ }
+
+ at = (arptab_t *)0;
+ ARPTAB_LOOK(at, isaddr);
+ if (at) {
+ bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE);
+ at->at_flags |= ATF_COM;
+ if (at->at_hold) {
+ phold = at->at_hold;
+ at->at_hold = (packet_t *)0;
+#if 0
+ printf("ArpInput: found addr, releasing packet\n");
+#endif
+ EtherSend(phold, ETHTYPE_IP, at->at_eaddr);
+ PktRelease(phold);
+ }
+ }
+
+ /*
+ * Only answer ARP request which are for me
+ */
+ if (itaddr != ip_myaddr) {
+#if 0
+ printf("ArpInput: it addr ");
+ IpPrintAddr(itaddr);
+ printf(" somebody else\n");
+#endif
+ return;
+ }
+
+ if (at == 0) { /* ensure we have a table entry */
+ at = ArpTnew(isaddr);
+ bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE);
+ at->at_flags |= ATF_COM;
+ }
+ if (ntohs(ap->arp_op) != ARPOP_REQUEST) {
+ printf("ArpInput: incorrect operation: 0x%x\n", ntohs(ap->arp_op));
+ return;
+ }
+ bcopy((char *)ap->arp_sha, (char *)ap->arp_tha, ETH_ADDRSIZE);
+ bcopy((char *)ap->arp_spa, (char *)ap->arp_tpa, sizeof(ipaddr_t));
+ bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE);
+ bcopy((char *)&itaddr, (char *)ap->arp_spa, sizeof(ipaddr_t));
+ ap->arp_op = htons(ARPOP_REPLY);
+#if 0
+printf("ArpInput: valid request rec'd, replying\n");
+#endif
+ EtherSend(pkt, ETHTYPE_ARP, ap->arp_tha);
+}
diff --git a/sys/arch/i386/netboot/arp.h b/sys/arch/i386/netboot/arp.h
new file mode 100644
index 00000000000..8144b3184b3
--- /dev/null
+++ b/sys/arch/i386/netboot/arp.h
@@ -0,0 +1,64 @@
+/* $NetBSD: arp.h,v 1.3 1994/10/27 04:21:03 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Ethernet Address Resolution Protocol (see RFC 826)
+ */
+
+/*
+ * ARP packets are variable in size; the arphdr_t type defines the
+ * 10Mb Ethernet variant. Field names used correspond to RFC 826.
+ */
+typedef struct {
+ u_short arp_hrd; /* format of hardware address */
+#define ARPHRD_ETHER 1 /* ethernet hardware address */
+ u_short arp_pro; /* format of proto. address */
+ u_char arp_hln; /* length of hardware address */
+ u_char arp_pln; /* length of protocol address */
+ u_short arp_op;
+#define ARPOP_REQUEST 1 /* request to resolve address */
+#define ARPOP_REPLY 2 /* response to previous request */
+#define REVARP_REQUEST 3 /* reverse ARP request */
+#define REVARP_REPLY 4 /* reverse ARP reply */
+ u_char arp_sha[ETH_ADDRSIZE]; /* sender hardware address */
+ u_char arp_spa[4]; /* sender protocol address */
+ u_char arp_tha[ETH_ADDRSIZE]; /* target hardware address */
+ u_char arp_tpa[4]; /* target protocol address */
+} arphdr_t;
+
+/*
+ * Internet to hardware address resolution table
+ */
+typedef struct {
+ ipaddr_t at_ipaddr; /* internet address */
+ u_char at_eaddr[ETH_ADDRSIZE]; /* ethernet address */
+ u_long at_timer; /* time when referenced */
+ u_char at_flags; /* flags */
+ packet_t *at_hold; /* ast packet until resolved/timeout */
+} arptab_t;
+
+/* at_flags field values */
+#define ATF_INUSE 1 /* entry in use */
+#define ATF_COM 2 /* completed entry (eaddr valid) */
+
+#define ARPTAB_BSIZ 3 /* bucket size */
+#define ARPTAB_NB 2 /* number of buckets */
+#define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
+
+#define ARPTAB_HASH(a) \
+ ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
+
+#define ARPTAB_LOOK(at, addr) { \
+ register n; \
+ at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
+ for (n = 0; n < ARPTAB_BSIZ; n++, at++) \
+ if (at->at_ipaddr == addr) \
+ break; \
+ if (n >= ARPTAB_BSIZ) \
+ at = 0; }
+
+ipaddr_t GetIpAddress(ipaddr_t *server, ipaddr_t *my_addr, ipaddr_t *gateway, char *filename);
+void ArpInput(packet_t *);
+int ArpResolve(packet_t *, ipaddr_t, u_char *);
diff --git a/sys/arch/i386/netboot/asm.h b/sys/arch/i386/netboot/asm.h
new file mode 100644
index 00000000000..b4441cb3a01
--- /dev/null
+++ b/sys/arch/i386/netboot/asm.h
@@ -0,0 +1,161 @@
+/* $NetBSD: asm.h,v 1.3 1994/10/27 04:21:04 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the 386BSD boot blocks written by Julian Elsicher.
+ *
+ * Ported to Boot 386BSD by Julian Elsicher (julian@tfs.com) Sept. 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#define S_ARG0 4(%esp)
+#define S_ARG1 8(%esp)
+#define S_ARG2 12(%esp)
+#define S_ARG3 16(%esp)
+
+#define FRAME pushl %ebp; movl %esp, %ebp
+#define EMARF leave
+
+#define B_ARG0 8(%ebp)
+#define B_ARG1 12(%ebp)
+#define B_ARG2 16(%ebp)
+#define B_ARG3 20(%ebp)
+
+#ifdef wheeze
+
+#define ALIGN 4
+#define EXT(x) x
+#define LEXT(x) x:
+#define LCL(x) ./**/x
+
+#define LB(x,n) ./**/x
+#define LBb(x,n) ./**/x
+#define LBf(x,n) ./**/x
+
+#define SVC lcall $7,$0
+
+#define String .string
+#define Value .value
+#define Times(a,b) [a\*b]
+#define Divide(a,b) [a\\b]
+
+#define INB inb (%dx)
+#define OUTB outb (%dx)
+#define INL inl (%dx)
+#define OUTL outl (%dx)
+
+#else wheeze
+/* #define ALIGN */
+#define ALIGN 4
+#define LCL(x) x
+
+#define LB(x,n) n
+#ifdef __STDC__
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define LBb(x,n) n ## b
+#define LBf(x,n) n ## f
+#else __STDC__
+#define EXT(x) _/**/x
+#define LEXT(x) _/**/x/**/:
+#define LBb(x,n) n/**/b
+#define LBf(x,n) n/**/f
+#endif __STDC__
+#define SVC .byte 0x9a; .long 0; .word 0x7
+
+#define String .ascii
+#define Value .word
+#define Times(a,b) (a*b)
+#define Divide(a,b) (a/b)
+
+#define INB inb %dx, %al
+#define OUTB outb %al, %dx
+#define INL inl %dx, %eax
+#define OUTL outl %eax, %dx
+
+#endif wheeze
+
+#define data32 .byte 0x66
+#define data16 .byte 0x66
+#define addr16 .byte 0x67
+
+
+
+#ifdef GPROF
+#ifdef __STDC__
+
+#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#else __STDC__
+
+#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x: ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#endif __STDC__
+#else GPROF
+#ifdef __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x ## :
+
+#else __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x:
+
+#endif __STDC__
+#endif GPROF
+
+#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
+
+CR0_PE = 0x00000001
+
+KERN_CODE_SEG = 0x08
+KERN_DATA_SEG = 0x10
+BOOT_16_SEG = 0x18
+
+#define opsize .byte 0x66
+#define addrsize .byte 0x67
diff --git a/sys/arch/i386/netboot/asm.s b/sys/arch/i386/netboot/asm.s
new file mode 100644
index 00000000000..3fe9f70940f
--- /dev/null
+++ b/sys/arch/i386/netboot/asm.s
@@ -0,0 +1,231 @@
+/* $NetBSD: asm.s,v 1.3 1994/10/27 04:21:05 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the 386BSD boot blocks written by Julian Elischer.
+ *
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ .file "asm.s"
+
+#include "asm.h"
+
+ .text
+
+ENTRY(StartProg)
+ /* void StartProg(u_long phyaddr, u_long *args)
+ * start the program in protected mode. phyaddr is the entry point.
+ */
+
+#ifndef USE_BUFFER
+ push %ebp
+ mov %esp, %ebp
+
+ # get things we need into registers
+ movl 0x8(%ebp), %ecx # entry offset
+ movl 0x0c(%ebp), %eax # &argv
+
+ # make a new stack at 0:0xa0000 (big segs)
+ mov $KERN_DATA_SEG, %ebx
+ movw %bx, %ss
+ movl $0xa0000,%ebx
+ movl %ebx,%esp
+
+
+ # push some number of args onto the stack
+ pushl $0 # nominally a cyl offset in the boot.
+ pushl 0x8(%eax) # argv[2] = bootdev
+ pushl 0x4(%eax) # argv[1] = howto
+ pushl $0 # dummy 'return' address
+
+ # push on our entry address
+ mov $KERN_CODE_SEG, %ebx # segment
+ pushl %ebx
+ pushl %ecx
+
+ # convert over the other data segs
+ mov $KERN_DATA_SEG, %ebx
+ movw %bx, %ds
+ movw %bx, %es
+
+ # convert the PC (and code seg)
+ lret
+#else
+/* test version - relocating, kernel move (TBD) */
+ /* if necessary, move ourself out of the way
+ * move the copy of the kernel to its correct load point
+ * set up a stack and transfer args to it
+ * call the entry point
+ * this is best done in assembly as the potential relocation will
+ * have a bad effect on non-PIC code.
+ */
+ /* get things we need into registers */
+ movl 0x8(%ebp), %ecx # entry offset
+ movl 0x0c(%ebp), %eax # &argv
+
+ /* relocate ourselves to <tmp_reloc_org> */
+ # PhysBcopy(RELOC, tmp_reloc_org, WORK_AREA_SIZE);
+ mov $RELOC, %esi
+ mov $tmp_reloc_org, %edi
+ mov $WORK_AREA_SIZE, %ecx
+ mov %ds, %ax
+ mov %ax, %es
+ rep
+ movsb
+
+ /* TBD - could probably also do this by munging a seg descriptor.
+ * would it be easier?
+ */
+ ljmp $KERN_CODE_SEG, tmp_reloc_org+$1f
+1:
+ /* now we are PIC - caveats */
+ /* move the stack pointer to the new copy */
+ add tmp_reloc_org-xxx, %esp
+
+ /* push some number of args onto the stack */
+ pushl $0 # nominally a cyl offset in the boot.
+ pushl 0x8(%eax) # argv[2] = bootdev
+ pushl 0x4(%eax) # argv[1] = howto
+ pushl $0 # dummy 'return' address
+
+ /* push on our entry address */
+ mov $0x08, %ebx # segment
+ pushl %ebx
+ pushl %ecx
+
+ /* copy loaded file to its destination (TBD) */
+ # PhysBcopy(kcopy, korg, ksize);
+ mov kern_copy_org, %esi
+ mov boot_area_org, %edi
+ mov xxxksize, %ecx
+ mov %ds, %ax
+ mov %ax, %es
+ rep
+ movsb
+
+ /* convert the PC (and code seg) */
+ lret
+#endif
+
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ */
+
+ENTRY(setjmp)
+ movl 4(%esp),%ecx
+ movl 0(%esp),%edx
+ movl %edx, 0(%ecx)
+ movl %ebx, 4(%ecx)
+ movl %esp, 8(%ecx)
+ movl %ebp,12(%ecx)
+ movl %esi,16(%ecx)
+ movl %edi,20(%ecx)
+ movl %eax,24(%ecx)
+ movl $0,%eax
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ cmpl $0,%eax
+ jne 1f
+ movl $1,%eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/sys/arch/i386/netboot/assert.h b/sys/arch/i386/netboot/assert.h
new file mode 100644
index 00000000000..4d22e64f7e3
--- /dev/null
+++ b/sys/arch/i386/netboot/assert.h
@@ -0,0 +1,19 @@
+/* $NetBSD: assert.h,v 1.3 1994/10/27 04:21:07 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * assert.h
+ */
+
+#ifndef NDEBUG
+#define assert(exp) \
+ if (!(exp)) { \
+ printf("Assertion \"%s\" failed: file %s, line %d\n", \
+ #exp, __FILE__, __LINE__); \
+ exit(1); \
+ }
+#else
+#define assert(exp) /* */
+#endif /* _ASSERT_H */
diff --git a/sys/arch/i386/netboot/bootp.c b/sys/arch/i386/netboot/bootp.c
new file mode 100644
index 00000000000..f6420b49028
--- /dev/null
+++ b/sys/arch/i386/netboot/bootp.c
@@ -0,0 +1,20 @@
+/* $NetBSD: bootp.c,v 1.3 1994/10/27 04:21:08 cgd Exp $ */
+
+/*
+ * bootp functions
+ */
+
+int BootpGetInfo(ipaddr_t *ip_servaddr, ipaddr_t *ip_myaddr, ipaddr_t *ip_gateway, char *file_name) {
+ /* zero a packet */
+ bzero(xxx);
+ /* set dest to 255... */
+ xxx = IP_BCASTADDR
+ /* set up udp ports */
+ /* send it */
+ /* wait for reply or timeout */
+ /* do exp backoff and retry if timeout */
+ /* give up after a minute or so */
+ /* return success or failure */
+}
+
+/* tbd - set up incoming packet handler to handle bootp replies??? */
diff --git a/sys/arch/i386/netboot/bootp.h b/sys/arch/i386/netboot/bootp.h
new file mode 100644
index 00000000000..aef88513ee3
--- /dev/null
+++ b/sys/arch/i386/netboot/bootp.h
@@ -0,0 +1,106 @@
+/* $NetBSD: bootp.h,v 1.3 1994/10/27 04:21:09 cgd Exp $ */
+
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1048.
+ *
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ *
+ * Copyright 1988 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University. Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+
+struct bootp {
+ unsigned char bp_op; /* packet opcode type */
+ unsigned char bp_htype; /* hardware addr type */
+ unsigned char bp_hlen; /* hardware addr length */
+ unsigned char bp_hops; /* gateway hops */
+ unsigned long bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_unused;
+ ipaddr_t bp_ciaddr; /* client IP address */
+ ipaddr_t bp_yiaddr; /* 'your' IP address */
+ ipaddr_t bp_siaddr; /* server IP address */
+ ipaddr_t bp_giaddr; /* gateway IP address */
+ unsigned char bp_chaddr[16]; /* client hardware address */
+ unsigned char bp_sname[64]; /* server host name */
+ unsigned char bp_file[128]; /* boot file name */
+ unsigned char bp_vend[64]; /* vendor-specific area */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define IPPORT_BOOTPS 67
+#define IPPORT_BOOTPC 68
+
+#define BOOTREPLY 2
+#define BOOTREQUEST 1
+
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048 { 99, 130, 83, 99 }
+
+
+
+/*
+ * RFC1048 tag values used to specify what information is being supplied in
+ * the vendor field of the packet.
+ */
+
+#define TAG_PAD ((unsigned char) 0)
+#define TAG_SUBNET_MASK ((unsigned char) 1)
+#define TAG_TIME_OFFSET ((unsigned char) 2)
+#define TAG_GATEWAY ((unsigned char) 3)
+#define TAG_TIME_SERVER ((unsigned char) 4)
+#define TAG_NAME_SERVER ((unsigned char) 5)
+#define TAG_DOMAIN_SERVER ((unsigned char) 6)
+#define TAG_LOG_SERVER ((unsigned char) 7)
+#define TAG_COOKIE_SERVER ((unsigned char) 8)
+#define TAG_LPR_SERVER ((unsigned char) 9)
+#define TAG_IMPRESS_SERVER ((unsigned char) 10)
+#define TAG_RLP_SERVER ((unsigned char) 11)
+#define TAG_HOSTNAME ((unsigned char) 12)
+#define TAG_BOOTSIZE ((unsigned char) 13)
+#define TAG_END ((unsigned char) 255)
+
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ unsigned char v_magic[4]; /* magic number */
+ unsigned long v_flags; /* flags/opcodes, etc. */
+ ipaddr_t v_smask; /* Subnet mask */
+ ipaddr_t v_dgate; /* Default gateway */
+ ipaddr_t v_dns1, v_dns2; /* Domain name servers */
+ ipaddr_t v_ins1, v_ins2; /* IEN-116 name servers */
+ ipaddr_t v_ts1, v_ts2; /* Time servers */
+ unsigned char v_unused[25]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/sys/arch/i386/netboot/cga.c b/sys/arch/i386/netboot/cga.c
new file mode 100644
index 00000000000..21ca95ce5d7
--- /dev/null
+++ b/sys/arch/i386/netboot/cga.c
@@ -0,0 +1,220 @@
+/* $NetBSD: cga.c,v 1.3 1994/10/27 04:21:10 cgd Exp $ */
+
+/* netboot
+ *
+ * source in this file came from
+ * the original 386BSD boot block.
+ *
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cga.c 5.3 (Berkeley) 4/28/91
+ */
+
+#include "proto.h"
+
+#define COL 80
+#define ROW 25
+#define CHR 2
+#define MONO_BASE 0x3B4
+#define MONO_BUF 0xB0000
+#define CGA_BASE 0x3D4
+#define CGA_BUF 0xB8000
+
+static u_char att = 0x7 ;
+u_char *Crtat = (u_char *)CGA_BUF;
+
+static unsigned int addr_6845 = CGA_BASE;
+
+static void cursor(int pos) {
+ outb(addr_6845, 14);
+ outb(addr_6845+1, pos >> 8);
+ outb(addr_6845, 15);
+ outb(addr_6845+1, pos&0xff);
+}
+
+void
+putc(int c) {
+#ifdef USE_BIOS
+ asm("
+ movb %0, %%cl
+ call _prot_to_real
+ .byte 0x66
+ mov $0x1, %%ebx
+ movb $0xe, %%ah
+ movb %%cl, %%al
+ sti
+ int $0x10
+ cli
+ .byte 0x66
+ call _real_to_prot
+ " : : "g" (ch));
+#else
+ static u_char *crtat = 0;
+ unsigned cursorat; u_short was;
+ u_char *cp;
+
+ if (crtat == 0) {
+
+ /* XXX probe to find if a color or monochrome display */
+ was = *(u_short *)Crtat;
+ *(u_short *)Crtat = 0xA55A;
+ if (*(u_short *)Crtat != 0xA55A) {
+ Crtat = (u_char *) MONO_BUF;
+ addr_6845 = MONO_BASE;
+ }
+ *(u_short *)Crtat = was;
+
+ /* Extract cursor location */
+ outb(addr_6845,14);
+ cursorat = inb(addr_6845+1)<<8 ;
+ outb(addr_6845,15);
+ cursorat |= inb(addr_6845+1);
+
+ if(cursorat <= COL*ROW) {
+ crtat = Crtat + cursorat*CHR;
+ /* att = crtat[1]; */ /* use current attribute present */
+ } else crtat = Crtat;
+
+ /* clean display */
+ for (cp = crtat; cp < Crtat+ROW*COL*CHR; cp += 2) {
+ cp[0] = ' ';
+ cp[1] = att;
+ }
+ }
+
+ switch (c) {
+
+ case '\t':
+ do
+ putc(' ');
+ while ((int)crtat % (8*CHR));
+ break;
+
+ case '\010':
+ crtat -= CHR;
+ break;
+
+ case '\r':
+ crtat -= (crtat - Crtat) % (COL*CHR);
+ break;
+
+ case '\n':
+ crtat += COL*CHR ;
+ break;
+
+ default:
+ crtat[0] = c;
+ crtat[1] = att;
+ crtat += CHR;
+ break ;
+ }
+
+ /* implement a scroll */
+ if (crtat >= Crtat+COL*ROW*CHR) {
+ /* move text up */
+ bcopy((char *)(Crtat+COL*CHR), (char *)Crtat, COL*(ROW-1)*CHR);
+
+ /* clear line */
+ for (cp = Crtat+ COL*(ROW-1)*CHR;
+ cp < Crtat + COL*ROW*CHR ; cp += 2)
+ cp[0] = ' ';
+
+ crtat -= COL*CHR ;
+ }
+ cursor((crtat-Crtat)/CHR);
+#endif
+}
+
+void
+putchar(int c)
+{
+ if (c == '\n')
+ putc('\r');
+ putc(c);
+}
+
+/* printf - only handles %d as decimal, %c as char, %s as string */
+
+void
+printf(format,data)
+ const char *format;
+ int data;
+{
+ int *dataptr = &data;
+ char c;
+ while ((c = *format++)) {
+ if (c != '%')
+ putchar(c);
+ else {
+ switch (c = *format++) {
+ case 'd': {
+ int num = *dataptr++;
+ char buf[10], *ptr = buf;
+ if (num<0) {
+ num = -num;
+ putchar('-');
+ }
+ do
+ *ptr++ = '0'+num%10;
+ while ((num /= 10));
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'x': {
+ int num = *dataptr++, dig;
+ char buf[8], *ptr = buf;
+ do
+ *ptr++ = (dig=(num&0xf)) > 9?
+ 'a' + dig - 10 :
+ '0' + dig;
+ while ((num >>= 4));
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'c': putchar((*dataptr++)&0xff); break;
+ case 's': {
+ char *ptr = (char *)*dataptr++;
+ while ((c = *ptr++))
+ putchar(c);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/sys/arch/i386/netboot/config.h b/sys/arch/i386/netboot/config.h
new file mode 100644
index 00000000000..38586743818
--- /dev/null
+++ b/sys/arch/i386/netboot/config.h
@@ -0,0 +1,23 @@
+/* $NetBSD: config.h,v 1.3 1994/10/27 04:21:10 cgd Exp $ */
+
+/* netboot
+ *
+ * source in this file came from
+ */
+
+#if !defined(__config_h_)
+#define __config_h_
+
+/*
+ configuration items shared between .c and .s files
+ */
+
+#define WORK_AREA_SIZE 0x10000L
+
+#define T(x) printf(" " #x ":\n")
+
+/* turn a near address into an integer
+ representing a linear physical addr */
+#define LA(x) ((u_long)(x))
+
+#endif
diff --git a/sys/arch/i386/netboot/dp8390.h b/sys/arch/i386/netboot/dp8390.h
new file mode 100644
index 00000000000..2436d729bc7
--- /dev/null
+++ b/sys/arch/i386/netboot/dp8390.h
@@ -0,0 +1,166 @@
+/* $NetBSD: dp8390.h,v 1.3 1994/10/27 04:21:11 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * National Semiconductor DP8390 Network Interface Controller
+ */
+
+/* page 0: for reading */
+#define DP_CR 0x00 /* read side of command register */
+#define DP_CLDA0 0x01 /* current local DMA address 0 */
+#define DP_CLDA1 0x02 /* current local DMA address 1 */
+#define DP_BNRY 0x03 /* boundary pointer */
+#define DP_TSR 0x04 /* transmit status register */
+#define DP_NCR 0x05 /* number of collisions register */
+#define DP_FIFO 0x06 /* FIFO */
+#define DP_ISR 0x07 /* interrupt status register */
+#define DP_CRDA0 0x08 /* current remote DMA address 0 */
+#define DP_CRDA1 0x09 /* current remote DMA address 1 */
+#define DP_RSR 0x0C /* receive status register */
+#define DP_CNTR0 0x0D /* tally counter 0 */
+#define DP_CNTR1 0x0E /* tally counter 1 */
+#define DP_CNTR2 0x0F /* tally counter 2 */
+
+/* page 0: for writing */
+#define DP_CR 0x00 /* write side of command register */
+#define DP_PSTART 0x01 /* page start register */
+#define DP_PSTOP 0x02 /* page stop register */
+#define DP_BNRY 0x03 /* boundary pointer */
+#define DP_TPSR 0x04 /* transmit page start register */
+#define DP_TBCR0 0x05 /* transmit byte count register 0 */
+#define DP_TBCR1 0x06 /* transmit byte count register 1 */
+#define DP_ISR 0x07 /* interrupt status register */
+#define DP_RSAR0 0x08 /* remote start address register 0 */
+#define DP_RSAR1 0x09 /* remote start address register 1 */
+#define DP_RBCR0 0x0A /* remote byte count register 0 */
+#define DP_RBCR1 0x0B /* remote byte count register 1 */
+#define DP_RCR 0x0C /* receive configuration register */
+#define DP_TCR 0x0D /* transmit configuration register */
+#define DP_DCR 0x0E /* data configuration register */
+#define DP_IMR 0x0F /* interrupt mask register */
+
+/* page 1: read/write */
+#define DP_CR 0x00 /* command register */
+#define DP_PAR0 0x01 /* physical address register 0 */
+#define DP_PAR1 0x02 /* physical address register 1 */
+#define DP_PAR2 0x03 /* physical address register 2 */
+#define DP_PAR3 0x04 /* physical address register 3 */
+#define DP_PAR4 0x05 /* physical address register 4 */
+#define DP_PAR5 0x06 /* physical address register 5 */
+#define DP_CURR 0x07 /* current page register */
+#define DP_MAR0 0x08 /* multicast address register 0 */
+#define DP_MAR1 0x09 /* multicast address register 1 */
+#define DP_MAR2 0x0A /* multicast address register 2 */
+#define DP_MAR3 0x0B /* multicast address register 3 */
+#define DP_MAR4 0x0C /* multicast address register 4 */
+#define DP_MAR5 0x0D /* multicast address register 5 */
+#define DP_MAR6 0x0E /* multicast address register 6 */
+#define DP_MAR7 0x0F /* multicast address register 7 */
+
+/* bits in command register */
+#define CR_STP 0x01 /* stop: software reset */
+#define CR_STA 0x02 /* start: activate NIC */
+#define CR_TXP 0x04 /* transmit packet */
+#define CR_DMA 0x38 /* mask for DMA control */
+# define CR_DM_NOP 0x00 /* DMA: no operation */
+# define CR_DM_RR 0x08 /* DMA: remote read */
+# define CR_DM_RW 0x10 /* DMA: remote write */
+# define CR_DM_SP 0x18 /* DMA: send packet */
+# define CR_DM_ABORT 0x20 /* DMA: abort remote DMA operation */
+#define CR_PS 0xC0 /* mask for page select */
+# define CR_PS_P0 0x00 /* register page 0 */
+# define CR_PS_P1 0x40 /* register page 1 */
+# define CR_PS_T0 0x80 /* test mode register map */
+# define CR_SP_T1 0xC0 /* test mode register map */
+
+/* bits in interrupt status register */
+#define ISR_PRX 0x01 /* packet received with no errors */
+#define ISR_PTX 0x02 /* packet transmitted with no errors */
+#define ISR_RXE 0x04 /* receive error */
+#define ISR_TXE 0x08 /* transmit error */
+#define ISR_OVW 0x10 /* overwrite warning */
+#define ISR_CNT 0x20 /* counter overflow */
+#define ISR_RDC 0x40 /* remote DMA complete */
+#define ISR_RST 0x80 /* reset status */
+
+/* bits in interrupt mask register */
+#define IMR_PRXE 0x01 /* packet received ienable */
+#define IMR_PTXE 0x02 /* packet transmitted ienable */
+#define IMR_RXEE 0x04 /* receive error ienable */
+#define IMR_TXEE 0x08 /* transmit error ienable */
+#define IMR_OVWE 0x10 /* overwrite warning ienable */
+#define IMR_CNTE 0x20 /* counter overflow ienable */
+#define IMR_RDCE 0x40 /* DMA complete ienable */
+
+/* bits in data control register */
+#define DCR_WTS 0x01 /* word transfer select */
+# define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */
+# define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */
+#define DCR_BOS 0x02 /* byte order select */
+# define DCR_LTLENDIAN 0x00 /* BOS: little endian */
+# define DCR_BIGENDIAN 0x02 /* BOS: big endian */
+#define DCR_LAS 0x04 /* long address select */
+#define DCR_BMS 0x08 /* burst mode select */
+#define DCR_AR 0x10 /* autoinitialize remote */
+#define DCR_FTS 0x60 /* FIFO threshold select */
+# define DCR_2BYTES 0x00 /* 2 bytes */
+# define DCR_4BYTES 0x40 /* 4 bytes */
+# define DCR_8BYTES 0x20 /* 8 bytes */
+# define DCR_12BYTES 0x60 /* 12 bytes */
+
+/* bits in transmit configuration register */
+#define TCR_CRC 0x01 /* inhibit CRC */
+#define TCR_ELC 0x06 /* encoded loopback control */
+# define TCR_NORMAL 0x00 /* ELC: normal operation */
+# define TCR_INTERNAL 0x02 /* ELC: internal loopback */
+# define TCR_0EXTERNAL 0x04 /* ELC: external loopback LPBK=0 */
+# define TCR_1EXTERNAL 0x06 /* ELC: external loopback LPBK=1 */
+#define TCR_ATD 0x08 /* auto transmit */
+#define TCR_OFST 0x10 /* collision offset enable (be nice) */
+
+/* bits in transmit status register */
+#define TSR_PTX 0x01 /* packet transmitted (without error)*/
+#define TSR_DFR 0x02 /* transmit deferred */
+#define TSR_COL 0x04 /* transmit collided */
+#define TSR_ABT 0x08 /* transmit aborted */
+#define TSR_CRS 0x10 /* carrier sense lost */
+#define TSR_FU 0x20 /* fifo underrun */
+#define TSR_CDH 0x40 /* CD heartbeat */
+#define TSR_OWC 0x80 /* out of window collision */
+
+/* bits in receive configuration register */
+#define RCR_SEP 0x01 /* save errored packets */
+#define RCR_AR 0x02 /* accept runt packets */
+#define RCR_AB 0x04 /* accept broadcast */
+#define RCR_AM 0x08 /* accept multicast */
+#define RCR_PRO 0x10 /* physical promiscuous */
+#define RCR_MON 0x20 /* monitor mode */
+
+/* bits in receive status register */
+#define RSR_PRX 0x01 /* packet received intact */
+#define RSR_CRC 0x02 /* CRC error */
+#define RSR_FAE 0x04 /* frame alignment error */
+#define RSR_FO 0x08 /* FIFO overrun */
+#define RSR_MPA 0x10 /* missed packet */
+#define RSR_PHY 0x20 /* multicast address match !! */
+#define RSR_DIS 0x40 /* receiver disabled */
+
+/* dp8390 configuration information */
+typedef struct {
+ u_short dc_reg; /* dp8390 base address */
+ u_long dc_mem; /* base memory */
+ u_char dc_tpsr; /* transmit start page */
+ u_char dc_pstart; /* receive start page */
+ u_char dc_pstop; /* receive end page */
+} dpconf_t;
+
+
+/* dp8390 receive header */
+typedef struct {
+ u_char dh_status; /* copy of rsr */
+ u_char dh_next; /* pointer to next packet */
+ u_char dh_rbcl; /* receive byte count low */
+ u_char dh_rbch; /* receive byte count high */
+} dphdr_t;
diff --git a/sys/arch/i386/netboot/ether.h b/sys/arch/i386/netboot/ether.h
new file mode 100644
index 00000000000..fc215ff69f6
--- /dev/null
+++ b/sys/arch/i386/netboot/ether.h
@@ -0,0 +1,77 @@
+/* $NetBSD: ether.h,v 1.3 1994/10/27 04:21:12 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Ethernet definitions
+ */
+
+#define ETH_ADDRSIZE 6 /* address size */
+
+/*
+ * Structure of an ethernet header
+ */
+typedef struct {
+ u_char eth_dst[ETH_ADDRSIZE]; /* destination address */
+ u_char eth_src[ETH_ADDRSIZE]; /* source address */
+ u_short eth_proto; /* protocol type */
+} ethhdr_t;
+
+/* protocol types */
+#define ETHTYPE_IP 0x0800 /* IP protocol */
+#define ETHTYPE_ARP 0x0806 /* ARP protocol */
+#define ETHTYPE_RARP 0x8035 /* Reverse ARP protocol */
+
+extern u_char eth_myaddr[];
+
+int EtherInit(void);
+void EtherReset(void);
+void EtherStop(void);
+void EtherSend(packet_t *pkt, u_short proto, u_char *dest);
+packet_t *EtherReceive(void);
+void EtherPrintAddr(u_char *addr);
+
+/* TBD - move these elsewhere? */
+
+static inline u_short
+htons(u_short x) {
+ return ((x >> 8) & 0xff)
+ | ((x & 0xff) << 8);
+}
+
+#if 0
+static inline u_short
+ntohs(u_short x) {
+ return x >> 8 & 0xff
+ | (x & 0xff) << 8;
+}
+#else
+static inline u_short
+ntohs(u_short x) {
+ return htons(x);
+}
+#endif
+
+static inline u_long
+htonl(u_long x) {
+ return (x >> 24 & 0xffL)
+ | (x >> 8 & 0xff00L)
+ | (x << 8 & 0xff0000L)
+ | (x << 24 & 0xff000000L);
+}
+
+#if 0
+static inline u_long
+ntohl(u_long x) {
+ return x >> 24 & 0xffL
+ | x >> 8 & 0xff00L
+ | x << 8 & 0xff0000L
+ | x << 24 & 0xff000000L;
+}
+#else
+static inline u_long
+ntohl(u_long x) {
+ return htonl(x);
+}
+#endif
diff --git a/sys/arch/i386/netboot/genprom.c b/sys/arch/i386/netboot/genprom.c
new file mode 100644
index 00000000000..ea8d56bfa0c
--- /dev/null
+++ b/sys/arch/i386/netboot/genprom.c
@@ -0,0 +1,33 @@
+/* $NetBSD: genprom.c,v 1.3 1994/10/27 04:21:13 cgd Exp $ */
+
+/*
+ * Read a binary image of a bios extension, generate the
+ * appropriate block count and checksum and write them
+ * into the rom image (replacing 2nd and 5th bytes)
+ * The binary image should be sized before being filtered
+ * through this routine.
+ */
+
+#include <stdio.h>
+
+#define USE_SIZE ROM_SIZE
+#define PROM_SIZE 0x10000
+
+main() {
+ char w[PROM_SIZE], ck;
+ int i, sum;
+ memset(w, 0xff, PROM_SIZE);
+ i = fread(w, 1, PROM_SIZE, stdin);
+ fprintf(stderr, "bios extension size: %d (0x%x), read %d bytes\n",
+ USE_SIZE, USE_SIZE, i);
+ w[2] = USE_SIZE / 512;
+ for (sum=0, i=0; i<USE_SIZE; i++) {
+ sum += w[i];
+ }
+ w[5] = -sum;
+ for (ck=0, i=0; i<USE_SIZE; i++) {
+ ck += w[i];
+ }
+ fwrite(w, 1, PROM_SIZE, stdout);
+}
+
diff --git a/sys/arch/i386/netboot/inet.h b/sys/arch/i386/netboot/inet.h
new file mode 100644
index 00000000000..5d29ccf7ef5
--- /dev/null
+++ b/sys/arch/i386/netboot/inet.h
@@ -0,0 +1,59 @@
+/* $NetBSD: inet.h,v 1.3 1994/10/27 04:21:14 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Various UDP/IP definitions (see RFC 768, and 791)
+ */
+
+/* generic IP address */
+#define IP_ANYADDR (ipaddr_t)0 /* IP any address */
+#define IP_BCASTADDR (ipaddr_t)0xffffffff /* IP broadcast address */
+
+/* some well defined protocols/ports */
+#define IP_PROTO_UDP 17 /* user datagram protocol */
+#define IP_PORT_TFTP 69 /* trivial FTP port */
+
+/* internet address type */
+typedef u_long ipaddr_t;
+
+/* internet address type (only used for printing address) */
+typedef union {
+ ipaddr_t a;
+ struct { u_char a0, a1, a2, a3; } s;
+} inetaddr_t;
+
+/*
+ * Structure of an internet header (without options)
+ */
+typedef struct {
+ u_char ip_vhl; /* version and header length */
+#define IP_VERSION 4 /* current version number */
+ u_char ip_tos; /* type of service */
+ u_short ip_len; /* total length */
+ u_short ip_id; /* identification */
+ u_short ip_off; /* fragment offset field */
+ u_char ip_ttl; /* time to live */
+#define IP_FRAGTTL 60 /* time to live for frags */
+ u_char ip_p; /* protocol */
+ u_short ip_sum; /* checksum */
+ ipaddr_t ip_src; /* source address */
+ ipaddr_t ip_dst; /* destination address */
+} iphdr_t;
+
+/*
+ * Structure of an UDP header
+ */
+typedef struct {
+ u_short uh_sport; /* source port */
+ u_short uh_dport; /* destination port */
+ u_short uh_len; /* udp length */
+ u_short uh_sum; /* udp checksum */
+} udphdr_t;
+
+/* these are actually defined in arp.c */
+extern ipaddr_t ip_myaddr; /* my own IP address */
+extern ipaddr_t ip_gateway; /* gateway's IP address */
+
+void IpPrintAddr(ipaddr_t);
diff --git a/sys/arch/i386/netboot/kbd.c b/sys/arch/i386/netboot/kbd.c
new file mode 100644
index 00000000000..6b6f33e1662
--- /dev/null
+++ b/sys/arch/i386/netboot/kbd.c
@@ -0,0 +1,363 @@
+/* $NetBSD: kbd.c,v 1.3 1994/10/27 04:21:15 cgd Exp $ */
+
+/* netboot
+ *
+ * source in this file came from
+ * the original 386BSD boot blocks.
+ *
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kbd.c 7.4 (Berkeley) 5/4/91
+ */
+
+#include "proto.h"
+
+#define KBSTATP 0x64 /* kbd status port */
+#define KBS_INP_BUF_FUL 0x02 /* kbd char ready */
+#define KBDATAP 0x60 /* kbd data port */
+
+#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_A20 0x9f /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+#define L 0x01 /* locking function */
+#define SHF 0x02 /* keyboard shift */
+#define ALT 0x04 /* alternate shift -- alternate chars */
+#define NUM 0x08 /* numeric shift cursors vs. numeric */
+#define CTL 0x10 /* control shift -- allows ctl function */
+#define CPS 0x20 /* caps shift -- swaps case of letter */
+#define ASCII 0x40 /* ascii code for this key */
+#define STP 0x80 /* stop output */
+
+static u_char action[128] = {
+0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */
+ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */
+ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */
+ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */
+ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */
+ASCII, ASCII, SHF , ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */
+ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */
+ ALT, ASCII, CPS|L, 0, 0, ASCII, 0, 0, /* scan 56-63 */
+ 0, 0, 0, 0, 0, NUM|L, STP|L, ASCII, /* scan 64-71 */
+ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */
+ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
+
+static u_char unshift[128] = { /* no shift */
+0, 033 , '1' , '2' , '3' , '4' , '5' , '6' , /* scan 0- 7 */
+'7' , '8' , '9' , '0' , '-' , '=' , 0177 ,'\t' , /* scan 8-15 */
+
+'q' , 'w' , 'e' , 'r' , 't' , 'y' , 'u' , 'i' , /* scan 16-23 */
+'o' , 'p' , '[' , ']' , '\r' , CTL , 'a' , 's' , /* scan 24-31 */
+
+'d' , 'f' , 'g' , 'h' , 'j' , 'k' , 'l' , ';' , /* scan 32-39 */
+'\'' , '`' , SHF , '\\' , 'z' , 'x' , 'c' , 'v' , /* scan 40-47 */
+
+'b' , 'n' , 'm' , ',' , '.' , '/' , SHF , '*', /* scan 48-55 */
+ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
+
+ 0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */
+ '8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
+
+ '2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
+
+static u_char shift[128] = { /* shift shift */
+0, 033 , '!' , '@' , '#' , '$' , '%' , '^' , /* scan 0- 7 */
+'&' , '*' , '(' , ')' , '_' , '+' , 0177 ,'\t' , /* scan 8-15 */
+'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , /* scan 16-23 */
+'O' , 'P' , '[' , ']' , '\r' , CTL , 'A' , 'S' , /* scan 24-31 */
+'D' , 'F' , 'G' , 'H' , 'J' , 'K' , 'L' , ':' , /* scan 32-39 */
+'"' , '~' , SHF , '|' , 'Z' , 'X' , 'C' , 'V' , /* scan 40-47 */
+'B' , 'N' , 'M' , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */
+ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
+ 0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */
+ '8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
+ '2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
+
+static u_char ctl[128] = { /* CTL shift */
+0, 033 , '!' , 000 , '#' , '$' , '%' , 036 , /* scan 0- 7 */
+'&' , '*' , '(' , ')' , 037 , '+' , 034 ,'\177', /* scan 8-15 */
+021 , 027 , 005 , 022 , 024 , 031 , 025 , 011 , /* scan 16-23 */
+017 , 020 , 033 , 035 , '\r' , CTL , 001 , 013 , /* scan 24-31 */
+004 , 006 , 007 , 010 , 012 , 013 , 014 , ';' , /* scan 32-39 */
+'\'' , '`' , SHF , 034 , 032 , 030 , 003 , 026 , /* scan 40-47 */
+002 , 016 , 015 , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */
+ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
+CPS|L, 0, 0, 0, 0, 0, 0, 0, /* scan 64-71 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* scan 72-79 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* scan 80-87 */
+ 0, 0, 033, '7' , '4' , '1' , 0, NUM|L, /* scan 88-95 */
+'8' , '5' , '2' , 0, STP|L, '9' , '6' , '3' , /*scan 96-103*/
+'.' , 0, '*' , '-' , '+' , 0, 0, 0, /*scan 104-111*/
+0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
+
+static u_char shfts, ctls, alts, caps, num, stp;
+static u_char chr;
+static int is_chr_queued = 0;
+
+static int
+ProcessKbdEvent(void) {
+ /* Returns 1 if event result is an ascii char, 0 otherwise (or no event).
+ * As a side effect, it digests keyboard events and queues bona fide
+ * characters for subsequent reading.
+ */
+ u_char dt, brk, act;
+ if ((inb(KBSTATP) & 0x01) == 0)
+ return is_chr_queued;
+ dt = inb(KBDATAP);
+ brk = dt & 0x80;
+ dt = dt & 0x7f;
+
+ act = action[dt];
+ if (act & SHF) {
+ if (brk)
+ shfts = 0;
+ else
+ shfts = 1;
+ }
+ if (act & ALT) {
+ if (brk)
+ alts = 0;
+ else
+ alts = 1;
+ }
+ if (act & NUM) {
+ if (act & L) {
+ if (!brk)
+ num ^= 1;
+ } else
+ if(brk)
+ num = 0;
+ else
+ num = 1;
+ }
+ if (act & CTL) {
+ if (brk)
+ ctls = 0;
+ else
+ ctls = 1;
+ }
+ if (act & CPS) {
+ if (act & L) {
+ if (!brk)
+ caps ^= 1;
+ } else
+ if (brk)
+ caps = 0;
+ else
+ caps = 1;
+ }
+ if (act & STP) {
+ if (act & L) {
+ if (!brk)
+ stp ^= 1;
+ } else
+ if (brk)
+ stp = 0;
+ else
+ stp = 1;
+ }
+ if (ctls && alts && dt == 83)
+ exit(1);
+ if ((act & ASCII) && !brk) {
+ if (shfts) {
+ chr = shift[dt];
+ } else {
+ if (ctls) {
+ chr = ctl[dt];
+ } else {
+ chr = unshift[dt];
+ }
+ }
+ if (caps && (chr >= 'a' && chr <= 'z')) {
+ chr -= 'a' - 'A' ;
+ }
+ is_chr_queued = 1;
+ }
+ return is_chr_queued;
+}
+
+int
+IsKbdCharReady(void) {
+#ifdef USE_BIOS
+ int result;
+ asm("
+ push %%ebx
+ call _prot_to_real
+ mov $1, %%ax
+ int $0x16
+ setz %%bl
+ .byte 0x66
+ call _real_to_prot
+ movsbl %%bl, %0
+ pop %%ebx
+ " : "=g" (result));
+ return result;
+#else
+ return ProcessKbdEvent();
+#endif
+}
+
+static int
+scankbd(void) {
+
+#ifdef notdef
+ u_char c;
+ c = inb(KBDATAP);
+ if (c == 83) exit();
+ /*if (c == 0xaa) return (0);
+ if (c == 0xfa) return (0);*/
+
+ if (bdt == 0) { bdt = c&0x7f; return(0); }
+
+ if(odt) return(1);
+
+ c &= 0x7f;
+
+ if (bdt == c) return(0);
+ odt = c;
+#endif
+ return 1;
+}
+
+static void
+kbdreset(void) {
+ u_char c;
+
+ /* Enable interrupts and keyboard controller */
+ while (inb(KBSTATP)&2); outb(KBSTATP,0x60);
+ while (inb(KBSTATP)&2); outb(KBDATAP,0x4D);
+
+ /* Start keyboard stuff RESET */
+ while (inb(KBSTATP)&2); /* wait input ready */
+ outb(KBDATAP,0xFF); /* RESET */
+
+ while((c=inb(KBDATAP))!=0xFA) ;
+
+ /* While we are here, defeat gatea20 */
+ while (inb(KBSTATP)&2); /* wait input ready */
+ outb(KBSTATP,0xd1);
+ while (inb(KBSTATP)&2); /* wait input ready */
+ outb(KBDATAP,0xdf);
+ while (inb(KBSTATP)&2); /* wait input ready */
+ inb(KBDATAP);
+}
+
+/* TBD - what does this do?, used by ResetCpu() */
+void
+KbdWait(int n) {
+ int v;
+
+ v = 0;
+ while(n-- && (v = scankbd()) == 0);
+ if (v) kbdreset();
+}
+
+/*
+ * Gate A20 for high memory
+ */
+u_char x_20 = KB_A20;
+
+void
+gateA20(void) {
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+}
+
+int
+getc(void) {
+#ifdef USE_BIOS
+ int rslt;
+ asm("
+ push %%ebx
+ call _prot_to_real
+ movb $0x0, %%ah
+ sti
+ int $0x16
+ cli
+ movb %%al, %%bl
+ .byte 0x66
+ call _real_to_prot
+ xor %%eax, %%eax
+ movb %%bl, %0
+ pop %%ebx
+ " : "=g" (rslt));
+ return rslt;
+#else
+ while (!is_chr_queued) {
+ ProcessKbdEvent();
+ }
+ is_chr_queued = 0;
+ return chr;
+#endif
+}
+
+int
+getchar(void) {
+ int c;
+
+ if ((c=getc()) == '\r')
+ c = '\n';
+ if (c == '\b') {
+ putchar('\b');
+ putchar(' ');
+ }
+ putchar(c);
+ return c;
+}
diff --git a/sys/arch/i386/netboot/lance.h b/sys/arch/i386/netboot/lance.h
new file mode 100644
index 00000000000..4cf39f74102
--- /dev/null
+++ b/sys/arch/i386/netboot/lance.h
@@ -0,0 +1,114 @@
+/* $NetBSD: lance.h,v 1.3 1994/10/27 04:21:16 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ */
+
+/* RAP functions as a select for RDP */
+#define RDP_CSR0 0
+#define RDP_CSR1 1
+#define RDP_CSR2 2
+#define RDP_CSR3 3
+
+/* contents of csr0 */
+#define CSR_ERR 0x8000
+#define CSR_BABL 0x4000
+#define CSR_CERR 0x2000
+#define CSR_MISS 0x1000
+#define CSR_MERR 0x0800
+#define CSR_RINT 0x0400
+#define CSR_TINT 0x0200
+#define CSR_IDON 0x0100
+#define CSR_INTR 0x0080
+#define CSR_INEA 0x0040
+#define CSR_RXON 0x0020
+#define CSR_TXON 0x0010
+#define CSR_TDMD 0x0008
+#define CSR_STOP 0x0004
+#define CSR_STRT 0x0002
+#define CSR_INIT 0x0001
+
+/* csr1 contains low 16 bits of address of Initialization Block */
+
+/* csr2 contains in low byte high 8 bits of address of InitBlock */
+
+/* contents of csr3 */
+#define CSR3_BSWP 0x04 /* byte swap (for big endian) */
+#define CSR3_ACON 0x02 /* ALE control */
+#define CSR3_BCON 0x01 /* byte control */
+
+/*
+ * The initialization block
+ */
+typedef struct {
+ u_short ib_mode; /* modebits, see below */
+ char ib_padr[6]; /* physical 48bit Ether-address */
+ u_short ib_ladrf[4]; /* 64bit hashtable for "logical" addresses */
+ u_short ib_rdralow; /* low 16 bits of Receiver Descr. Ring addr */
+ u_char ib_rdrahigh; /* high 8 bits of Receiver Descr. Ring addr */
+ u_char ib_rlen; /* upper 3 bits are 2log Rec. Ring Length */
+ u_short ib_tdralow; /* low 16 bits of Transm. Descr. Ring addr */
+ u_char ib_tdrahigh; /* high 8 bits of Transm. Descr. Ring addr */
+ u_char ib_tlen; /* upper 3 bits are 2log Transm. Ring Length */
+} initblock_t;
+
+/* bits in mode */
+#define IB_PROM 0x8000
+#define IB_INTL 0x0040
+#define IB_DRTY 0x0020
+#define IB_COLL 0x0010
+#define IB_DTCR 0x0008
+#define IB_LOOP 0x0004
+#define IB_DTX 0x0002
+#define IB_DRX 0x0001
+
+/*
+ * A receive message descriptor entry
+ */
+typedef struct {
+ u_short rmd_ladr; /* low 16 bits of bufaddr */
+ char rmd_hadr; /* high 8 bits of bufaddr */
+ char rmd_flags; /* see below */
+ short rmd_bcnt; /* two's complement of buffer byte count */
+ u_short rmd_mcnt; /* message byte count */
+} rmde_t;
+
+/* bits in flags */
+#define RMD_OWN 0x80
+#define RMD_ERR 0x40
+#define RMD_FRAM 0x20
+#define RMD_OFLO 0x10
+#define RMD_CRC 0x08
+#define RMD_BUFF 0x04
+#define RMD_STP 0x02
+#define RMD_ENP 0x01
+
+/*
+ * A transmit message descriptor entry
+ */
+typedef struct {
+ u_short tmd_ladr; /* low 16 bits of bufaddr */
+ u_char tmd_hadr; /* high 8 bits of bufaddr */
+ u_char tmd_flags; /* see below */
+ short tmd_bcnt; /* two's complement of buffer byte count */
+ u_short tmd_err; /* more error bits + TDR */
+} tmde_t;
+
+/* bits in flags */
+#define TMD_OWN 0x80
+#define TMD_ERR 0x40
+#define TMD_MORE 0x10
+#define TMD_ONE 0x08
+#define TMD_DEF 0x04
+#define TMD_STP 0x02
+#define TMD_ENP 0x01
+
+/* bits in tmd_err */
+#define TMDE_BUFF 0x8000
+#define TMDE_UFLO 0x4000
+#define TMDE_LCOL 0x1000
+#define TMDE_LCAR 0x0800
+#define TMDE_RTRY 0x0400
+#define TMDE_TDR 0x003F /* mask for TDR */
+
diff --git a/sys/arch/i386/netboot/main.c b/sys/arch/i386/netboot/main.c
new file mode 100644
index 00000000000..c62ca8a9516
--- /dev/null
+++ b/sys/arch/i386/netboot/main.c
@@ -0,0 +1,639 @@
+/* $NetBSD: main.c,v 1.5 1994/10/27 04:21:17 cgd Exp $ */
+
+/*
+ * source code in this file is from:
+ * 386BSD boot blocks by Julian Elischer (julian@tfs.com)
+ * 386BSD Adaptec 1542 SCSI boot blocks by Pace Willisson (pace@blitz.com)
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+
+#include "config.h"
+#include "nbtypes.h"
+#include "assert.h"
+#include "param.h"
+#include "packet.h"
+#include "ether.h"
+#include "inet.h"
+#include "arp.h"
+#include "tftp.h"
+
+#include "proto.h"
+
+
+u_long work_area_org = RELOC;
+u_long kernel_size;
+u_short real_cs;
+u_long howto = 0;
+u_char vendor_area[64];
+
+enum LoadErr {
+ load_success,
+ load_no_answer,
+ load_bad_format,
+ load_bad_size,
+};
+
+static inline enum LoadErr
+LoadProgFromServer(ipaddr_t server, ipaddr_t gateway, char *file_name) {
+ /* TBD - fail (or at least warn) if we don't get the entire file */
+ u_long start_addr;
+ u_long boot_area_org;
+ u_long tmp_reloc_org;
+ u_long kern_copy_org;
+ u_long kern_copy_p;
+ struct exec head;
+ u_long boot_argv[4];
+#if 1 /* ndef USE_BUFFER */
+ u_char tmpbuf[4096]; /* we need to load the first 4k here */
+#endif
+
+ SetTftpParms(server, gateway, file_name);
+
+ /* TBD - heuristics about what we are loading - load linux, ... also */
+
+ if (Read(&head, sizeof(head)) != sizeof(head))
+ return load_bad_size;
+
+ if (N_GETMAGIC(head) != ZMAGIC) {
+ printf("Invalid format!\n");
+ return load_bad_format;
+ }
+
+ /* Load/tftp the executable to a temporary area beyond 640k - after
+ successful load, copy to correct area. If load fails or is interrrupted,
+ we can recover gracefully
+ */
+
+ start_addr = (u_long)head.a_entry;
+ boot_area_org = start_addr & 0x00f00000; /* some MEG boundary */
+ tmp_reloc_org = 0x00100000;
+#ifdef USE_BUFFER
+ kern_copy_org = tmp_reloc_org + WORK_AREA_SIZE; /* leave free for relocation */
+#else
+ kern_copy_org = boot_area_org; /* leave free for relocation */
+#endif
+ kern_copy_p = kern_copy_org;
+ kernel_size = head.a_text + head.a_data + head.a_bss;
+
+ printf("Loading ");
+ IpPrintAddr(server);
+ printf(":%s @ 0x%x\n", file_name, boot_area_org);
+#ifndef USE_BUFFER
+ if(boot_area_org < work_area_org) {
+ if((boot_area_org + head.a_text + head.a_data) > work_area_org) {
+ printf("kernel will not fit below loader\n");
+ return load_bad_size;
+ }
+ if((boot_area_org + head.a_text + head.a_data + head.a_bss) > 0xa0000) {
+ printf("kernel too big, won't fit in 640K with bss\n");
+ printf("Only hope is to link the kernel for > 1MB\n");
+ return load_bad_size;
+ }
+ if(boot_area_org + kernel_size > work_area_org) {
+ printf("loader overlaps bss, kernel must bzero\n");
+ }
+ }
+#else
+ if(boot_area_org + kernel_size > 0xa0000) {
+ printf("kernel too big, won't fit in 640K with bss\n");
+ printf("Only hope is to link the kernel for > 1MB\n");
+ return load_bad_size;
+ }
+ /* check if too large for tmp buffer (TBD) */
+#endif
+ printf("text=0x%x", head.a_text);
+
+#if 01
+ /* skip to first 4k boundry */
+ Read(tmpbuf, 4096-sizeof(head));
+#endif
+
+#if 0 /* ndef USE_BUFFER */
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /* don't clobber the first 4k yet (BIOS NEEDS IT) */
+ /********************************************************/
+ Read(tmpbuf, sizeof(tmpbuf));
+ kern_copy_p += sizeof(tmpbuf);
+ PhysRead(kern_copy_p, head.a_text - sizeof(tmpbuf));
+ kern_copy_p += head.a_text - sizeof(tmpbuf);
+#else
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /********************************************************/
+ PhysRead(kern_copy_p, head.a_text);
+ kern_copy_p += head.a_text;
+#endif
+
+ /********************************************************/
+ /* Load the Initialised data after the text */
+ /********************************************************/
+/* TBD - this is bogus - file system oriented */
+#define CLSIZE 1
+#define NBPG 4096 /* bytes/page */
+#define CLOFSET (CLSIZE*NBPG-1) /* for clusters, like PGOFSET */
+
+ while (kern_copy_p & CLOFSET)
+ *(char *)kern_copy_p++ = 0;
+
+ printf(" data=0x%x", head.a_data);
+ PhysRead(kern_copy_p, head.a_data);
+ kern_copy_p += head.a_data;
+
+ /********************************************************/
+ /* Skip over the uninitialised data */
+ /* (but clear it) */
+ /********************************************************/
+ printf(" bss=0x%x", head.a_bss);
+ if (kern_copy_p < RELOC &&
+ (kern_copy_p + head.a_bss) > RELOC) {
+ PhysBzero(kern_copy_p, RELOC-(u_int)kern_copy_p);
+ } else {
+ PhysBzero(kern_copy_p, head.a_bss);
+ }
+
+#ifdef LOADSYMS /* not yet, haven't worked this out yet */
+ if (kern_copy_p > 0x100000) {
+ /********************************************************/
+ /*copy in the symbol header */
+ /********************************************************/
+ PhysBcopy(&head.a_syms, kern_copy_p, sizeof(head.a_syms));
+ kern_copy_p += sizeof(head.a_syms);
+
+ /********************************************************/
+ /* READ in the symbol table */
+ /********************************************************/
+ printf(" symbols=[+0x%x", head.a_syms);
+ Read(kern_copy_p, head.a_syms);
+ kern_copy_p += head.a_syms;
+
+ /********************************************************/
+ /* Followed by the next integer (another header) */
+ /* more debug symbols? */
+ /********************************************************/
+ read(&i, sizeof(u_int));
+ PhysBcopy(&i, kern_copy_p, sizeof(u_int));
+ i -= sizeof(u_int);
+ kern_copy_p += sizeof(u_int);
+
+ /********************************************************/
+ /* and that many bytes of (debug symbols?) */
+ /********************************************************/
+ printf("+0x%x]", i);
+ Read(kern_copy_p, i);
+ kern_copy_p += i;
+ }
+#endif LOADSYMS
+
+ /********************************************************/
+ /* and note the end address of all this */
+ /********************************************************/
+
+ printf(" total=0x%x",kern_copy_p - kern_copy_org);
+
+ boot_argv[0] = 0;
+ boot_argv[1] = howto;
+ boot_argv[2] = 0;
+ boot_argv[3] = 0;
+
+/* TBD - place vendor_area on stack */
+
+ printf(" entry point=0x%x\n" ,((u_int)start_addr) & 0xffffff);
+
+ if (howto) {
+ static char *rb_option_name[9] = {
+ "askname",
+ "single",
+ "nosync",
+ "halt",
+ "initname",
+ "dfltroot",
+ "kdb",
+ "rdonly",
+ "dump",
+ };
+ int i;
+ printf("Starting kernel with options (0x%x): ", howto);
+ for (i=0; i<9; i++) {
+ if (howto & (1<<i)) {
+ printf("%s ", rb_option_name[i]);
+ }
+ }
+ printf("\n");
+ }
+
+#if 0 /* ndef USE_BUFFER */
+ PhysBcopy(tmpbuf, boot_area_org, sizeof(tmpbuf));
+#endif
+
+ StartProg(start_addr & 0xffffff, boot_argv);
+
+ return load_success; /* hah! */
+}
+
+int GetHex(int old) {
+ int r, c, ch;
+ r = 0;
+ ch = 0;
+ while((c=getchar()) != '\n') {
+ ch = 1;
+ if (c>='0' && c<='9')
+ r = r*16 + (c-'0');
+ else if (c>='a' && c<='f')
+ r = r*16 + (c+10-'a');
+ }
+ if (ch)
+ return r;
+ else
+ return old;
+}
+
+static char
+ToHex(int n) {
+ n &= 0x0F;
+ return n >= 10 ? n - 10 + 'A' : n + '0';
+}
+
+static char name_set[][9] = {
+ "xxxxxxxx",
+ "default",
+};
+
+static char *ext_set[] = {
+ ".netbsd",
+ ".netbsd.old",
+ ".386bsd",
+ ".386bsd.old",
+ ".vmunix",
+ ".vmunix.old",
+};
+
+static ipaddr_t server_set[2] = {
+ 0,
+ IP_BCASTADDR,
+};
+
+static inline void
+TryToLoadSomething(void) {
+ int nserver;
+ for (nserver=0; nserver<nelt(server_set); nserver++) {
+ int nname;
+ char file_name[MAX_FILE_NAME_LEN+1];
+ file_name[0] = '\0';
+ if (GetIpAddress(&server_set[nserver], &ip_myaddr, &ip_gateway, file_name)) {
+ if (*file_name) {
+ LoadProgFromServer(server_set[nserver], ip_gateway, file_name);
+ }
+ else {
+ /* no file name supplied from server, synthesize one */
+ inetaddr_t ip;
+ ip.a = ip_myaddr;
+ name_set[0][0] = ToHex(ip.s.a0 >> 4);
+ name_set[0][1] = ToHex(ip.s.a0);
+ name_set[0][2] = ToHex(ip.s.a1 >> 4);
+ name_set[0][3] = ToHex(ip.s.a1);
+ name_set[0][4] = ToHex(ip.s.a2 >> 4);
+ name_set[0][5] = ToHex(ip.s.a2);
+ name_set[0][6] = ToHex(ip.s.a3 >> 4);
+ name_set[0][7] = ToHex(ip.s.a3);
+ name_set[0][8] = 0;
+ for (nname=0; nname<nelt(name_set); nname++) {
+ int next;
+ for (next=0; next<nelt(ext_set); next++) {
+ strncpy(file_name, name_set[nname], MAX_FILE_NAME_LEN);
+ strncat(file_name, ext_set[next], MAX_FILE_NAME_LEN-strlen(file_name));
+ LoadProgFromServer(server_set[nserver], ip_gateway, file_name);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static char *
+DecimalToByte(char *s, u_char *n) {
+ for (*n = 0; *s >= '0' && *s <= '9'; s++)
+ *n = (*n * 10) + *s - '0';
+ return s;
+}
+
+static ipaddr_t
+IpConvertAddr(char *p) {
+ inetaddr_t addr;
+
+ if (p == (char *)0 || *p == '\0')
+ return IP_ANYADDR;
+ p = DecimalToByte(p, &addr.s.a0);
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = DecimalToByte(p, &addr.s.a1);
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = DecimalToByte(p, &addr.s.a2);
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = DecimalToByte(p, &addr.s.a3);
+ if (*p != '\0')
+ return IP_ANYADDR;
+ return addr.a;
+}
+
+static int
+GetLine(char **argv, int argvsize) {
+ char *p, ch;
+ static char line[128];
+ int argc;
+
+ /*
+ * Read command line, implement some simple editing features
+ */
+ p = line;
+ while ((ch = getchar()) != '\r' && ch != '\n' && (p-line) < sizeof(line)) {
+ if (ch == '\b') {
+ if (p > line) {
+ p--;
+ printf(" \b");
+ }
+ } else
+ *p++ = ch;
+ }
+ *p = '\0';
+
+ /*
+ * Break command line up into an argument vector
+ */
+ argc = 0;
+ for (p = line; *p == ' ' || *p == '\t'; p++)
+ /* skip white spaces */;
+ while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') {
+ if (argc > argvsize) break;
+ argv[(argc)++] = p;
+ for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++)
+ /* skip word */;
+ if (*p != '\0') *p++ ='\0';
+ for (; *p == ' ' || *p == '\t'; p++)
+ /* skip white spaces */;
+ }
+ argv[(argc)] = (char *)0;
+ return argc;
+}
+
+enum cmd_token_type {
+ CMD_GO,
+ CMD_HELP,
+ CMD_RESET,
+ CMD_AUTO,
+ CMD_WHO,
+ CMD_REBOOT,
+ CMD_DISKBOOT,
+ CMD_ADDRESS,
+ CMD_GATEWAY,
+ CMD_TFTP,
+ CMD_DEBUG,
+ CMD_SINGLE,
+ CMD_FILE,
+ CMD_SERVER,
+};
+
+struct commands {
+ enum cmd_token_type cmd_token;
+ char *cmd_name;
+ char *cmd_help;
+} commands[] = {
+ {CMD_GO, "go", " start loaded binary"},
+ {CMD_HELP, "help", " this help message"},
+ {CMD_RESET, "reset", " reset ethernet board"},
+ {CMD_AUTO, "auto", " continue with auto boot"},
+ {CMD_WHO, "whoami", " get IP address"},
+ {CMD_REBOOT, "reboot", " hard reboot"},
+ {CMD_DISKBOOT, "diskboot", " soft reboot (from disk)"},
+ {CMD_ADDRESS, "address", "[<addr>] set IP address"},
+ {CMD_GATEWAY, "gateway", "[<addr>] set IP gateway"},
+ {CMD_SERVER, "server", "[<addr>] set server IP address"},
+ {CMD_FILE, "file", "[<name>] set boot file name"},
+ {CMD_TFTP, "tftp", " TFTP download"},
+ {CMD_DEBUG, "debug", " enter kernel debugger at boot"},
+ {CMD_SINGLE, "single", " enter single user at boot"},
+};
+
+#define ARGVECSIZE 100
+
+/*
+ * A very simple and terse monitor
+ */
+static void
+Monitor(void) {
+ char *argv[ARGVECSIZE];
+ static char file_name[MAX_FILE_NAME_LEN+1] = "default.bsd386";
+ int loaded, argc;
+ int i;
+ int token;
+ static ipaddr_t ip_servaddr = IP_ANYADDR;
+
+ loaded = 0;
+ printf("\n"
+#ifdef USE_BOOTP
+ "BOOTP/"
+#endif
+#ifdef USE_RARP
+ "RARP/"
+#endif
+ "TFTP monitor mode\n");
+ for (;;) {
+ char filename[MAX_FILE_NAME_LEN+1];
+ ipaddr_t gateway;
+ printf("ethernet boot monitor: ");
+ if ((argc = GetLine(argv, ARGVECSIZE)) > 0) {
+
+ for (token = -1, i = 0; i < nelt(commands); i++) {
+ if (strcmp(argv[0], commands[i].cmd_name) == 0) {
+ token = commands[i].cmd_token;
+ break;
+ }
+ }
+ switch (token) {
+ case CMD_HELP:
+ for (i = 0; i < nelt(commands); i++)
+ printf("%s %s\n", commands[i].cmd_name, commands[i].cmd_help);
+ break;
+ case CMD_RESET:
+ PktInit();
+ EtherReset();
+ break;
+ case CMD_REBOOT:
+ EtherStop();
+ ResetCpu();
+ break;
+ case CMD_DISKBOOT:
+ EtherStop();
+ exit(0);
+ break;
+ case CMD_AUTO:
+ return;
+ case CMD_WHO:
+ (void) GetIpAddress(&ip_servaddr, &ip_myaddr, &gateway, filename);
+ break;
+ case CMD_ADDRESS:
+ if (argc != 2) {
+ printf("My IP address is ");
+ IpPrintAddr(ip_myaddr);
+ printf("\n");
+ } else
+ ip_myaddr = IpConvertAddr(argv[1]);
+ break;
+ case CMD_SERVER:
+ if (argc != 2) {
+ printf("Server's IP address is ");
+ IpPrintAddr(ip_servaddr);
+ printf("\n");
+ } else
+ ip_servaddr = IpConvertAddr(argv[1]);
+ break;
+ case CMD_FILE:
+ if (argc != 2) {
+ printf("File name is \"%s\"\n", file_name);
+ } else
+ strncpy(file_name, argv[1], MAX_FILE_NAME_LEN);
+ break;
+ case CMD_GATEWAY:
+ if (argc != 2) {
+ printf("Gateway IP address is ");
+ IpPrintAddr(ip_gateway);
+ printf("\n");
+ } else
+ ip_gateway = IpConvertAddr(argv[1]);
+ break;
+ case CMD_DEBUG:
+ howto ^= RB_KDB;
+ break;
+ case CMD_SINGLE:
+ howto ^= RB_SINGLE;
+ break;
+ case CMD_TFTP:
+ if (ip_myaddr == IP_ANYADDR) {
+ printf("This machine's IP address must be set first.\n");
+ goto complain;
+ }
+ loaded = LoadProgFromServer(ip_servaddr, ip_gateway, file_name);
+ printf("File could not be loaded, giving up.\n");
+ break;
+ default:
+ goto complain;
+ }
+ } else
+ complain:
+ printf("Invalid or incorrect command. Type \"help\" for help.\n");
+ }
+}
+
+static jmp_buf jmp_env;
+
+void
+HandleKbdAttn(void) {
+ if (IsKbdCharReady())
+ if (getc() == 0x1b) {
+ EtherReset();
+ PktInit();
+ longjmp(jmp_env, 1);
+ }
+}
+
+int time_zero;
+
+void
+main(void) {
+
+ extern char edata[], end[];
+ char volatile * volatile p;
+
+ /* clear bss */
+ for (p = edata; p < end; p++)
+ *p = 0;
+
+ printf(
+#ifdef USE_BOOTP
+ "BOOTP/"
+#endif
+#ifdef USE_RARP
+ "RARP/"
+#endif
+ "TFTP bootstrap loader @0x%x: %d/%d k of memory. ^] for attn.\n",
+ work_area_org,
+ GetMemSize(0),
+ GetMemSize(1));
+
+ gateA20();
+
+ PktInit();
+ if (!EtherInit()) {
+ printf("No ethernet board found\n");
+ exit(1);
+ }
+ srand((time_zero=timer()) ^ eth_myaddr[5]);
+
+ printf("Ethernet address is ");
+ EtherPrintAddr(eth_myaddr);
+ printf("\n");
+
+ for (;;) {
+ if (setjmp(jmp_env))
+ Monitor();
+ else {
+ TryToLoadSomething();
+ }
+ }
+}
+
+#ifdef __GNUC__
+void
+__main(void) {
+}
+#endif
diff --git a/sys/arch/i386/netboot/misc.c b/sys/arch/i386/netboot/misc.c
new file mode 100644
index 00000000000..13a28b540f5
--- /dev/null
+++ b/sys/arch/i386/netboot/misc.c
@@ -0,0 +1,225 @@
+/* $NetBSD: misc.c,v 1.3 1994/10/27 04:21:18 cgd Exp $ */
+
+#include "proto.h"
+
+#if defined(DEBUG)
+
+void
+DUMP_STRUCT(char *s, u_char *p, u_int ps) {
+ int i;
+ printf("struct %s (@0x%x %d bytes): ", s, p, ps);
+ for (i=0; i<ps; i++)
+ printf("%x ", *(p+i));
+ printf("\n");
+}
+
+#else
+
+void
+DUMP_STRUCT(char *s, u_char *p, u_int ps) {
+}
+
+
+#endif
+
+
+char *
+strncpy(char *dst, const char *src, int len) {
+ char *p=dst;
+ while (*src && len--)
+ *p++ = *src++;
+ *p = 0;
+ return dst;
+}
+
+
+int
+strlen(const char *s) {
+ int len = 0;
+ while (*s++)
+ len++;
+ return len;
+}
+
+
+char *
+strncat(char *s, const char *append, int len) {
+ int offset = strlen(s);
+ strncpy(s+offset, append, len);
+ return s;
+}
+
+
+int
+strcmp(const char *s, const char *t) {
+ while (*s == *t++)
+ if (*s++ == '\0')
+ return 0;
+ return *s - *--t;
+}
+
+
+int
+bcmp(const void *p, const void *q, int len) {
+ while (len--)
+ if (*((const char *)p)++ != *((const char *)q)++)
+ return 1;
+ return 0;
+}
+
+
+void volatile exit(int v) {
+#ifdef DEBUG
+ L: goto L;
+#else
+ ExitToBios();
+#endif
+}
+
+
+#define RTC_ADDR 0x70
+#define RTC_DATA 0x71
+
+#define RTC_SECONDS 0x00
+#define RTC_MINUTES 0x02
+#define RTC_HOURS 0x04
+#define RTC_STATUS_A 0x0a
+#define RTC_BASEMEM_LO 0x15
+#define RTC_BASEMEM_HI 0x16
+#define RTC_EXPMEM_LO 0x30
+#define RTC_EXPMEM_HI 0x31
+
+static u_char
+ReadRtcRam(u_short addr) {
+ for (;;) {
+ /* wait if updating */
+ outb(RTC_ADDR, RTC_STATUS_A);
+ if (!(inb(RTC_DATA) & 0x80))
+ break;
+ }
+ outb(RTC_ADDR, addr);
+ return inb(RTC_DATA);
+}
+
+static void
+getrtc(u_long *hrs, u_long *mins, u_long *secs) {
+/* TBD - replace args with single arg - struct or sec of day */
+ /*
+ * Get real time clock values (they are in BCD)
+ */
+#ifdef USE_BIOS
+ asm("
+ call _prot_to_real
+ movb $0x02,%ah # read real time clock
+ int $0x1a
+ .byte 0x66
+ call _real_to_prot
+
+ xor %eax, %eax
+ movb %dh, %al
+ mov %%eax, %0
+ movb %cl, %al
+ mov %eax, %1
+ movb %ch, %al
+ mov %eax, %2
+ " : "=g" (secs), "=g" (mins), "=g" (hrs));
+#else
+ *secs = ReadRtcRam(RTC_SECONDS);
+ *mins = ReadRtcRam(RTC_MINUTES);
+ *hrs = ReadRtcRam(RTC_HOURS);
+#endif
+}
+
+static inline u_long
+bcd2dec(u_long arg) {
+ return ((arg & 0xF0) >> 4) * 10 + (arg & 0x0F);
+}
+
+
+u_long
+timer(void) {
+/* TBD - replace with StartCountdown()/CountdownAtZero() routines,
+ isolate the span-midnight problem to inside these routines
+ */
+ /*
+ * Return the current time in seconds
+ */
+
+ u_long sec, min, hour;
+
+ /* BIOS time is stored in bcd */
+ getrtc(&hour, &min, &sec);
+ sec = bcd2dec(sec);
+ min = bcd2dec(min);
+ hour = bcd2dec(hour);
+#if 0
+printe("time h%d m%d s%d = sum%d\n", hour, min, sec, hour * 3600L + min * 60L + sec);
+#endif
+ return hour * 3600L + min * 60L + sec;
+}
+
+/*
+ * Simple random generator
+ */
+static u_long next = 1;
+
+void
+srand(u_int seed) {
+ next = seed;
+}
+
+int
+rand(void) {
+ next = next * 1103515245L + 12345;
+ return (u_int)(next / 65536) % 32768;
+}
+
+u_short
+GetMemSize(u_short s) {
+#ifdef USE_BIOS
+ u_short result;
+ asm("
+ push %%ebx
+ mov %1, %%ebx
+ call _prot_to_real
+ cmpb $0x1, %%bl
+ .byte 0x66
+ je 1f
+ sti
+ int $0x12
+ cli
+ .byte 0x66
+ jmp 2f
+1: movb $0x88, %%ah
+ sti
+ int $0x15
+ cli
+2: mov %%eax, %%ebx
+ .byte 0x66
+ call _real_to_prot
+ mov %%bx, %0
+ pop %%ebx
+ " : "=g" (result) : "g" (s));
+ return result;
+#else
+ u_long result;
+ if (s)
+ result = ((u_long)ReadRtcRam(RTC_EXPMEM_HI)<<8) + ReadRtcRam(RTC_EXPMEM_LO);
+ else
+ result = ((u_long)ReadRtcRam(RTC_BASEMEM_HI)<<8) + ReadRtcRam(RTC_BASEMEM_LO);
+ return result;
+#endif
+}
+
+void
+ResetCpu(void) {
+#ifdef USE_BIOS
+ asm("
+ call _prot_to_real # enter real mode
+ int $0x19
+ " );
+#else
+ while (inb(0x64)&2); /* wait input ready */
+ outb(0x64, 0xFE); /* Reset Command */
+#endif
+}
diff --git a/sys/arch/i386/netboot/nbtypes.h b/sys/arch/i386/netboot/nbtypes.h
new file mode 100644
index 00000000000..8a4c3ffbafe
--- /dev/null
+++ b/sys/arch/i386/netboot/nbtypes.h
@@ -0,0 +1,95 @@
+/* $NetBSD: nbtypes.h,v 1.4 1994/10/27 04:21:19 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * various 386BSD system header files.
+ * The intent is to render these sources compilable from environments
+ * other than native 386bsd.
+ *
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __nbtypes_h_
+#define __nbtypes_h_
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+#define _JBLEN 10
+typedef int jmp_buf[_JBLEN];
+
+struct exec {
+ long a_midmag; /* magic number */
+unsigned long a_text; /* text segment size */
+unsigned long a_data; /* initialized data size */
+unsigned long a_bss; /* uninitialized data size */
+unsigned long a_syms; /* symbol table size */
+unsigned long a_entry; /* entry point */
+unsigned long a_trsize; /* text relocation size */
+unsigned long a_drsize; /* data relocation size */
+};
+
+#define N_GETMAGIC(ex) \
+ ( (((ex).a_midmag)&0xffff0000) ? (ntohl(((ex).a_midmag))&0xffff) : ((ex).a_midmag))
+
+#define ZMAGIC 0413 /* demand load format */
+
+#if 0
+typedef char *va_list;
+#define __va_promote(type) \
+ (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
+#define va_start(ap, last) \
+ (ap = ((char *)&(last) + __va_promote(last)))
+#define va_arg(ap, type) \
+ ((type *)(ap += sizeof(type) < sizeof(int) ? \
+ (abort(), 0) : sizeof(type)))[-1]
+#define va_end(ap)
+#else
+typedef char *va_list;
+#define va_start(ap, parmN) ((ap) = (char *)(&parmN + 1))
+#define va_arg(ap, type) ((ap) += sizeof(type), ((type *)(ap))[-1])
+#define va_end(ap)
+#endif
+
+#define RB_ASKNAME 0x01 /* ask for file name to reboot from */
+#define RB_SINGLE 0x02 /* reboot to single user only */
+#define RB_NOSYNC 0x04 /* dont sync before reboot */
+#define RB_HALT 0x08 /* don't reboot, just halt */
+#define RB_INITNAME 0x10 /* name given for /etc/init (unused) */
+#define RB_DFLTROOT 0x20 /* use compiled-in rootdev */
+#define RB_KDB 0x40 /* give control to kernel debugger */
+#define RB_RDONLY 0x80 /* mount root fs read-only */
+#define RB_DUMP 0x100 /* dump kernel memory before reboot */
+
+#endif /* __types_h_ */
diff --git a/sys/arch/i386/netboot/ne2100.c b/sys/arch/i386/netboot/ne2100.c
new file mode 100644
index 00000000000..3de6137ce68
--- /dev/null
+++ b/sys/arch/i386/netboot/ne2100.c
@@ -0,0 +1,328 @@
+/* $NetBSD: ne2100.c,v 1.3 1994/10/27 04:21:20 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * A very simple network driver for NE2100 boards that polls.
+ *
+ * Copyright (c) 1992 by Leendert van Doorn
+ */
+
+#include "assert.h"
+#include "nbtypes.h"
+#include "packet.h"
+#include "ether.h"
+#include "lance.h"
+#include "proto.h"
+
+/* configurable parameters */
+#define NE_BASEREG 0x300 /* base register */
+#define NE_DMACHANNEL 5 /* DMA channel */
+
+/* Lance register offsets */
+#define LA_CSR (NE_BASEREG+0x10)
+#define LA_CSR1 (NE_BASEREG+0x10)
+#define LA_CSR2 (NE_BASEREG+0x10)
+#define LA_CSR3 (NE_BASEREG+0x10)
+#define LA_RAP (NE_BASEREG+0x12)
+
+/*
+ * Some driver specific constants.
+ * Take care when tuning, this program only has 32 Kb
+ */
+#define LANCEBUFSIZE 1518 /* plus 4 CRC bytes */
+#define MAXLOOP 1000000L /* arbitrary retry limit */
+#define LOG2NRCVRING 2 /* log2(NRCVRING) */
+#define NRCVRING (1 << LOG2NRCVRING)
+
+u_char eth_myaddr[ETH_ADDRSIZE];
+
+static int next_rmd; /* next receive element */
+static initblock_t *initblock; /* initialization block */
+static tmde_t *tmd; /* transmit ring */
+static rmde_t *rmd; /* receive ring */
+static char rbuffer[NRCVRING][LANCEBUFSIZE]; /* receive buffers */
+
+static char *top = (char *)RAMSIZE;
+static char last;
+
+static char *
+aalloc(size, align)
+ int size, align;
+{
+ register char *p;
+ register int mask;
+
+ if (align == 0)
+ align = sizeof(int);
+ mask = align - 1;
+ assert((align & mask) == 0);
+ top = top - (size + align);
+ p = (char *)((int)top & ~mask);
+ assert(p > &last);
+ assert(p <= (char *) RAMSIZE);
+ return top = p;
+}
+
+/*
+ * Program DMA channel 'chan' for cascade mode
+ */
+static void
+dma_cascade(chan)
+ int chan;
+{
+ assert(chan >= 0);
+ assert(chan <= 7);
+ if (chan >= 0 && chan <= 3) {
+ outb(0x0B, 0xC0 | (chan & 03));
+ outb(0x0A, chan & 03);
+ } else {
+ outb(0xD6, 0xC0 | ((chan - 4) & 03));
+ outb(0xD4, (chan - 4) & 03);
+ }
+}
+
+/*
+ * Reset ethernet board (i.e. after a timeout)
+ */
+void
+EtherReset(void) {
+ long l;
+ u_long addr;
+ int i;
+
+ /* program DMA chip */
+ dma_cascade(NE_DMACHANNEL);
+
+ /* stop the chip, and make sure it did */
+ outw(LA_RAP, RDP_CSR0);
+ outw(LA_CSR, CSR_STOP);
+ for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) {
+ if (l >= MAXLOOP) {
+ printf("Lance failed to stop\n");
+ return;
+ }
+ }
+
+ /* fill lance initialization block */
+ bzero(initblock, sizeof(initblock_t));
+
+ /* set my ethernet address */
+ initblock->ib_padr[0] = eth_myaddr[0];
+ initblock->ib_padr[1] = eth_myaddr[1];
+ initblock->ib_padr[2] = eth_myaddr[2];
+ initblock->ib_padr[3] = eth_myaddr[3];
+ initblock->ib_padr[4] = eth_myaddr[4];
+ initblock->ib_padr[5] = eth_myaddr[5];
+
+ /* receive ring pointer */
+ addr = LA(rmd);
+ initblock->ib_rdralow = (u_short)addr;
+ initblock->ib_rdrahigh = (u_char)(addr >> 16);
+ initblock->ib_rlen = LOG2NRCVRING << 5;
+
+ /* transmit ring with one element */
+ addr = LA(tmd);
+ initblock->ib_tdralow = (u_short)addr;
+ initblock->ib_tdrahigh = (u_char)(addr >> 16);
+ initblock->ib_tlen = 0 << 5;
+
+ /* setup the receive ring entries */
+ for (next_rmd = 0, i = 0; i < NRCVRING; i++) {
+ addr = LA(&rbuffer[i]);
+ rmd[i].rmd_ladr = (u_short)addr;
+ rmd[i].rmd_hadr = (u_char)(addr >> 16);
+ rmd[i].rmd_mcnt = 0;
+ rmd[i].rmd_bcnt = -LANCEBUFSIZE;
+ rmd[i].rmd_flags = RMD_OWN;
+ }
+
+ /* zero transmit ring */
+ bzero(tmd, sizeof(tmde_t));
+
+ /* give lance the init block */
+ addr = LA(initblock);
+ outw(LA_RAP, RDP_CSR1);
+ outw(LA_CSR1, (u_short)addr);
+ outw(LA_RAP, RDP_CSR2);
+ outw(LA_CSR2, (char)(addr >> 16));
+ outw(LA_RAP, RDP_CSR3);
+ outw(LA_CSR3, 0);
+
+ /* and initialize it */
+ outw(LA_RAP, RDP_CSR0);
+ outw(LA_CSR, CSR_INIT|CSR_STRT);
+
+ /* wait for the lance to complete initialization and fire it up */
+ for (l = 0; (inw(LA_CSR) & CSR_IDON) == 0; l++) {
+ if (l >= MAXLOOP) {
+ printf("Lance failed to initialize\n");
+ break;
+ }
+ }
+ for (l=0; (inw(LA_CSR)&(CSR_TXON|CSR_RXON))!=(CSR_TXON|CSR_RXON); l++) {
+ if (l >= MAXLOOP) {
+ printf("Lance not started\n");
+ break;
+ }
+ }
+}
+
+/*
+ * Get ethernet address and compute checksum to be sure
+ * that there is a board at this address.
+ */
+int
+EtherInit()
+{
+ u_short checksum, sum;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ eth_myaddr[i] = inb(NE_BASEREG + i);
+
+ sum = 0;
+ for (i = 0x00; i <= 0x0B; i++)
+ sum += inb(NE_BASEREG + i);
+ for (i = 0x0E; i <= 0xF; i++)
+ sum += inb(NE_BASEREG + i);
+ checksum = inb(NE_BASEREG + 0x0C) | (inb(NE_BASEREG + 0x0D) << 8);
+ if (sum != checksum)
+ return 0;
+
+ /* initblock, tmd, and rmd should be 8 byte aligned ! */
+ initblock = (initblock_t *) aalloc(sizeof(initblock_t), 8);
+ tmd = (tmde_t *) aalloc(sizeof(tmde_t), 8);
+ rmd = (rmde_t *) aalloc(NRCVRING * sizeof(rmde_t), 8);
+ EtherReset();
+ return 1;
+}
+
+/*
+ * Disable DMA for channel 'chan'
+ */
+static void
+dma_done(chan)
+ int chan;
+{
+ assert(chan >= 0);
+ assert(chan <= 7);
+ if (chan >= 0 && chan <= 3)
+ outb(0x0A, 0x04 | (chan & 03));
+ else
+ outb(0xD4, 0x04 | ((chan - 4 ) & 03));
+}
+
+/*
+ * Stop ethernet board
+ */
+void
+EtherStop()
+{
+ long l;
+
+ /* stop chip and disable DMA access */
+ outw(LA_RAP, RDP_CSR0);
+ outw(LA_CSR, CSR_STOP);
+ for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) {
+ if (l >= MAXLOOP) {
+ printf("Lance failed to stop\n");
+ break;
+ }
+ }
+ dma_done(NE_DMACHANNEL);
+}
+
+/*
+ * Send an ethernet packet to destination 'dest'
+ */
+void
+EtherSend(pkt, proto, dest)
+ packet_t *pkt;
+ u_short proto;
+ u_char *dest;
+{
+ ethhdr_t *ep;
+ long l;
+ u_long addr;
+ u_short csr;
+
+ /* add ethernet header and fill in source & destination */
+ pkt->pkt_len += sizeof(ethhdr_t);
+ pkt->pkt_offset -= sizeof(ethhdr_t);
+ ep = (ethhdr_t *) pkt->pkt_offset;
+ ep->eth_proto = htons(proto);
+ bcopy(dest, ep->eth_dst, ETH_ADDRSIZE);
+ bcopy(eth_myaddr, ep->eth_src, ETH_ADDRSIZE);
+ if (pkt->pkt_len < 60)
+ pkt->pkt_len = 60;
+ assert(pkt->pkt_len <= 1514);
+
+ /* set up transmit ring element */
+ assert((tmd->tmd_flags & TMD_OWN) == 0);
+ addr = LA(pkt->pkt_offset);
+ assert((addr & 1) == 0);
+ tmd->tmd_ladr = (u_short)addr;
+ tmd->tmd_hadr = (u_char)(addr >> 16);
+ tmd->tmd_bcnt = -pkt->pkt_len;
+ tmd->tmd_err = 0;
+ tmd->tmd_flags = TMD_OWN|TMD_STP|TMD_ENP;
+
+ /* start transmission */
+ outw(LA_CSR, CSR_TDMD);
+
+ /* wait for interrupt and acknowledge it */
+ for (l = 0; l < MAXLOOP; l++) {
+ if ((csr = inw(LA_CSR)) & CSR_TINT) {
+ outw(LA_CSR, CSR_TINT);
+ break;
+ }
+ }
+}
+
+/*
+ * Poll the LANCE just see if there's an Ethernet packet
+ * available. If there is, its contents is returned in a
+ * pkt structure, otherwise a nil pointer is returned.
+ */
+packet_t *
+EtherReceive(void) {
+ packet_t *pkt;
+ rmde_t *rp;
+ u_long addr;
+ u_short csr;
+
+ pkt = (packet_t *)0;
+ if ((csr = inw(LA_CSR)) & CSR_RINT) {
+ outw(LA_CSR, CSR_RINT);
+ assert(next_rmd >= 0);
+ assert(next_rmd <= NRCVRING);
+ rp = &rmd[next_rmd];
+ if ((rp->rmd_flags & ~RMD_OFLO) == (RMD_STP|RMD_ENP)) {
+ pkt = PktAlloc(0);
+ pkt->pkt_len = rp->rmd_mcnt - 4;
+ assert(pkt->pkt_len >= 0);
+ assert(pkt->pkt_len < PKT_DATASIZE);
+ bcopy(rbuffer[next_rmd], pkt->pkt_offset, pkt->pkt_len);
+ /* give packet back to the lance */
+ rp->rmd_bcnt = -LANCEBUFSIZE;
+ rp->rmd_mcnt = 0;
+ rp->rmd_flags = RMD_OWN;
+ }
+ next_rmd = (next_rmd + 1) & (NRCVRING - 1);
+ }
+ return pkt;
+}
+
+/*
+ * Print an ethernet address in human readable form
+ */
+void
+EtherPrintAddr(addr)
+ u_char *addr;
+{
+ printf("%x:%x:%x:%x:%x:%x",
+ addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF,
+ addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF);
+}
diff --git a/sys/arch/i386/netboot/packet.c b/sys/arch/i386/netboot/packet.c
new file mode 100644
index 00000000000..a292f699f32
--- /dev/null
+++ b/sys/arch/i386/netboot/packet.c
@@ -0,0 +1,59 @@
+/* $NetBSD: packet.c,v 1.3 1994/10/27 04:21:21 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Packet allocation and deallocation routines.
+ *
+ * Copyright (c) 1992 by Leendert van Doorn
+ */
+
+#include "proto.h"
+#include "assert.h"
+#include "param.h"
+#include "packet.h"
+
+static packet_t *pool = (packet_t *)0;
+static packet_t *last;
+
+void
+PktInit(void) {
+ static packet_t s_pool[PKT_POOLSIZE];
+ pool = s_pool;
+ bzero((char *)pool, PKT_POOLSIZE * sizeof(packet_t));
+ last = pool;
+}
+
+packet_t *
+PktAlloc(u_long offset) {
+ int i;
+
+ for (i = 0; i < PKT_POOLSIZE; i++) {
+ if (last->pkt_used == FALSE) {
+ bzero((char *)last->pkt_data, PKT_DATASIZE);
+ last->pkt_used = TRUE;
+ last->pkt_len = 0;
+ last->pkt_offset = last->pkt_data + offset;
+#if 0
+printf("PktAlloc: used %x\n", last);
+#endif
+ return last;
+ }
+ if (++last == &pool[PKT_POOLSIZE])
+ last = pool;
+ }
+ printf("Pool out of free packets\n");
+ exit(1);
+ return 0; /* silence warnings */
+}
+
+void
+PktRelease(packet_t *pkt) {
+#if 0
+printf("PktAlloc: freed %x\n", pkt);
+#endif
+ assert(pkt >= &pool[0]);
+ assert(pkt < &pool[PKT_POOLSIZE]);
+ (last = pkt)->pkt_used = FALSE;
+}
diff --git a/sys/arch/i386/netboot/packet.h b/sys/arch/i386/netboot/packet.h
new file mode 100644
index 00000000000..74480965369
--- /dev/null
+++ b/sys/arch/i386/netboot/packet.h
@@ -0,0 +1,27 @@
+/* $NetBSD: packet.h,v 1.3 1994/10/27 04:21:22 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Packet layout definitions
+ */
+
+/* implementation constants */
+#define PKT_POOLSIZE 5
+#define PKT_DATASIZE 1514
+
+/*
+ * Structure of a packet.
+ * Each packet can hold exactly one ethernet message.
+ */
+typedef struct {
+ u_short pkt_used; /* whether this packet it used */
+ u_short pkt_len; /* length of data */
+ u_char *pkt_offset; /* current offset in data */
+ u_char pkt_data[PKT_DATASIZE]; /* packet data */
+} packet_t;
+
+void PktInit(void);
+packet_t *PktAlloc(u_long);
+void PktRelease(packet_t *);
diff --git a/sys/arch/i386/netboot/param.h b/sys/arch/i386/netboot/param.h
new file mode 100644
index 00000000000..de2b454dfbb
--- /dev/null
+++ b/sys/arch/i386/netboot/param.h
@@ -0,0 +1,26 @@
+/* $NetBSD: param.h,v 1.3 1994/10/27 04:21:23 cgd Exp $ */
+
+/*
+ * Tunable parameters
+ */
+
+/*
+ * RARP as well as TFTP uses a timeout mechanism which starts with four
+ * seconds and eventually go up as high as 4 << NRETRIES seconds. That
+ * is, the number of retry iterations.
+ */
+#define NRETRIES 6
+
+#ifdef MONITOR
+/*
+ * BIOS break interrupt. This interrupt is generated by the
+ * keyboard driver every time CTRL BREAK is pressed. We pick
+ * it up to jump into the monitor.
+ */
+#define BRK_INTR 0x1B
+
+/*
+ * Number of arguments in the users' command line
+ */
+#define ARGVECSIZE 5
+#endif /* MONITOR */
diff --git a/sys/arch/i386/netboot/proto.h b/sys/arch/i386/netboot/proto.h
new file mode 100644
index 00000000000..381f0c487a6
--- /dev/null
+++ b/sys/arch/i386/netboot/proto.h
@@ -0,0 +1,146 @@
+/* $NetBSD: proto.h,v 1.3 1994/10/27 04:21:24 cgd Exp $ */
+
+/*
+ * TBD - need for common typedefs - rethink?
+ * TBD - move config include into the source files - this is just expedient
+ */
+
+#include "config.h"
+#include "nbtypes.h"
+
+#define TRUE 1
+#define FALSE 0
+#define MDUMP 100 /* TBD - remove */
+#define MAX_FILE_NAME_LEN 128
+#define CRTBASE ((char *)0xb8000)
+#define CHECKPOINT(x) (CRTBASE[0] = x)
+#define nelt(x) (sizeof(x)/sizeof((x)[0]))
+
+void ENTER(char *); /* remove TBD */
+int IsKbdCharReady(void);
+u_char GetKbdChar(void);
+void HandleKbdAttn(void);
+void KbdWait(int n);
+
+int bcmp(const void *, const void *, int);
+void volatile exit(int);
+void volatile ExitToBios(void);
+void gateA20(void);
+int getc(void);
+int getchar(void);
+u_short GetMemSize(u_short);
+int gets(char *);
+int ischar(void);
+void longjmp(jmp_buf env, int val);
+void printf( /* const char *, ... */ );
+void putc(int);
+void putchar(int);
+int rand(void);
+void ResetCpu(void);
+int setjmp(jmp_buf env);
+void srand(u_int);
+void StartProg(u_long phyaddr, u_long *args);
+int strlen(const char *);
+char *strncat(char *, const char *, int len);
+char *strncpy(char *, const char *, int len);
+int strcmp(const char *, const char *);
+u_long timer(void);
+
+/* macros in pio.h, rewritten as in-line functions */
+/* TBD - define addr arg as long - short might result in extra
+bit masking whereas longs simply get plonked down in %edx */
+#undef inb
+#undef outb
+#undef inw
+#undef outw
+#undef inl
+#undef outl
+
+static inline u_char
+inb(u_short addr) {
+ u_char datum;
+ asm volatile("inb %1, %0" : "=a" (datum) : "d" (addr));
+ return datum;
+}
+
+static inline void
+outb(u_short addr, u_char datum) {
+ asm volatile("outb %0, %1" : : "a" (datum), "d" (addr));
+}
+
+static inline u_short
+inw(u_short addr) {
+ u_short datum;
+ asm volatile(".byte 0x66; inl %1, %0" : "=a" (datum) : "d" (addr));
+ return datum;
+}
+
+static inline void
+outw(u_short addr, u_short datum) {
+ asm volatile(".byte 0x66; outw %0, %1" : : "a" (datum), "d" (addr));
+}
+
+static inline u_long
+inl(u_short addr) {
+ u_long datum;
+ asm volatile("inw %1, %0" : "=a" (datum) : "d" (addr));
+ return datum;
+}
+
+static inline void
+outl(u_short addr, u_long datum) {
+ asm volatile("outw %0, %1" : : "a" (datum), "d" (addr));
+}
+
+#if __GCC__ >= 2
+/* fast versions of bcopy(), bzero() */
+static inline void
+bcopy(const void *from, void *to, int len) {
+ /* assumes %es == %ds */
+ asm("
+ mov %0, %%esi
+ mov %1, %%edi
+ mov %2, %%ecx
+ cld
+ rep
+ movsb
+ " : : "g" (from), "g" (to), "g" (len) : "esi", "edi", "ecx");
+}
+
+static inline void
+bzero(void *dest, int len) {
+ /* assumes %es == %ds */
+ asm("
+ mov %0, %%edi
+ mov %1, %%ecx
+ xor %%eax, %%eax
+ cld
+ rep
+ stosb
+ " : : "g" (dest), "g" (len) : "edi", "ecx", "eax");
+}
+#else
+
+static inline void
+bcopy(char *from, char *to, int len)
+{
+ while (len-- > 0)
+ *to++ = *from++;
+}
+
+static inline void
+bzero(char *to, int len)
+{
+ while (len-- > 0)
+ *to++ = '\0';
+}
+
+#endif
+
+static inline void PhysBcopy(u_long src, u_long dest, u_long nbytes) {
+ bcopy((void *)src, (void *)dest, nbytes);
+}
+
+static inline void PhysBzero(u_long dest, u_long nbytes) {
+ bzero((void *)dest, nbytes);
+}
diff --git a/sys/arch/i386/netboot/start.s b/sys/arch/i386/netboot/start.s
new file mode 100644
index 00000000000..0bc14e124d9
--- /dev/null
+++ b/sys/arch/i386/netboot/start.s
@@ -0,0 +1,292 @@
+/* $NetBSD: start.s,v 1.4 1994/10/27 04:21:25 cgd Exp $ */
+
+#include "asm.h"
+
+/* At entry, the processor is in 16 bit real mode and the code is being
+ * executed from an address it was not linked to. Code must be pic and
+ * 32 bit sensitive until things are fixed up.
+ */
+
+ .word 0xaa55 /* bios extension signature */
+ .byte 0 /* no. of 512B blocks */
+ jmp 1f /* enter from bios here */
+ .byte 0 /* checksum */
+ENTRY(start)
+1:
+ cli
+ # save the bios return address in these registers until protected
+ # mode %ds is set up
+ # mov (%esp), %edx
+ # mov 2(%esp), %ebp
+ pop %dx /* return offset */
+ pop %ebp /* return segment */
+
+ /* save stack [, data] context in case we are under dos */
+ mov %esp, %ecx
+ mov %ss, %ax
+ mov %eax, %ebx
+
+ /* set up a usable stack */
+ .byte 0xb8 /* (mov $0xa000, %ax) */
+ .word 0xa000
+ mov %ax, %ss
+ xor %esp, %esp
+
+ push %ebp /* return segment */
+ push %dx /* return offset */
+ push %ds
+
+#if 0
+ jmp ret16
+#endif
+
+
+#ifdef CHECK_386
+ # check if 386 or later
+ # from Intel i486 programmer\'s reference manual, section 22.10
+ # Care must be taken with the first few instructions to ensure
+ # operations are compatible with 386 progenitors - no operand
+ # or address size overrides, all operations must be 16 bit.
+ # Real mode not well supported by gas so it looks a bit crufty
+
+ # TBD - there is little stack space, although the routine below
+ # uses only two bytes; might set up new stack first thing, then
+ # check processor type - would mean carrying sp, ss in two gp
+ # registers for a while. also make alternate provisions for saving
+ # ds: below.
+
+ pushf
+ pop %ebx
+ .byte 0x81, 0xe3 /* (and 0x0fff, %ebx) */
+ .word 0x0fff
+ push %ebx
+ popf
+ pushf
+ pop %eax
+ .byte 0x25 /* (and 0xf000, %eax) */
+ .word 0xf000
+ .byte 0x3d /* (cmp 0xf000, %eax) */
+ .word 0xf000
+ jz Lwrong_cpu /* \'86 */
+ .byte 0x81, 0xcb /* (or 0xf000, %ebx) */
+ .word 0xf000
+ push %ebx
+ popf
+ pushf
+ pop %eax
+ .byte 0x25 /* (and 0xf000, %eax) */
+ .word 0xf000
+ jnz Lcpu_ok /* else is \'286 */
+
+Lwrong_cpu:
+ .byte 0xbb /* (mov bad_cpu_msg, %ebx) */
+ .word bad_cpu_msg
+ .byte 0xe8 /* (call xputs) */
+ .word xputs-.-2
+ lret
+
+xputc: /* print byte in %al */
+ data32
+ pusha
+ .byte 0xbb /* (mov $0x1, %ebx) %bh=0, %bl=1 (blue) */
+ .word 0x0001
+ movb $0xe, %ah
+ # sti
+ int $0x10 /* display a byte */
+ # cli
+ data32
+ popa
+ ret
+
+xputs: /* print string pointed to by cs:bx */
+ data32
+ pusha
+1:
+ cs
+ .byte 0x8a, 0x07 /* (mov (%ebx), %al) */
+ cmpb $0, %al
+ jz 1f
+ push %ebx
+ .byte 0xe8 /* (call xputc) */
+ .word xputc-.-2
+ pop %ebx
+ inc %ebx
+ jmp 1b
+1:
+ data32
+ popa
+ ret
+
+bad_cpu_msg: .asciz "netboot: cpu cannot execute '386 instructions, net boot not done.\n\r"
+
+Lcpu_ok:
+ # at this point it is known this can execute 386 instructions
+ # so operand and address size prefixes are ok
+#endif /* CHECK_386 */
+
+ /* copy rom to link addr, prepare for relocation */
+ xor %esi, %esi /* source */
+ opsize
+ mov $0, %edi /* destination */
+ opsize
+ mov $(RELOC)>>4, %eax
+ mov %ax, %es
+ opsize
+ mov $(ROM_SIZE), %ecx /* count */
+ cs
+ rep
+ movsb
+
+ addrsize
+ cs
+ lgdt gdtarg-RELOC
+
+ /* turn on protected mode */
+ cli
+ mov %cr0, %eax
+ opsize
+ or $CR0_PE, %eax
+ mov %eax, %cr0
+
+ /* jump to relocation, flush prefetch queue, and reload %cs */
+ opsize
+ ljmp $KERN_CODE_SEG, $1f
+1:
+ /* reload other segment registers */
+ movl $KERN_DATA_SEG, %eax
+ movl %ax, %ds
+ movl %ax, %es
+ movl %ax, %ss
+ movl $0xa0000, %esp
+ call _main
+ call _exit
+
+_ExitToBios:
+ .globl _ExitToBios
+ /* set up a dummy stack frame for the second seg change. */
+ mov $(RELOC)>>4, %eax
+ pushw %ax /* real cs */
+ pushw $2f /* real pc */
+
+ /* Change to use16 mode. */
+ ljmp $BOOT_16_SEG, $1f /* jump to a 16 bit segment */
+1:
+ /* clear the PE bit of CR0 */
+ mov %cr0, %eax
+ opsize
+ and $0!CR0_PE, %eax
+ mov %eax, %cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * using the fake stack frame set up earlier
+ * and reload CS register
+ */
+ lret
+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, %ss
+ movw %ax, %es
+
+ret16: /* temporary label - remove (TBD) */
+ /* now in dumbed down mode, caveats */
+ /* restore old context and return to whatever called us */
+ pop %ds
+ pop %dx
+ pop %ebp
+
+ mov %ebx, %eax
+ mov %ax, %ss
+ mov %ecx, %esp
+
+ push %ebp
+ push %dx
+ sti
+ lret
+
+#ifdef USE_BIOS
+_real_to_prot:
+ .global _real_to_prot
+
+ addrsize
+ cs
+ lgdt gdtarg-RELOC
+ cli
+ mov %cr0, %eax
+ opsize
+ or $CR0_PE, %eax
+ mov %eax, %cr0
+
+ /* jump to relocation, flush prefetch queue, and reload %cs */
+ opsize
+ ljmp $KERN_CODE_SEG, $1f
+1:
+ movl $KERN_DATA_SEG, %eax
+ movl %ax, %ds
+ movl %ax, %es
+ movl %ax, %ss
+
+ ret
+#endif
+
+#ifdef USE_BIOS
+_prot_to_real:
+ .global _prot_to_real
+
+ /* set up a dummy stack frame for the second seg change. */
+ movl $(RELOC), %eax
+ sarl $4, %eax
+ pushw %ax /* real cs */
+ pushw $2f /* real pc */
+
+ /* Change to use16 mode. */
+ ljmp $BOOT_16_SEG, $1f /* jump to a 16 bit segment */
+1:
+ /* clear the PE bit of CR0 */
+ mov %cr0, %eax
+ opsize
+ and $0!CR0_PE, %eax
+ mov %eax, %cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * using the fake stack frame set up earlier
+ * and reload CS register
+ */
+ lret
+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, %ss
+ movw %ax, %es
+
+ opsize
+ ret
+#endif
+
+ .align 4
+gdt:
+ .word 0, 0
+ .byte 0, 0x00, 0x00, 0
+
+ /* code segment */
+ .word 0xffff, 0
+ .byte 0, 0x9f, 0xcf, 0
+
+ /* data segment */
+ .word 0xffff, 0
+ .byte 0, 0x93, 0xcf, 0
+
+ /* 16 bit real mode */
+ .word 0xffff, 0
+ .byte 0, 0x9e, 0x00, 0
+
+ .align 4
+gdtarg:
+ .word 0x1f /* limit */
+ .long gdt /* addr */
diff --git a/sys/arch/i386/netboot/tftp.c b/sys/arch/i386/netboot/tftp.c
new file mode 100644
index 00000000000..6725080aa5a
--- /dev/null
+++ b/sys/arch/i386/netboot/tftp.c
@@ -0,0 +1,484 @@
+/* $NetBSD: tftp.c,v 1.3 1994/10/27 04:21:26 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Trivial File Transfer Protocol (see RFC 783).
+ *
+ * Copyright (c) 1992 by Leendert van Doorn
+ */
+
+#include "proto.h"
+#include "assert.h"
+#include "param.h"
+#include "packet.h"
+#include "ether.h"
+#include "inet.h"
+#include "tftp.h"
+#include "arp.h"
+
+ipaddr_t tftp_server; /* IP address of TFTP server */
+ipaddr_t tftp_gateway;
+static char tftp_file_name[100];
+static short block; /* current block */
+static int ctid, stid; /* UDP client and server TID (network order) */
+
+extern u_long work_area_org;
+
+/*
+ * Print IP address in a readable form
+ */
+void
+IpPrintAddr(ipaddr_t addr) {
+ inetaddr_t ip;
+
+ ip.a = addr;
+ printf("%d.%d.%d.%d", ip.s.a0, ip.s.a1, ip.s.a2, ip.s.a3);
+}
+
+/*
+ * Generic TFTP error routine
+ */
+static void
+TftpFail(ipaddr_t fromaddr, ipaddr_t toaddr, char *filename, char *reason) {
+ printf("Tftp of file '%s' from ", filename);
+ IpPrintAddr(fromaddr);
+ printf(" failed, %s\n", reason);
+}
+
+/*
+ * One complement check sum
+ */
+static u_short
+InChecksum(char *cp, u_long count) {
+ u_short *sp;
+ u_long sum, oneword = 0x00010000;
+
+ for (sum = 0, sp = (u_short *)cp, count >>= 1; count--; ) {
+ sum += *sp++;
+ if (sum >= oneword) {
+ /* wrap carry into low bit */
+ sum -= oneword;
+ sum++;
+ }
+ }
+ return ~sum;
+}
+
+/*
+ * Setup the standard IP header fields for a destination,
+ * and send packet (possibly using the gateway).
+ */
+void
+IpSend(packet_t *pkt, ipaddr_t dst, ipaddr_t gateway) {
+ iphdr_t *ip;
+ u_char edst[ETH_ADDRSIZE];
+ static int ipid = 0;
+#if TRACE > 0
+DUMP_STRUCT("IpSend: pkt (front)", pkt, 100);
+#endif
+ pkt->pkt_offset -= sizeof(iphdr_t);
+ pkt->pkt_len += sizeof(iphdr_t);
+ ip = (iphdr_t *) pkt->pkt_offset;
+ ip->ip_vhl = (IP_VERSION << 4) | (sizeof(*ip) >> 2);
+ ip->ip_tos = 0;
+ ip->ip_len = htons(pkt->pkt_len);
+ ip->ip_id = ipid++;
+ ip->ip_off = 0;
+ ip->ip_ttl = IP_FRAGTTL;
+ ip->ip_p = IP_PROTO_UDP;
+ ip->ip_src = ip_myaddr ? ip_myaddr : IP_ANYADDR;
+ ip->ip_dst = dst;
+ ip->ip_sum = 0;
+ ip->ip_sum = InChecksum((char *)ip, sizeof(*ip));
+#if 0
+/* DUMP_STRUCT("pkt (after)", pkt, 100); */
+DUMP_STRUCT("ip", ip, sizeof(iphdr_t)+pkt->pkt_len);
+#endif
+ if (ArpResolve(pkt, gateway ? gateway : dst, edst)) {
+ EtherSend(pkt, ETHTYPE_IP, edst);
+ PktRelease(pkt);
+ }
+}
+
+/*
+ * States which TFTP can be in
+ */
+enum TftpPacketStatus {
+ TFTP_RECD_GOOD_PACKET,
+ TFTP_RECD_BAD_PACKET,
+ TFTP_RECD_SERVER_ABORT,
+};
+
+/*
+ * Pseudo header to compute UDP checksum
+ */
+struct pseudoheader {
+ ipaddr_t ph_src;
+ ipaddr_t ph_dst;
+ u_char ph_zero;
+ u_char ph_prot;
+ u_short ph_length;
+};
+
+/*
+ * Determine whether this IP packet is the TFTP data packet
+ * we were expecting. When a broadcast TFTP request was made
+ * we'll set the TFTP server address as well.
+ */
+static enum TftpPacketStatus
+TftpDigestPacket(packet_t *pkt, char *rbuf, u_long *rlen) {
+ iphdr_t *ip;
+ udphdr_t *up;
+ tftphdr_t *tp;
+ struct pseudoheader ph;
+ u_short oldsum, sum;
+ u_short udplength;
+
+ /* check for minimum size tftp packet */
+ if (pkt->pkt_len < (sizeof(ethhdr_t) + sizeof(iphdr_t) +
+ sizeof(udphdr_t) + sizeof(tftphdr_t))) {
+#if 0
+ printe("TftpDigestPacket: bad packet size %d\n", pkt->pkt_len);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ /* IP related checks */
+ ip = (iphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
+ if (tftp_server != IP_BCASTADDR && ip->ip_src != tftp_server) {
+#if 0
+ printe("TftpDigestPacket: incorrect ip source address 0x%x\n", ip->ip_src);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+ if (ntohs(ip->ip_len) <
+ sizeof(iphdr_t) + sizeof(udphdr_t) + sizeof(tftphdr_t)) {
+#if 0
+ printe("TftpDigestPacket: bad ip length %d\n", ip->ip_len);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+ if (ip->ip_p != IP_PROTO_UDP) {
+#if 0
+ printe("TftpDigestPacket: wrong ip protocol type 0x%x\n", ip->ip_p);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+ if (ip_myaddr && ip->ip_dst != ip_myaddr) {
+#if 0
+ printe("TftpDigestPacket: incorrect ip destination address %x\n", ip->ip_dst);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ /* UDP related checks */
+ up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t));
+ if (block && up->uh_sport != stid) {
+#if 0
+ printe("TftpDigestPacket: wrong udp source port 0x%x\n", up->uh_sport);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+ *rlen = ntohs(up->uh_len) - sizeof(udphdr_t) - sizeof(tftphdr_t);
+ if (up->uh_dport != ctid) {
+#if 0
+ printe("TftpDigestPacket: wrong udp destination port 0x%x\n", up->uh_dport);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ /* compute UDP checksum if any */
+ oldsum = up->uh_sum;
+ if (oldsum) {
+ udplength = ntohs(up->uh_len);
+ /*
+ * zero the byte past the last data byte because the
+ * checksum will be over an even number of bytes.
+ */
+ if (udplength & 01)
+ ((char *)up)[udplength] = '\0';
+
+ /* set up the pseudo-header */
+ ph.ph_src = ip->ip_src;
+ ph.ph_dst = ip->ip_dst;
+ ph.ph_zero = 0;
+ ph.ph_prot = ip->ip_p;
+ ph.ph_length = htons(udplength);
+
+ up->uh_sum = ~InChecksum((char *)&ph, sizeof(ph));
+ sum = InChecksum((char *)up, (u_long)((udplength + 1) & ~1));
+ up->uh_sum = oldsum; /* put original back */
+ if (oldsum == (u_short) -1)
+ oldsum = 0;
+ if (sum != oldsum) {
+#if 0
+ printe("TftpDigestPacket: Bad checksum %x != %x, length %d from ",
+ sum, oldsum, udplength);
+ IpPrintAddr(ip->ip_src);
+ printe("\n");
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+ }
+
+ /* TFTP related checks */
+ tp = (tftphdr_t *) ((char *)up + sizeof(udphdr_t));
+ switch (ntohs(tp->th_op)) {
+ case TFTP_ERROR:
+ printf("Diagnostic from server: error #%d, %s\n",
+ ntohs(tp->th_code), &tp->th_msg);
+ return TFTP_RECD_SERVER_ABORT;
+ case TFTP_DATA:
+ break;
+ default:
+#if 0
+ printe("TftpDigestPacket: incorrect tftp packet type 0x%x\n", tp->th_op);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ /* reject old packets */
+ if (ntohs(tp->th_block) != block + 1) {
+#if 0
+ printe("TftpDigestPacket: bad block no. %d\n", tp->th_block);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ /* some TFTP related check */
+ if (block == 0) {
+ stid = up->uh_sport;
+ /* in case of a broadcast, remember server address */
+ if (tftp_server == IP_BCASTADDR) {
+ tftp_server = ip->ip_src;
+#if 0
+ printe("Found TFTP server at ");
+ IpPrintAddr(tftp_server);
+ printe("\n");
+#endif
+ }
+ }
+ if (stid != up->uh_sport) {
+#if 0
+ printe("TftpDigestPacket: incorrect udp source port 0x%x\n", up->uh_sport);
+#endif
+ return TFTP_RECD_BAD_PACKET;
+ }
+
+ bcopy(&tp->th_data, rbuf, *rlen);
+
+ /* advance to next block */
+ block++;
+ return TFTP_RECD_GOOD_PACKET;
+}
+
+enum TftpStatus {
+ TFTP_SUCCESS,
+ TFTP_FAILURE,
+};
+
+static enum TftpStatus
+Tftp(char *rbuf, u_long *rlen) {
+ u_long time, current, timeout;
+ int retry, quit;
+ enum TftpStatus rc = TFTP_FAILURE;
+
+ *rlen = 0;
+ timeout = 4; /* four seconds */
+ for (retry=0, quit=0; ++retry < NRETRIES && !quit; ) {
+ /*
+ * Send out a TFTP request. On the first block (actually
+ * zero) we send out a read request. Every other block we
+ * just acknowledge.
+ */
+ packet_t *pkt;
+ ethhdr_t *ep;
+ udphdr_t *up;
+ tftphdr_t *tp;
+#if TRACE > 0
+printe("Tftp: block %d, try #%d\n", block, retry);
+#endif
+ pkt = PktAlloc(sizeof(ethhdr_t) + sizeof(iphdr_t));
+ up = (udphdr_t *) pkt->pkt_offset;
+ tp = (tftphdr_t *) (pkt->pkt_offset + sizeof(udphdr_t));
+ if (block == 0) { /* <RRQ> | <filename> | 0 | "octet" | 0 */
+ char *cp, *p;
+
+ tp->th_op = htons(TFTP_RRQ);
+ cp = tp->th_stuff;
+ for (p = tftp_file_name; *p; )
+ *cp++ = *p++;
+ *cp++ = '\0';
+ *cp++ = 'o';
+ *cp++ = 'c';
+ *cp++ = 't';
+ *cp++ = 'e';
+ *cp++ = 't';
+ *cp++ = '\0';
+ pkt->pkt_len = sizeof(udphdr_t) + (cp - (char *)tp);
+ } else { /* else <ACK> | <block> */
+ tp->th_op = htons(TFTP_ACK);
+ tp->th_block = htons(block);
+#if 0
+printe("ack block %x %x\n", tp->th_block, block);
+#endif
+ pkt->pkt_len = sizeof(udphdr_t) + sizeof(tftphdr_t);
+ }
+ up->uh_sport = ctid;
+ up->uh_dport = stid;
+ up->uh_sum = 0;
+ up->uh_len = htons(pkt->pkt_len);
+#if 0
+DUMP_STRUCT("tftphdr_t", tp, sizeof(tftphdr_t));
+DUMP_STRUCT("udphdr_t", up, sizeof(udphdr_t));
+printe("Tftp: ");
+#endif
+ IpSend(pkt, tftp_server, tftp_gateway);
+
+ /*
+ * Receive TFTP data or ARP packets
+ */
+ time = timer() + timeout;
+ do {
+ pkt = EtherReceive();
+ if (pkt) {
+ static int spin = 0;
+ ep = (ethhdr_t *) pkt->pkt_offset;
+#if 0
+DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t));
+#endif
+ switch (ntohs(ep->eth_proto)) {
+ case ETHTYPE_ARP:
+ ArpInput(pkt);
+ break;
+ case ETHTYPE_IP:
+ switch (TftpDigestPacket(pkt, rbuf, rlen)) {
+ case TFTP_RECD_GOOD_PACKET:
+ if (block % 8 == 0)
+ printf("%c\b", "-\\|/"[spin++ % 4]);
+#if 0
+DUMP_STRUCT("good tftp packet", pkt, 100);
+printe("TBD - copy tftp packet #%d, len %d to buffer\n", block, *rlen);
+#endif
+ rc = TFTP_SUCCESS;
+ quit = 1;
+ break;
+ case TFTP_RECD_SERVER_ABORT:
+ TftpFail(tftp_server, ip_myaddr, tftp_file_name, "aborted by server");
+
+ rc = TFTP_FAILURE;
+ quit = 1;
+ break;
+ default:
+ /* for anything else, retry */
+#if 0
+printe("Tftp: bogus IP packet rec'd, still waiting\n");
+#endif
+ break;
+ }
+ break;
+ default:
+#if 0
+printe("Tftp: undesired ethernet packet (type 0x%x) rec'd, still waiting\n",
+ ep->eth_proto);
+#endif
+ break;
+ }
+ PktRelease(pkt);
+ }
+ current = timer();
+ HandleKbdAttn();
+ } while (current < time && !quit);
+
+#if 0
+/* TBD - move */
+ eth_reset();
+#endif
+
+ if (current >= time)
+ timeout <<= 1;
+ }
+
+ if (retry > NRETRIES) {
+ TftpFail(tftp_server, ip_myaddr, tftp_file_name, "timed Out");
+ }
+ return rc;
+}
+
+static int tftp_at_eof = 1;
+static u_long tftp_unread_bytes_in_buffer = 0;
+
+void
+SetTftpParms(ipaddr_t server, ipaddr_t gateway, char *file_name) {
+ block = 0;
+ strncpy(tftp_file_name, file_name, MAX_FILE_NAME_LEN);
+ tftp_server = server;
+ tftp_at_eof = 0;
+ tftp_unread_bytes_in_buffer = 0;
+ stid = htons(IP_PORT_TFTP);
+ ctid = htons(rand());
+ printf("Attempting to tftp file '%s'", tftp_file_name);
+ if (tftp_server != IP_BCASTADDR) {
+ printf(" from server ");
+ IpPrintAddr(tftp_server);
+ } else
+ printf(" using IP broadcast");
+ tftp_gateway = gateway;
+ if (tftp_gateway) {
+ printf(" using gateway ");
+ IpPrintAddr(tftp_gateway);
+ }
+ printf("\n");
+}
+
+u_long
+Read(void *result, u_long n_req) {
+ static u_long bufp = 0;
+ static char buf[PKT_DATASIZE];
+ u_long length;
+ u_long n_recd = 0;
+ while (n_req && !tftp_at_eof) {
+ if (tftp_unread_bytes_in_buffer) {
+ *((char *)result)++ = buf[bufp++];
+ n_req--;
+ n_recd++;
+ tftp_unread_bytes_in_buffer--;
+ } else {
+ switch (Tftp(buf, &length)) {
+ case TFTP_SUCCESS:
+ tftp_unread_bytes_in_buffer = length;
+ bufp = 0;
+ if (length < SEGSIZE)
+ tftp_at_eof = 1;
+ break;
+ default:
+ /* anything else should cause this to abend */
+ tftp_unread_bytes_in_buffer = 0;
+ tftp_at_eof = 1;
+ break;
+ }
+ }
+ }
+ return n_recd;
+}
+
+u_long
+PhysRead(u_long addr, u_long n_req) {
+ u_long n_recd = 0;
+ while (n_req) {
+ char buf[512];
+ u_long nd = n_req<sizeof(buf) ? n_req : sizeof(buf);
+ u_long nr = Read(buf, nd);
+ if (nr == 0) {
+ /* problem, incomplete read */
+ break;
+ }
+ PhysBcopy(LA(buf), addr, nr);
+ n_req -= nr;
+ n_recd += nr;
+ addr += nr;
+ }
+ return n_recd;
+}
diff --git a/sys/arch/i386/netboot/tftp.h b/sys/arch/i386/netboot/tftp.h
new file mode 100644
index 00000000000..6abba940325
--- /dev/null
+++ b/sys/arch/i386/netboot/tftp.h
@@ -0,0 +1,43 @@
+/* $NetBSD: tftp.h,v 1.3 1994/10/27 04:21:27 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * Trivial File Transfer Protocol (see RFC 783)
+ */
+
+#define SEGSIZE 512 /* data segment size */
+
+/*
+ * Packet types
+ */
+#define TFTP_RRQ 01 /* read request */
+#define TFTP_WRQ 02 /* write request */
+#define TFTP_DATA 03 /* data packet */
+#define TFTP_ACK 04 /* acknowledgement */
+#define TFTP_ERROR 05 /* error code */
+
+/*
+ * TFTP header structure
+ */
+typedef struct {
+ u_short th_op; /* packet type */
+ union {
+ u_short tu_block; /* block # */
+ u_short tu_code; /* error code */
+ char tu_stuff[1]; /* request packet stuff */
+ } th_u;
+} tftphdr_t;
+
+/* for ease of reference */
+#define th_block th_u.tu_block
+#define th_code th_u.tu_code
+#define th_stuff th_u.tu_stuff
+#define th_data th_stuff[2]
+#define th_msg th_data
+
+void SetTftpParms(ipaddr_t server, ipaddr_t gateway, char *file_name);
+u_long Read(void *result, u_long nbytes);
+u_long PhysRead(u_long addr, u_long nbytes);
+void IpSend(packet_t *pkt, ipaddr_t dst, ipaddr_t gateway);
diff --git a/sys/arch/i386/netboot/wd80x3.c b/sys/arch/i386/netboot/wd80x3.c
new file mode 100644
index 00000000000..3c4fe8b6b66
--- /dev/null
+++ b/sys/arch/i386/netboot/wd80x3.c
@@ -0,0 +1,432 @@
+/* $NetBSD: wd80x3.c,v 1.4 1994/10/27 04:21:28 cgd Exp $ */
+
+/*
+ * source in this file came from
+ * the Mach ethernet boot written by Leendert van Doorn.
+ *
+ * A very simple network driver for WD80x3 boards that polls.
+ *
+ * Copyright (c) 1992 by Leendert van Doorn
+ */
+
+#include "proto.h"
+#include "assert.h"
+#include "packet.h"
+#include "ether.h"
+#include "dp8390.h"
+
+/* configurable parameters */
+#define WD_BASEREG 0x280 /* base register */
+/* the base address doesn't have to be particularly accurate - the
+ board seems to pick up on addresses in the range a0000..effff.
+ */
+#define WD_BASEMEM 0xd0000 /* base ram */
+
+/* bit definitions for board features */
+#define INTERFACE_CHIP 01 /* has an WD83C583 interface chip */
+#define BOARD_16BIT 02 /* 16 bit board */
+#define SLOT_16BIT 04 /* 16 bit slot */
+
+/* register offset definitions */
+#define WD_MSR 0x00 /* control (w) and status (r) */
+#define WD_REG0 0x00 /* generic register definitions */
+#define WD_REG1 0x01
+#define WD_REG2 0x02
+#define WD_REG3 0x03
+#define WD_REG4 0x04
+#define WD_REG5 0x05
+#define WD_REG6 0x06
+#define WD_REG7 0x07
+#define WD_EA0 0x08 /* most significant addr byte */
+#define WD_EA1 0x09
+#define WD_EA2 0x0A
+#define WD_EA3 0x0B
+#define WD_EA4 0x0C
+#define WD_EA5 0x0D /* least significant addr byte */
+#define WD_LTB 0x0E /* LAN type byte */
+#define WD_CHKSUM 0x0F /* sum from WD_EA0 upto here is 0xFF */
+#define WD_DP8390 0x10 /* natsemi chip */
+
+/* bits in control register */
+#define WD_MSR_MEMMASK 0x3F /* memory enable bits mask */
+#define WD_MSR_MENABLE 0x40 /* memory enable */
+#define WD_MSR_RESET 0x80 /* software reset */
+
+/* bits in bus size register */
+#define WD_BSR_16BIT 0x01 /* 16 bit bus */
+
+/* bits in LA address register */
+#define WD_LAAR_A19 0x01 /* address lines for above 1Mb ram */
+#define WD_LAAR_LAN16E 0x40 /* enables 16bit shrd RAM for LAN */
+#define WD_LAAR_MEM16E 0x80 /* enables 16bit shrd RAM for host */
+
+u_char eth_myaddr[ETH_ADDRSIZE];
+
+static int boardid;
+static dpconf_t dpc;
+
+/*
+ * Determine whether wd8003 hardware performs register aliasing
+ * (i.e. whether it is an old WD8003E board).
+ */
+static int
+Aliasing(void) {
+ if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1))
+ return 0;
+ if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2))
+ return 0;
+ if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3))
+ return 0;
+ if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4))
+ return 0;
+ if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM))
+ return 0;
+ return 1;
+}
+
+/*
+ * This trick is stolen from the clarkson packet driver
+TBD - this is _ugly_ bogus! should use system timer
+ */
+static void
+LongPause(void) {
+ short i;
+ for (i = 1600; i > 0; i++)
+ (void) inb(0x61);
+}
+
+/*
+ * Determine whether this board has 16-bit capabilities
+ */
+static int
+BoardIs16Bit(void) {
+ u_char bsreg = inb(WD_BASEREG + WD_REG1);
+
+ outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT);
+ LongPause();
+ if (inb(WD_BASEREG + WD_REG1) == bsreg) {
+ /*
+ * Pure magic: LTB is 0x05 indicates that this is a WD8013EB board,
+ * 0x27 indicates that this is an WD8013 Elite board, and 0x29
+ * indicates an SMC Elite 16 board.
+ */
+ u_char tlb = inb(WD_BASEREG + WD_LTB);
+ return tlb == 0x05 || tlb == 0x27 || tlb == 0x29;
+ }
+ outb(WD_BASEREG + WD_REG1, bsreg);
+ return 1;
+}
+
+/*
+ * Determine whether the 16 bit capable board is plugged
+ * into a 16 bit slot.
+ */
+static int
+SlotIs16Bit(void) {
+ return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT;
+}
+
+/*
+ * Reset ethernet board after a timeout
+ */
+void
+EtherReset(void) {
+ int dpreg = dpc.dc_reg;
+ /* initialize the board */
+ outb(WD_BASEREG + WD_MSR,
+ WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK));
+
+ /* reset dp8390 ethernet chip */
+ outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT);
+
+ /* initialize first register set */
+ outb(dpreg + DP_IMR, 0);
+ outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT);
+ outb(dpreg + DP_TPSR, dpc.dc_tpsr);
+ outb(dpreg + DP_PSTART, dpc.dc_pstart);
+ outb(dpreg + DP_PSTOP, dpc.dc_pstop);
+ outb(dpreg + DP_BNRY, dpc.dc_pstart);
+ outb(dpreg + DP_RCR, RCR_MON);
+ outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST);
+ if (boardid & SLOT_16BIT)
+ outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES);
+ else
+ outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES);
+ outb(dpreg + DP_RBCR0, 0);
+ outb(dpreg + DP_RBCR1, 0);
+ outb(dpreg + DP_ISR, 0xFF);
+
+ /* initialize second register set */
+ outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT);
+ outb(dpreg + DP_PAR0, eth_myaddr[0]);
+ outb(dpreg + DP_PAR1, eth_myaddr[1]);
+ outb(dpreg + DP_PAR2, eth_myaddr[2]);
+ outb(dpreg + DP_PAR3, eth_myaddr[3]);
+ outb(dpreg + DP_PAR4, eth_myaddr[4]);
+ outb(dpreg + DP_PAR5, eth_myaddr[5]);
+ outb(dpreg + DP_CURR, dpc.dc_pstart+1);
+
+ /* and back to first register set */
+ outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT);
+ outb(dpreg + DP_RCR, RCR_AB);
+
+ /* flush counters */
+ (void) inb(dpreg + DP_CNTR0);
+ (void) inb(dpreg + DP_CNTR1);
+ (void) inb(dpreg + DP_CNTR2);
+
+ /* and go ... */
+ outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT);
+}
+
+/*
+ * Initialize the WD80X3 board
+ */
+int
+EtherInit(void) {
+ unsigned sum;
+ int memsize;
+ /* reset the ethernet card */
+ outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
+ LongPause();
+ outb(WD_BASEREG + WD_MSR, 0);
+
+ /* determine whether the controller is there */
+ sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) +
+ inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) +
+ inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) +
+ inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM);
+ if ((sum & 0xFF) != 0xFF)
+ return 0;
+
+ /*
+ * Determine the type of board
+ */
+ boardid = 0;
+ if (!Aliasing()) {
+ if (BoardIs16Bit()) {
+ boardid |= BOARD_16BIT;
+ if (SlotIs16Bit())
+ boardid |= SLOT_16BIT;
+ }
+ }
+ memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */
+
+ /* special setup needed for WD8013 boards */
+ if (boardid & SLOT_16BIT)
+ outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E);
+
+ /* get ethernet address */
+ eth_myaddr[0] = inb(WD_BASEREG + WD_EA0);
+ eth_myaddr[1] = inb(WD_BASEREG + WD_EA1);
+ eth_myaddr[2] = inb(WD_BASEREG + WD_EA2);
+ eth_myaddr[3] = inb(WD_BASEREG + WD_EA3);
+ eth_myaddr[4] = inb(WD_BASEREG + WD_EA4);
+ eth_myaddr[5] = inb(WD_BASEREG + WD_EA5);
+
+ /* save settings for future use */
+ dpc.dc_reg = WD_BASEREG + WD_DP8390;
+ dpc.dc_mem = WD_BASEMEM;
+ dpc.dc_tpsr = 0;
+ dpc.dc_pstart = 6;
+ dpc.dc_pstop = (memsize >> 8) & 0xFF;
+
+ printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize);
+
+ EtherReset();
+ return 1;
+}
+
+/*
+ * Stop ethernet board
+ */
+void
+EtherStop(void) {
+ /* stop dp8390, followed by a board reset */
+ outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT);
+ outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
+ outb(WD_BASEREG + WD_MSR, 0);
+}
+
+/* TBD - all users must take care to use the current "data seg" value
+when moving data from/to the controller */
+static void
+WdCopy(u_long src, u_long dst, u_long count) {
+#if TRACE > 0
+printf("WdCopy from %x to %x for %d\n", src, dst, count);
+#endif
+ assert(count <= 1514);
+ if (boardid & SLOT_16BIT)
+ outb(WD_BASEREG + WD_REG5,
+ WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
+ PhysBcopy(src, dst, count);
+ if (boardid & SLOT_16BIT)
+ outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
+}
+
+/*
+ * Send an ethernet packet to destination 'dest'
+ */
+void
+EtherSend(packet_t *pkt, u_short proto, u_char *dest) {
+ ethhdr_t *ep;
+
+ pkt->pkt_len += sizeof(ethhdr_t);
+ pkt->pkt_offset -= sizeof(ethhdr_t);
+ ep = (ethhdr_t *) pkt->pkt_offset;
+ ep->eth_proto = htons(proto);
+ bcopy((char *)dest, (char *)ep->eth_dst, ETH_ADDRSIZE);
+ bcopy((char *)eth_myaddr, (char *)ep->eth_src, ETH_ADDRSIZE);
+#if 0
+DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t));
+#endif
+ if (pkt->pkt_len < 60)
+ pkt->pkt_len = 60;
+
+#if TRACE > 0
+ {
+ int i;
+DUMP_STRUCT("EtherSend: pkt", pkt->pkt_offset, pkt->pkt_len);
+#if 0
+ for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)(pkt->pkt_offset)+i));
+ printe("\n");
+#endif
+ }
+#endif
+
+#if 0
+printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt->pkt_offset), dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
+#endif
+ WdCopy(LA(pkt->pkt_offset),
+ dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
+ outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
+ outb(dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
+ outb(dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
+ outb(dpc.dc_reg + DP_CR, CR_TXP);
+
+#if 0
+ printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
+ printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
+ printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
+ printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP);
+#endif
+}
+
+/*
+ * Copy dp8390 packet header for observation
+ */
+static void
+GetHeader(u_long haddr, dphdr_t *dph) {
+#if TRACE > 0
+printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t));
+#endif
+ WdCopy(haddr, LA(dph), sizeof(dphdr_t));
+#if 0
+DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t));
+#endif
+}
+
+/*
+ * Poll the dp8390 just see if there's an Ethernet packet
+ * available. If there is, its contents is returned in a
+ * pkt structure, otherwise a nil pointer is returned.
+ */
+packet_t *
+EtherReceive(void) {
+ u_char pageno, curpage, nextpage;
+ int dpreg = dpc.dc_reg;
+ packet_t *pkt;
+ dphdr_t dph;
+ u_long addr;
+
+ pkt = (packet_t *)0;
+ if (inb(dpreg + DP_RSR) & RSR_PRX) {
+ /* get current page numbers */
+ pageno = inb(dpreg + DP_BNRY) + 1;
+ if (pageno == dpc.dc_pstop)
+ pageno = dpc.dc_pstart;
+ outb(dpreg + DP_CR, CR_PS_P1);
+ curpage = inb(dpreg + DP_CURR);
+ outb(dpreg + DP_CR, CR_PS_P0);
+ if (pageno == curpage)
+ return (packet_t *) 0;
+
+ /* get packet header */
+ addr = dpc.dc_mem + (pageno << 8);
+ GetHeader(addr, &dph);
+ nextpage = dph.dh_next;
+
+ /* allocate packet */
+ pkt = PktAlloc(0);
+#if 0
+printe("EtherReceive: allocated pkt %x\n", pkt);
+#endif
+ pkt->pkt_len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF);
+ pkt->pkt_len -= sizeof(dphdr_t);
+ if (pkt->pkt_len > 1514) /* bug in dp8390 */
+ pkt->pkt_len = 1514;
+
+#if TRACE > 0
+ {
+ int i;
+ printe("EtherReceive %d bytes: ", pkt->pkt_len);
+#if 0
+ for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)pkt+i));
+#else
+ DUMP_STRUCT("", pkt, pkt->pkt_len);
+#endif
+ printe("\n");
+ }
+#endif
+
+ /*
+ * The dp8390 maintains a circular buffer of pages (256 bytes)
+ * in which incomming ethernet packets are stored. The following
+ * if detects wrap arounds, and copies the ethernet packet to
+ * our local buffer in two chunks if necesarry.
+ */
+ assert(pkt->pkt_offset);
+ assert(pkt->pkt_len <= (6 << 8));
+ if (nextpage < pageno && nextpage > dpc.dc_pstart) {
+ u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t);
+
+ assert(nbytes <= (6 << 8));
+#if TRACE > 0
+printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), nbytes);
+#endif
+ WdCopy(addr + sizeof(dphdr_t),
+ LA(pkt->pkt_offset), nbytes);
+ if ((pkt->pkt_len - nbytes) > 0)
+ /* TBD - this OK? */
+#if TRACE > 0
+printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt->pkt_offset) + nbytes, pkt->pkt_len - nbytes);
+#endif
+ WdCopy(dpc.dc_mem + (dpc.dc_pstart << 8),
+ LA(pkt->pkt_offset) + nbytes,
+ pkt->pkt_len - nbytes);
+ } else {
+#if TRACE > 0
+printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
+#endif
+ WdCopy(addr + sizeof(dphdr_t),
+ LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
+ }
+
+ /* release occupied pages */
+ if (nextpage == dpc.dc_pstart)
+ nextpage = dpc.dc_pstop;
+ outb(dpreg + DP_BNRY, nextpage - 1);
+ }
+
+ return pkt;
+}
+
+/*
+ * Print an ethernet address in human readable form
+ */
+void
+EtherPrintAddr(u_char *addr) {
+ printf("%x:%x:%x:%x:%x:%x",
+ addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF,
+ addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF);
+}