summaryrefslogtreecommitdiff
path: root/sys/arch/i386/stand/pxeboot
diff options
context:
space:
mode:
authorTom Cosgrove <tom@cvs.openbsd.org>2004-03-19 13:48:21 +0000
committerTom Cosgrove <tom@cvs.openbsd.org>2004-03-19 13:48:21 +0000
commit96c309c384e99b742c4307ece38772c4841ffad2 (patch)
treecdeec8f47d46f4ab706d96f40f448bd51c1ea38b /sys/arch/i386/stand/pxeboot
parent4700fd56f6db1ac60a4bef5eb9c8a0b7451a19d7 (diff)
Enter pxeboot, derived from the NetBSD implementation. Initially
intended to support network installs using bsd.rd over TFTP. Thanks to the many who tested, including Diana Eichert. ok deraadt@
Diffstat (limited to 'sys/arch/i386/stand/pxeboot')
-rw-r--r--sys/arch/i386/stand/pxeboot/Makefile46
-rw-r--r--sys/arch/i386/stand/pxeboot/conf.c129
-rw-r--r--sys/arch/i386/stand/pxeboot/devopen.c217
-rw-r--r--sys/arch/i386/stand/pxeboot/net.c290
-rw-r--r--sys/arch/i386/stand/pxeboot/open.c136
-rw-r--r--sys/arch/i386/stand/pxeboot/pxeboot.8165
-rw-r--r--sys/arch/i386/stand/pxeboot/srt0.S223
7 files changed, 1206 insertions, 0 deletions
diff --git a/sys/arch/i386/stand/pxeboot/Makefile b/sys/arch/i386/stand/pxeboot/Makefile
new file mode 100644
index 00000000000..464273724fb
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/Makefile
@@ -0,0 +1,46 @@
+# $OpenBSD: Makefile,v 1.1 2004/03/19 13:48:19 tom Exp $
+
+.include "${.CURDIR}/../Makefile.inc"
+
+MAN= pxeboot.8
+
+.if ${MACHINE} == "i386"
+PROG= pxeboot
+LD?= ld
+SIZE?= size
+LDFLAGS+=-nostdlib -Bstatic
+INSTALL_STRIP=
+
+LDFLAGS+=-Ttext $(LINKADDR) -N -x -noinhibit-exec
+CLEANFILES+= crt0.o
+SRCS= srt0.S
+
+SRCS+= boot.c cmd.c vars.c bootarg.c conf.c devopen.c net.c open.c
+S =${.CURDIR}/../../../..
+SADIR= ${.CURDIR}/..
+
+LDADD= ${LIBSA} ${LIBZ}
+DPADD= ${LIBSA} ${LIBZ}
+
+.PATH: ${S}/stand/boot
+
+${PROG}: $(OBJS) $(DPADD)
+ $(LD) $(LDFLAGS) -o ${PROG} $(OBJS) $(LDADD)
+ @$(SIZE) ${PROG}
+ @if [ -x ${.OBJDIR}/${PROG} ]; then \
+ objcopy -O binary ${PROG} ${.OBJDIR}/.tmp;\
+ mv -f ${.OBJDIR}/.tmp ${.OBJDIR}/${PROG}; \
+ ls -l ${.OBJDIR}/${PROG}; \
+ fi
+
+.else
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
+
+CPPFLAGS+=-DBOOTMAGIC=$(BOOTMAGIC) ${DEBUGFLAGS}
+CPPFLAGS+=-DLINKADDR=${LINKADDR}
+CFLAGS+=${SACFLAGS} -D__INTERNAL_LIBSA_CREAD
+#AFLAGS+=-Wa,-R
+# AFLAGS+=-Wa,-a
diff --git a/sys/arch/i386/stand/pxeboot/conf.c b/sys/arch/i386/stand/pxeboot/conf.c
new file mode 100644
index 00000000000..d7bb877b6a5
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/conf.c
@@ -0,0 +1,129 @@
+/* $OpenBSD: conf.c,v 1.1 2004/03/19 13:48:19 tom Exp $ */
+
+/*
+ * Copyright (c) 2004 Tom Cosgrove
+ * Copyright (c) 1996 Michael Shalayeff
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <libsa.h>
+#include <lib/libsa/ufs.h>
+#ifdef notdef
+#include <lib/libsa/cd9660.h>
+#include <lib/libsa/fat.h>
+#endif
+#include <lib/libsa/nfs.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/netif.h>
+#include <lib/libsa/unixdev.h>
+#include <biosdev.h>
+#include <dev/cons.h>
+#include "debug.h"
+#include "pxeboot.h"
+#include "pxe_net.h"
+
+const char version[] = "1.00";
+int debug = 1;
+
+#undef _TEST
+
+
+void (*sa_cleanup)(void) = pxe_shutdown;
+
+
+void (*i386_probe1[])(void) = {
+ ps2probe, gateA20on, debug_init, cninit, apmprobe,
+ pciprobe, /* smpprobe, */ pxeprobe, memprobe
+};
+void (*i386_probe2[])(void) = {
+ diskprobe
+};
+void (*i386_probe3[])(void) = {
+ pxeinfo
+/* netprobe_pxe, netprobe_mac, netprobe_inet4, netprobe_bootdev */
+};
+
+struct i386_boot_probes probe_list[] = {
+ { "probing", i386_probe1, NENTS(i386_probe1) },
+ { "disk", i386_probe2, NENTS(i386_probe2) },
+ { "net", i386_probe3, NENTS(i386_probe3) },
+};
+int nibprobes = NENTS(probe_list);
+
+/* This next list must match file_system[]. */
+char *fs_name[] = {
+ NULL, "tftp", "nfs"
+};
+int nfsname = NENTS(fs_name);
+
+struct fs_ops file_system[] = {
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
+ ufs_stat, ufs_readdir },
+ { tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek,
+ tftp_stat, tftp_readdir },
+ { nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek,
+ nfs_stat, nfs_readdir },
+#ifdef notdef
+ { fat_open, fat_close, fat_read, fat_write, fat_seek,
+ fat_stat, fat_readdir },
+ { cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
+ cd9660_stat, cd9660_readdir },
+#endif
+#ifdef _TEST
+ { null_open, null_close, null_read, null_write, null_seek,
+ null_stat, null_readdir }
+#endif
+};
+int nfsys = NENTS(file_system);
+
+struct devsw devsw[] = {
+#ifdef _TEST
+ { "UNIX", unixstrategy, unixopen, unixclose, unixioctl },
+#else
+ { "BIOS", biosstrategy, biosopen, biosclose, biosioctl },
+#endif
+};
+int ndevs = NENTS(devsw);
+
+struct devsw netsw[] = {
+ { "net", net_strategy, net_open, net_close, net_ioctl },
+};
+
+struct netif_driver *netif_drivers[] = {
+};
+int n_netif_drivers = NENTS(netif_drivers);
+
+struct consdev constab[] = {
+#ifdef _TEST
+ { unix_probe, unix_init, unix_getc, unix_putc },
+#else
+ { pc_probe, pc_init, pc_getc, pc_putc },
+ { com_probe, com_init, com_getc, com_putc },
+#endif
+ { NULL }
+};
+struct consdev *cn_tab = constab;
diff --git a/sys/arch/i386/stand/pxeboot/devopen.c b/sys/arch/i386/stand/pxeboot/devopen.c
new file mode 100644
index 00000000000..d7e327a82e6
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/devopen.c
@@ -0,0 +1,217 @@
+/* $OpenBSD: devopen.c,v 1.1 2004/03/19 13:48:19 tom Exp $ */
+
+/*
+ * Copyright (c) 1994 Tom Cosgrove
+ * Copyright (c) 1996-1999 Michael Shalayeff
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#include "libsa.h"
+#include "biosdev.h"
+#include <sys/param.h>
+#include <dev/cons.h>
+
+extern int debug;
+
+extern char *fs_name[];
+extern int nfsname;
+extern struct devsw netsw[];
+
+/* XXX use slot for 'rd' for 'hd' pseudo-device */
+const char bdevs[][4] = {
+ "wd", "", "fd", "wt", "sd", "st", "cd", "mcd",
+ "", "", "", "", "", "", "", "scd", "", "hd", ""
+};
+const int nbdevs = NENTS(bdevs);
+
+const char cdevs[][4] = {
+ "cn", "", "", "", "", "", "", "",
+ "com", "", "", "", "pc"
+};
+const int ncdevs = NENTS(cdevs);
+
+/* pass dev_t to the open routines */
+int
+devopen(struct open_file *f, const char *fname, char **file)
+{
+ struct devsw *dp = devsw;
+ char *p;
+ char *stripdev;
+ int i, l;
+ int rc = 1;
+
+ *file = (char *)fname;
+
+#ifdef DEBUG
+ if (debug)
+ printf("devopen(%s):", fname);
+#endif
+
+ /* Make sure we have a prefix, e.g. hd0a: or tftp:. */
+ for (p = (char *)fname; *p != ':' && *p != '\0'; ) p++;
+ if (*p != ':')
+ return 1;
+ stripdev = p + 1;
+
+ l = p - fname; /* Length of device prefix. */
+ for (i = 0; i < nfsname; i++) {
+ if ((fs_name[i] != NULL) &&
+ (strncmp(fname, fs_name[i], l) == 0)) {
+
+ /* Force oopen() etc to use this filesystem. */
+ f->f_ops = &file_system[i];
+ f->f_dev = dp = &netsw[0];
+
+ rc = (*dp->dv_open)(f, NULL);
+ if (rc == 0)
+ *file = stripdev;
+ else
+ f->f_dev = NULL;
+#ifdef DEBUG
+ if (debug)
+ putchar('\n');
+#endif
+ return rc;
+ }
+ }
+
+ for (i = 0; i < ndevs && rc != 0; dp++, i++) {
+#ifdef DEBUG
+ if (debug)
+ printf(" %s: ", dp->dv_name);
+#endif
+ if ((rc = (*dp->dv_open)(f, file)) == 0) {
+ f->f_dev = dp;
+ return 0;
+ }
+#ifdef DEBUG
+ else if (debug)
+ printf("%d", rc);
+#endif
+
+ }
+#ifdef DEBUG
+ if (debug)
+ putchar('\n');
+#endif
+
+ if ((f->f_flags & F_NODEV) == 0)
+ f->f_dev = dp;
+
+ return rc;
+}
+
+void
+devboot(dev_t bootdev, char *p)
+{
+ *p++ = 't';
+ *p++ = 'f';
+ *p++ = 't';
+ *p++ = 'p';
+ *p = '\0';
+}
+
+int pch_pos = 0;
+
+void
+putchar(int c)
+{
+ switch (c) {
+ case '\177': /* DEL erases */
+ cnputc('\b');
+ cnputc(' ');
+ case '\b':
+ cnputc('\b');
+ if (pch_pos)
+ pch_pos--;
+ break;
+ case '\t':
+ do
+ cnputc(' ');
+ while (++pch_pos % 8);
+ break;
+ case '\n':
+ case '\r':
+ cnputc(c);
+ pch_pos=0;
+ break;
+ default:
+ cnputc(c);
+ pch_pos++;
+ break;
+ }
+}
+
+int
+getchar(void)
+{
+ register int c = cngetc();
+
+ if (c == '\r')
+ c = '\n';
+
+ if ((c < ' ' && c != '\n') || c == '\177')
+ return c;
+
+ putchar(c);
+
+ return c;
+}
+
+char ttyname_buf[8];
+
+char *
+ttyname(int fd)
+{
+ snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
+ cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
+
+ return ttyname_buf;
+}
+
+dev_t
+ttydev(char *name)
+{
+ int i, unit = -1;
+ char *no = name + strlen(name) - 1;
+
+ while (no >= name && *no >= '0' && *no <= '9')
+ unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
+ if (no < name || unit < 0)
+ return NODEV;
+ for (i = 0; i < ncdevs; i++)
+ if (strncmp(name, cdevs[i], no - name + 1) == 0)
+ return (makedev(i, unit));
+ return NODEV;
+}
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ if (major(dev) == 8) /* comN */
+ return (comspeed(dev, sp));
+
+ /* pc0 and anything else */
+ return 9600;
+}
diff --git a/sys/arch/i386/stand/pxeboot/net.c b/sys/arch/i386/stand/pxeboot/net.c
new file mode 100644
index 00000000000..f6ff146a68f
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/net.c
@@ -0,0 +1,290 @@
+/* $OpenBSD: net.c,v 1.1 2004/03/19 13:48:19 tom Exp $ */
+/* $NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $ */
+
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL)
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libsa/net.h>
+
+#include <pxeboot.h>
+
+/* Caller must leave room for ethernet, ip and udp headers in front!! */
+ssize_t
+sendudp(struct iodesc *d, void *pkt, size_t len)
+{
+ return pxesendudp(d, pkt, len);
+}
+
+/*
+ * Receive a UDP packet and validate it is for us.
+ * Caller leaves room for the headers (Ether, IP, UDP)
+ */
+ssize_t
+readudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
+{
+ return pxereadudp(d, pkt, len, tleft);
+}
+
+/*
+ * Send a packet and wait for a reply, with exponential backoff.
+ *
+ * The send routine must return the actual number of bytes written.
+ *
+ * The receive routine can indicate success by returning the number of
+ * bytes read; it can return 0 to indicate EOF; it can return -1 with a
+ * non-zero errno to indicate failure; finally, it can return -1 with a
+ * zero errno to indicate it isn't done yet.
+ */
+ssize_t
+sendrecv(struct iodesc *d, ssize_t (*sproc)(struct iodesc *, void *, size_t),
+ void *sbuf, size_t ssize,
+ ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
+ void *rbuf, size_t rsize)
+{
+ ssize_t cc;
+ time_t t, tmo, tlast;
+ long tleft;
+
+#ifdef NET_DEBUG
+ if (debug)
+ printf("sendrecv: called\n");
+#endif
+
+ tmo = MINTMO;
+ tlast = tleft = 0;
+ t = getsecs();
+ for (;;) {
+ if (tleft <= 0) {
+ if (tmo >= MAXTMO) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ cc = (*sproc)(d, sbuf, ssize);
+ if (cc < 0 || (size_t)cc < ssize)
+ panic("sendrecv: short write! (%d < %d)",
+ cc, ssize);
+
+ tleft = tmo;
+ tmo <<= 1;
+ if (tmo > MAXTMO)
+ tmo = MAXTMO;
+ tlast = t;
+ }
+
+ /* Try to get a packet and process it. */
+ cc = (*rproc)(d, rbuf, rsize, tleft);
+ /* Return on data, EOF or real error. */
+ if (cc != -1 || errno != 0)
+ return (cc);
+
+ /* Timed out or didn't get the packet we're waiting for */
+ t = getsecs();
+ tleft -= t - tlast;
+ tlast = t;
+ }
+}
+
+/*
+ * Like inet_addr() in the C library, but we only accept base-10.
+ * Return values are in network order.
+ */
+n_long
+inet_addr(char *cp)
+{
+ u_long val;
+ int n;
+ char c;
+ u_int parts[4];
+ u_int *pp = parts;
+
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0;
+ while ((c = *cp) != '\0') {
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ goto bad;
+ *pp++ = val, cp++;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (*cp != '\0')
+ goto bad;
+
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ goto bad;
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ goto bad;
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ goto bad;
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+
+ return (htonl(val));
+ bad:
+ return (htonl(INADDR_NONE));
+}
+
+char *
+inet_ntoa(struct in_addr ia)
+{
+ return (intoa(ia.s_addr));
+}
+
+/* Similar to inet_ntoa() */
+char *
+intoa(n_long addr)
+{
+ char *cp;
+ u_int byte;
+ int n;
+ static char buf[sizeof(".255.255.255.255")];
+
+ NTOHL(addr);
+ cp = &buf[sizeof buf];
+ *--cp = '\0';
+
+ n = 4;
+ do {
+ byte = addr & 0xff;
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0) {
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0)
+ *--cp = byte + '0';
+ }
+ *--cp = '.';
+ addr >>= 8;
+ } while (--n > 0);
+
+ return (cp+1);
+}
+
+static char *
+number(char *s, int *n)
+{
+ for (*n = 0; isdigit(*s); s++)
+ *n = (*n * 10) + *s - '0';
+ return s;
+}
+
+n_long
+ip_convertaddr(char *p)
+{
+#define IP_ANYADDR 0
+ n_long addr = 0, n;
+
+ if (p == (char *)0 || *p == '\0')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 24) & 0xff000000;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 16) & 0xff0000;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 8) & 0xff00;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= n & 0xff;
+ if (*p != '\0')
+ return IP_ANYADDR;
+
+ return htonl(addr);
+}
diff --git a/sys/arch/i386/stand/pxeboot/open.c b/sys/arch/i386/stand/pxeboot/open.c
new file mode 100644
index 00000000000..3c91f3ab379
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/open.c
@@ -0,0 +1,136 @@
+/* $OpenBSD: open.c,v 1.1 2004/03/19 13:48:19 tom Exp $ */
+/* $NetBSD: open.c,v 1.12 1996/09/30 16:01:21 ws Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * 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. 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.
+ *
+ * @(#)open.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <lib/libsa/stand.h>
+
+struct open_file files[SOPEN_MAX];
+
+/*
+ * File primitives proper
+ */
+
+int
+#ifndef __INTERNAL_LIBSA_CREAD
+open(const char *fname, int mode)
+#else
+oopen(const char *fname, int mode)
+#endif
+{
+ struct open_file *f;
+ int fd, i, error;
+ char *file;
+
+ /* find a free file descriptor */
+ for (fd = 0, f = files; fd < SOPEN_MAX; fd++, f++)
+ if (f->f_flags == 0)
+ goto fnd;
+ errno = EMFILE;
+ return -1;
+fnd:
+ /*
+ * Try to open the device.
+ * Convert open mode (0,1,2) to F_READ, F_WRITE.
+ */
+ f->f_flags = mode + 1;
+ f->f_dev = (struct devsw *)0;
+ f->f_ops = (struct fs_ops *)0;
+ file = (char *)0;
+ error = devopen(f, fname, &file);
+ if (error ||
+ (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0))
+ goto err;
+
+ /* see if we opened a raw device; otherwise, 'file' is the file name. */
+ if (file == (char *)0 || *file == '\0') {
+ f->f_flags |= F_RAW;
+ return fd;
+ }
+
+ /* Allow f->f_ops to be set by devopen routine. */
+ if (f->f_ops != NULL) {
+ error = f->f_ops->open(file, f);
+ if (error == 0)
+ return fd;
+ }
+ else {
+ /* pass file name to the different filesystem open routines */
+ for (i = 0; i < nfsys; i++) {
+ /* convert mode (0,1,2) to FREAD, FWRITE. */
+ error = (file_system[i].open)(file, f);
+ if (error == 0) {
+ f->f_ops = &file_system[i];
+ return (fd);
+ }
+ if (error == ENOENT || error == ENOTDIR)
+ break;
+ }
+ }
+ if (error == 0)
+ error = ENOENT;
+
+ f->f_dev->dv_close(f);
+err:
+ f->f_flags = 0;
+ errno = error;
+ return -1;
+}
diff --git a/sys/arch/i386/stand/pxeboot/pxeboot.8 b/sys/arch/i386/stand/pxeboot/pxeboot.8
new file mode 100644
index 00000000000..9afa8c9a5ad
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/pxeboot.8
@@ -0,0 +1,165 @@
+.\" $OpenBSD: pxeboot.8,v 1.1 2004/03/19 13:48:19 tom Exp $
+.\" Copyright (c) 2004 Tom Cosgrove
+.\" Copyright (c) 2003 Matthias Drochner
+.\" Copyright (c) 1999 Doug White
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.Dd March 18, 2004
+.Dt PXEBOOT 8 i386
+.Os
+.Sh NAME
+.Nm pxeboot
+.Nd
+i386-specific second-stage PXE bootstrap
+.Sh DESCRIPTION
+.Nm
+is a modified version of the i386 second-stage bootstrap program,
+.Xr boot 8 ,
+configured to run under Intel's Preboot Execution Environment (PXE).
+PXE is a form of smart boot ROM, built into many Ethernet cards from Intel,
+3Com, and other manufacturers.
+.Pp
+The computer's PXE boot ROM contacts a DHCP server by broadcasting a request.
+It gets an IP address from the DHCP server,
+then it is told the name of the boot program to download \(em
+in this case, the boot program is
+.Nm .
+The ROM downloads the boot program using TFTP, then executes it.
+.Pp
+The
+.Nm
+boot program will look for an
+.Pa etc/boot.conf
+configuration
+file on the TFTP server.
+If it finds one, it processes the commands within it.
+.Pp
+.Nm
+then sits in a loop,
+processing commands given by the user.
+It accepts all the commands accepted by
+.Xr boot 8 .
+.Pp
+If no commands are given after a short period,
+.Nm
+will then attempt to load the OpenBSD kernel
+.Pa bsd
+via TFTP.
+It may be told to boot an alternative kernel,
+either by commands in the
+.Pa boot.conf
+file,
+or by commands typed by the user at the
+.Ic boot>
+prompt.
+At this time,
+it is expected that pxeboot will be used to load the
+.Pa bsd.rd
+install kernel,
+for network installs,
+although this is not the default kernel.
+.Pp
+To configure a server to support network installs,
+you must first enable and configure the
+.Xr dhcpd 8
+and
+.Xr tftpd 8
+services.
+You may also want to enable
+.Xr ftpd 8
+or
+.Xr httpd 8
+to serve the install sets.
+.Pp
+Put
+.Nm
+and the kernel into the TFTP server's root directory.
+Create an
+.Pa etc/boot.conf
+file if required.
+.Pp
+A sample configuration file for
+.Xr dhcpd 8
+might be as follows:
+.Bd -literal -offset indent
+option domain-name "example.com";
+option routers 10.0.0.1;
+option subnet-mask 255.255.255.0;
+option broadcast-address 10.0.0.255;
+option domain-name-servers 10.0.0.1;
+server-name "DHCPserver";
+server-identifier 10.0.0.1;
+
+default-lease-time 120;
+max-lease-time 120;
+
+subnet 10.0.0.0 netmask 255.255.255.0 {
+ filename "pxeboot";
+ range 10.0.0.10 10.0.0.254;
+}
+.Ed
+.Pp
+If you are using a more recent version of the ISC DHCP server,
+you can specify the boot program with a construct such as:
+.Bd -literal -offset indent
+class "pxe-clients-i386" {
+ match if substring(option vendor-class-identifier, 0, 20)
+ = "PXEClient:Arch:00000";
+ filename "pxeboot";
+}
+.Ed
+.Sh FILES
+.Bl -tag -width /usr/mdec/biosbootxx -compact
+.It Pa /usr/mdec/pxeboot
+PXE-specific second-stage bootstrap
+.It Pa /etc/boot.conf
+.Nm
+configuration file (read from TFTP server)
+.El
+.Sh EXAMPLES
+Boot the install kernel:
+.Pp
+.Dl boot> bsd.rd
+.Pp
+The same thing:
+.Pp
+.Dl boot> boot tftp:bsd.rd
+.Sh SEE ALSO
+.Xr dhcpd.conf 5 ,
+.Xr boot 8 ,
+.Xr boot_i386 8 ,
+.Xr dhcpd 8 ,
+.Xr httpd 8 ,
+.Xr tftpd 8
+.Rs
+.%T Preboot Execution Environment (PXE) Specification
+.%N Version 2.1
+.%D September 20, 1999
+.%A Intel Corporation
+.Re
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Ox 3.5 .
diff --git a/sys/arch/i386/stand/pxeboot/srt0.S b/sys/arch/i386/stand/pxeboot/srt0.S
new file mode 100644
index 00000000000..be237cf8f6f
--- /dev/null
+++ b/sys/arch/i386/stand/pxeboot/srt0.S
@@ -0,0 +1,223 @@
+/* $OpenBSD: srt0.S,v 1.1 2004/03/19 13:48:19 tom Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ */
+#include <machine/asm.h>
+#include <assym.h>
+
+#define BOOTSTACK 0xfffc
+
+ .globl _C_LABEL(end)
+ .globl _C_LABEL(edata)
+ .globl _C_LABEL(boot)
+ .globl _C_LABEL(_rtt)
+ .globl _C_LABEL(bios_bootdev)
+ .globl _ASM_LABEL(pmm_init)
+ .globl Gdtr
+
+ .text
+ .code16
+ .globl _start
+_start:
+#ifdef DEBUG
+ movl $0xb80a0, %ebx
+ addr32 movl $0x07420742, (%ebx)
+#endif
+
+/* Clobbers %ax, maybe more */
+#define putc(c) movb $c, %al; call Lchr
+
+ /*
+ * We are loaded by the PXE loader at location 0x7C00. Like
+ * the standard /boot, we are linked to run at 0x40120 (load
+ * address 0x40000), so we relocate to there.
+ *
+ * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so don't
+ * have to worry about an overlapping copy until pxeboot is
+ * over 225 KB.
+ *
+ * Note that there are other reasons to be worried if
+ * sizeof(/boot) > 64 KB. So currently we copy a maximum of 64 KB.
+ *
+ * PXE loads us with a stack that grows down from 0x80000 (512 KB).
+ * While it is unlikely that this will clash with our code that
+ * we're copying up, we create a temporary stack just below us
+ * before the relocate. We also set the entire %esp register, to
+ * be on the safe side.
+ */
+#define PXEBOOTADDR 0x7c00 /* Address where we are loaded by PXE */
+ xorw %ax, %ax
+ movw %ax, %ss /* CPU disables interrupts till.. */
+ movl $PXEBOOTADDR-4, %esp /* after this instruction */
+
+ movw $(PXEBOOTADDR >> 4), %ax
+ movw %ax, %ds
+ xorw %si, %si /* Where we're coming from */
+
+ movw $(LINKADDR >> 4), %ax
+ movw %ax, %es /* Set %es = 0x4000 */
+ xorw %di, %di /* Where we're going to */
+
+ movl $_C_LABEL(end), %ecx
+ subl $_C_LABEL(_start), %ecx /* How big are we? */
+
+ cld
+ rep; movsb /* Copy into place */
+
+ jmpl $(LINKADDR >> 4), $(relocated-_start) /* Now relocate */
+
+relocated:
+ /*
+ * In 16-bit mode, we have segment registers == 0x4012, and
+ * offsets work from here, with offset(_start) == 0.
+ *
+ * In 32-bit mode, we have a flat memory model, where
+ * offset(_start) == 0x40120. This is how we're linked.
+ *
+ * Now transition to protected mode.
+ *
+ * First, initialise the global descriptor table.
+ */
+ cli
+ push %cs
+ pop %ds
+ addr32 data32 lgdt (Gdtr - LINKADDR)
+
+ movl %cr0, %eax
+ orl $CR0_PE, %eax
+ data32 movl %eax, %cr0
+ data32 ljmp $8, $1f /* Seg sel 0x08 is flat 32-bit code */
+1:
+ .code32
+ movl $0x10, %eax /* Seg sel 0x10 is flat 32-bit data */
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ movl $BOOTSTACK, %esp
+#ifdef DEBUG
+ movl $0xb8000, %ebx
+ movl $0x07420742, (%ebx)
+#endif
+
+ xorl %edx, %edx
+ movl %edx, _C_LABEL(bios_bootdev)
+ pushl %edx /* boot() takes this as a parameter */
+
+ /* Set up an interrupt descriptor table for protected mode. */
+ call _ASM_LABEL(pmm_init)
+#ifdef DEBUG
+ movl $0xb80a4, %ebx
+ movl $0x07520752, (%ebx)
+#endif
+
+ /* Zero .bss */
+ xorl %eax, %eax
+ movl $_C_LABEL(end), %ecx
+ subl $_C_LABEL(edata), %ecx
+ movl $_C_LABEL(edata), %edi
+ cld
+ rep; stosb
+
+ /* Set our program name ("PXEBOOT", not "BOOT"). */
+ movl $pxe_progname, %eax
+ movl %eax, progname
+
+ /*
+ * Now call "main()".
+ *
+ * We run in flat 32-bit protected mode, with no address mapping.
+ */
+#ifdef DEBUG
+ movl $0xb8004, %ebx
+ movl $0x07410741, (%ebx)
+#endif
+ call _C_LABEL(boot)
+
+ /* boot() should not return. If it does, reset computer. */
+ jmp _C_LABEL(_rtt)
+
+ENTRY(debugchar)
+ pushl %ebx
+ movl 8(%esp), %ebx
+ addl %ebx, %ebx
+ addl $0xb8000, %ebx
+
+ xorl %eax, %eax
+ movb 12(%esp), %al
+
+ andl $0xfffffffe, %ebx
+ movb %al, (%ebx)
+ popl %ebx
+ ret
+
+ .code16
+
+/*
+ * Write out value in %ax in hex
+ */
+hex_word:
+ pushw %ax
+ mov %ah, %al
+ call hex_byte
+ popw %ax
+ /* fall thru */
+/*
+ * Write out value in %al in hex
+ */
+hex_byte:
+ pushw %ax
+ shrb $4, %al
+ call hex_nibble
+ popw %ax
+ /* fall thru */
+
+/* Write out nibble in %al */
+hex_nibble:
+ and $0x0F, %al
+ add $'0', %al
+ cmpb $'9', %al
+ jbe Lchr
+ addb $'A'-'9'-1, %al
+ /* fall thru to Lchr */
+/*
+ * Lchr: write the character in %al to console
+ */
+Lchr:
+ pushw %bx
+ movb $0x0e, %ah
+ xorw %bx, %bx
+ incw %bx /* movw $0x01, %bx */
+ int $0x10
+ popw %bx
+ ret
+
+pxe_progname:
+ .asciz "PXEBOOT"
+
+ .end