summaryrefslogtreecommitdiff
path: root/sys/arch/i386/stand
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
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')
-rw-r--r--sys/arch/i386/stand/Makefile4
-rw-r--r--sys/arch/i386/stand/boot/conf.c24
-rw-r--r--sys/arch/i386/stand/libsa/Makefile6
-rw-r--r--sys/arch/i386/stand/libsa/diskprobe.c5
-rw-r--r--sys/arch/i386/stand/libsa/exec_i386.c5
-rw-r--r--sys/arch/i386/stand/libsa/gateA20.c12
-rw-r--r--sys/arch/i386/stand/libsa/gidt.S10
-rw-r--r--sys/arch/i386/stand/libsa/gidt.h35
-rw-r--r--sys/arch/i386/stand/libsa/libsa.h16
-rw-r--r--sys/arch/i386/stand/libsa/machdep.c44
-rw-r--r--sys/arch/i386/stand/libsa/ps2probe.c (renamed from sys/arch/i386/stand/libsa/ps2probe.h)8
-rw-r--r--sys/arch/i386/stand/libsa/pxe.c547
-rw-r--r--sys/arch/i386/stand/libsa/pxe.h528
-rw-r--r--sys/arch/i386/stand/libsa/pxe_call.S202
-rw-r--r--sys/arch/i386/stand/libsa/pxe_net.c184
-rw-r--r--sys/arch/i386/stand/libsa/pxe_net.h44
-rw-r--r--sys/arch/i386/stand/libsa/pxe_netif.h43
-rw-r--r--sys/arch/i386/stand/libsa/pxeboot.h53
-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
25 files changed, 2928 insertions, 48 deletions
diff --git a/sys/arch/i386/stand/Makefile b/sys/arch/i386/stand/Makefile
index 4ce4685db6a..f688a25eb57 100644
--- a/sys/arch/i386/stand/Makefile
+++ b/sys/arch/i386/stand/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.10 2002/06/10 22:17:38 weingart Exp $
+# $OpenBSD: Makefile,v 1.11 2004/03/19 13:48:18 tom Exp $
.if ${MACHINE} == "i386"
SUBDIR= etc libsa libz mbr
.endif
-SUBDIR+= biosboot installboot boot
+SUBDIR+= biosboot installboot boot pxeboot
test-fd0:
sudo mount /dev/fd0a /mnt
diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c
index f6b90a6c977..8fe3b541c12 100644
--- a/sys/arch/i386/stand/boot/conf.c
+++ b/sys/arch/i386/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.27 2003/10/23 18:33:45 fgsch Exp $ */
+/* $OpenBSD: conf.c,v 1.28 2004/03/19 13:48:19 tom Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff
@@ -41,11 +41,30 @@
#include <lib/libsa/unixdev.h>
#include <biosdev.h>
#include <dev/cons.h>
+#include "debug.h"
-const char version[] = "2.05";
+const char version[] = "2.06";
int debug = 1;
+void (*sa_cleanup)(void) = NULL;
+
+
+void (*i386_probe1[])(void) = {
+ ps2probe, gateA20on, debug_init, cninit,
+ apmprobe, pciprobe, /* smpprobe, */ memprobe
+};
+void (*i386_probe2[])(void) = {
+ diskprobe
+};
+
+struct i386_boot_probes probe_list[] = {
+ { "probing", i386_probe1, NENTS(i386_probe1) },
+ { "disk", i386_probe2, NENTS(i386_probe2) }
+};
+int nibprobes = NENTS(probe_list);
+
+
struct fs_ops file_system[] = {
{ ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
ufs_stat, ufs_readdir },
@@ -93,4 +112,3 @@ struct consdev constab[] = {
{ NULL }
};
struct consdev *cn_tab = constab;
-
diff --git a/sys/arch/i386/stand/libsa/Makefile b/sys/arch/i386/stand/libsa/Makefile
index 23a372f994d..1a435b2c74a 100644
--- a/sys/arch/i386/stand/libsa/Makefile
+++ b/sys/arch/i386/stand/libsa/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.42 2003/08/08 07:38:45 deraadt Exp $
+# $OpenBSD: Makefile,v 1.43 2004/03/19 13:48:18 tom Exp $
.include "${.CURDIR}/../Makefile.inc"
@@ -22,7 +22,7 @@ CLEANFILES+= gidt.o debug_i386.o alloca.o \
SRCS+= gidt.S debug_i386.S alloca.S \
biosdev.c bioscons.c gateA20.c apmprobe.c \
memprobe.c diskprobe.c pciprobe.c smpprobe.c \
- time.c biosprobe.c
+ time.c biosprobe.c ps2probe.c pxe.c pxe_net.c pxe_call.S
CLEANFILES+= unixdev.o unixsys.o nullfs.o
.endif
@@ -42,7 +42,7 @@ SRCS+= arp.c ether.c in_cksum.c net.c netif.c rpc.c
SRCS+= bootp.c bootparam.c rarp.c
# boot filesystems
-SRCS+= ufs.c nfs.c cd9660.c
+SRCS+= ufs.c nfs.c tftp.c cd9660.c
# debugger
SRCS+= debug.c
diff --git a/sys/arch/i386/stand/libsa/diskprobe.c b/sys/arch/i386/stand/libsa/diskprobe.c
index b2bbf03a091..27cc00c7d47 100644
--- a/sys/arch/i386/stand/libsa/diskprobe.c
+++ b/sys/arch/i386/stand/libsa/diskprobe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diskprobe.c,v 1.25 2004/03/09 19:12:13 tom Exp $ */
+/* $OpenBSD: diskprobe.c,v 1.26 2004/03/19 13:48:18 tom Exp $ */
/*
* Copyright (c) 1997 Tobias Weingartner
@@ -171,7 +171,6 @@ diskprobe(void)
bios_diskinfo_t *bios_diskinfo;
/* Init stuff */
- printf("disk:");
TAILQ_INIT(&disklist);
/* Do probes */
@@ -203,8 +202,6 @@ diskprobe(void)
addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t),
bios_diskinfo);
-
- printf("\n");
}
diff --git a/sys/arch/i386/stand/libsa/exec_i386.c b/sys/arch/i386/stand/libsa/exec_i386.c
index 2274278b864..d4ce2e33d02 100644
--- a/sys/arch/i386/stand/libsa/exec_i386.c
+++ b/sys/arch/i386/stand/libsa/exec_i386.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_i386.c,v 1.29 2004/03/09 19:12:13 tom Exp $ */
+/* $OpenBSD: exec_i386.c,v 1.30 2004/03/19 13:48:18 tom Exp $ */
/*
* Copyright (c) 1997-1998 Michael Shalayeff
@@ -54,6 +54,9 @@ run_loadfile(u_long *marks, int howto)
bios_consdev_t cd;
extern int com_speed; /* from bioscons.c */
+ if (sa_cleanup != NULL)
+ (*sa_cleanup)();
+
cd.consdev = cn_tab->cn_dev;
cd.conspeed = com_speed;
addbootarg(BOOTARG_CONSDEV, sizeof(cd), &cd);
diff --git a/sys/arch/i386/stand/libsa/gateA20.c b/sys/arch/i386/stand/libsa/gateA20.c
index 38b592bb4df..00bfad10613 100644
--- a/sys/arch/i386/stand/libsa/gateA20.c
+++ b/sys/arch/i386/stand/libsa/gateA20.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gateA20.c,v 1.9 2003/08/11 06:23:09 deraadt Exp $ */
+/* $OpenBSD: gateA20.c,v 1.10 2004/03/19 13:48:18 tom Exp $ */
/*
* Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
@@ -43,6 +43,16 @@
/*
+ * "Probe"-style routine (no parameters) to turn A20 on
+ */
+void
+gateA20on(void)
+{
+ gateA20(1);
+}
+
+
+/*
* Gate A20 for high memory
*/
void
diff --git a/sys/arch/i386/stand/libsa/gidt.S b/sys/arch/i386/stand/libsa/gidt.S
index e0810e8569b..f4a51db396a 100644
--- a/sys/arch/i386/stand/libsa/gidt.S
+++ b/sys/arch/i386/stand/libsa/gidt.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: gidt.S,v 1.27 2004/01/13 23:54:07 millert Exp $ */
+/* $OpenBSD: gidt.S,v 1.28 2004/03/19 13:48:18 tom Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -36,11 +36,7 @@
#undef _LOCORE
#include <assym.h>
-#define SNULL 0x00
-#define S32TEXT 0x08
-#define S32DATA 0x10
-#define S16TEXT 0x18
-#define S16DATA 0x20
+#include "gidt.h"
#ifdef GIDT_DEBUG
#define gidt_debug0 ; \
@@ -204,11 +200,13 @@ idt:
idtb(36); idtb(37); idtb(38); idtb(39); idtb(40); idtb(41)
idtb(42); idtb(43); idtb(44); idtb(45); idtb(46); idtb(47)
#undef idte
+ .globl Idtr
Idtr: .word . - idt - 1
.long idt
.word 0
.align 8
+ .globl Idtr_real
Idtr_real: .word 1023
.long 0
.word 0
diff --git a/sys/arch/i386/stand/libsa/gidt.h b/sys/arch/i386/stand/libsa/gidt.h
new file mode 100644
index 00000000000..457709674c1
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/gidt.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: gidt.h,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+
+/*
+ * Copyright (c) 2004 Tom Cosgrove
+ * 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.
+ *
+ */
+
+#define SNULL 0x00
+#define S32TEXT 0x08
+#define S32DATA 0x10
+#define S16TEXT 0x18
+#define S16DATA 0x20
diff --git a/sys/arch/i386/stand/libsa/libsa.h b/sys/arch/i386/stand/libsa/libsa.h
index 4fec71c0b44..f2cae0987f1 100644
--- a/sys/arch/i386/stand/libsa/libsa.h
+++ b/sys/arch/i386/stand/libsa/libsa.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: libsa.h,v 1.38 2003/06/03 20:22:12 mickey Exp $ */
+/* $OpenBSD: libsa.h,v 1.39 2004/03/19 13:48:18 tom Exp $ */
/*
* Copyright (c) 1996-1999 Michael Shalayeff
@@ -33,9 +33,19 @@
#define DEFAULT_KERNEL_ADDRESS 0
+struct i386_boot_probes {
+ char *name;
+ void (**probes)(void);
+ int count;
+};
+
+extern void (*sa_cleanup)(void);
+
void gateA20(int);
+void gateA20on(void);
void smpprobe(void);
+void ps2probe(void);
void pciprobe(void);
void memprobe(void);
void diskprobe(void);
@@ -57,6 +67,10 @@ extern const int nbdevs;
extern u_int cnvmem, extmem; /* XXX global pass memprobe()->machdep_start() */
extern int ps2model;
+extern struct i386_boot_probes probe_list[];
+extern int nibprobes;
+extern void (*devboot_p)(dev_t, char *);
+
/* diskprobe.c */
extern bios_diskinfo_t bios_diskinfo[];
extern u_int32_t bios_cksumlen;
diff --git a/sys/arch/i386/stand/libsa/machdep.c b/sys/arch/i386/stand/libsa/machdep.c
index d74c043a68a..5dc8cf90680 100644
--- a/sys/arch/i386/stand/libsa/machdep.c
+++ b/sys/arch/i386/stand/libsa/machdep.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: machdep.c,v 1.34 2003/08/11 06:23:09 deraadt Exp $ */
+/* $OpenBSD: machdep.c,v 1.35 2004/03/19 13:48:18 tom Exp $ */
/*
+ * Copyright (c) 2004 Tom Cosgrove
* Copyright (c) 1997-1999 Michael Shalayeff
* All rights reserved.
*
@@ -29,8 +30,6 @@
#include "libsa.h"
#include <machine/apmvar.h>
#include <machine/biosvar.h>
-#include "debug.h"
-#include "ps2probe.h"
volatile struct BIOS_regs BIOS_regs;
@@ -40,30 +39,25 @@ volatile struct BIOS_regs BIOS_regs;
#define CKPT(c) /* c */
#endif
-extern int debug;
-int ps2model;
-
void
machdep(void)
{
- /* here */ CKPT('0');
- printf("probing:");
-#ifndef _TEST
- /* probe for a model number, gateA20() neds ps2model */
- ps2probe(); CKPT('1');
- gateA20(1); CKPT('2');
- debug_init(); CKPT('3');
-#endif
- /* call console init before doing any io */
- cninit(); CKPT('4');
-#ifndef _TEST
- apmprobe(); CKPT('5');
- pciprobe(); CKPT('6');
-/* smpprobe(); CKPT('7'); */
- memprobe(); CKPT('8');
- printf("\n");
+ int i, j;
+ struct i386_boot_probes *pr;
- diskprobe(); CKPT('9');
-#endif
- CKPT('Z');
+ /*
+ * The list of probe routines is now in conf.c.
+ */
+ for (i = 0; i < nibprobes; i++) {
+ pr = &probe_list[i];
+ if (pr != NULL) {
+ printf("%s:", pr->name);
+
+ for (j = 0; j < pr->count; j++) {
+ (*(pr->probes)[j])();
+ }
+
+ printf("\n");
+ }
+ }
}
diff --git a/sys/arch/i386/stand/libsa/ps2probe.h b/sys/arch/i386/stand/libsa/ps2probe.c
index 78018bd1a83..898fe5cf54f 100644
--- a/sys/arch/i386/stand/libsa/ps2probe.h
+++ b/sys/arch/i386/stand/libsa/ps2probe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ps2probe.h,v 1.3 2003/06/03 20:22:12 mickey Exp $ */
+/* $OpenBSD: ps2probe.c,v 1.1 2004/03/19 13:48:18 tom Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -26,7 +26,11 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-static __inline void
+#include "libsa.h"
+
+int ps2model;
+
+void
ps2probe(void)
{
char *p;
diff --git a/sys/arch/i386/stand/libsa/pxe.c b/sys/arch/i386/stand/libsa/pxe.c
new file mode 100644
index 00000000000..b159b51f5dc
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe.c
@@ -0,0 +1,547 @@
+/* $OpenBSD: pxe.c,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD: pxe.c,v 1.5 2003/03/11 18:29:00 drochner Exp $ */
+
+/*
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
+ * 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.
+ */
+
+/*
+ * Support for the Intel Preboot Execution Environment (PXE).
+ *
+ * PXE provides a UDP implementation as well as a UNDI network device
+ * driver. UNDI is much more complicated to use than PXE UDP, so we
+ * use PXE UDP as a cheap and easy way to get PXE support.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#ifdef _STANDALONE
+#include <lib/libkern/libkern.h>
+#else
+#include <string.h>
+#endif
+
+#include <net/if.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 <lib/libsa/bootp.h>
+
+#include "pxeboot.h"
+#include "pxe.h"
+#include "pxe_netif.h"
+
+void (*pxe_call)(u_int16_t);
+
+void pxecall_bangpxe(u_int16_t); /* pxe_call.S */
+void pxecall_pxenv(u_int16_t); /* pxe_call.S */
+
+char pxe_command_buf[256];
+
+BOOTPLAYER bootplayer;
+
+struct in_addr servip; /* for tftp */ /* XXX init this */
+
+/* static struct btinfo_netif bi_netif; */
+
+/*****************************************************************************
+ * This section is a replacement for libsa/udp.c
+ *****************************************************************************/
+
+/* Caller must leave room for ethernet, ip, and udp headers in front!! */
+ssize_t
+pxesendudp(struct iodesc *d, void *pkt, size_t len)
+{
+ t_PXENV_UDP_WRITE *uw = (void *) pxe_command_buf;
+
+ uw->status = 0;
+
+ uw->ip = d->destip.s_addr;
+ uw->gw = gateip.s_addr;
+ uw->src_port = d->myport;
+ uw->dst_port = d->destport;
+ uw->buffer_size = len;
+ uw->buffer.segment = VTOPSEG(pkt);
+ uw->buffer.offset = VTOPOFF(pkt);
+
+ pxe_call(PXENV_UDP_WRITE);
+
+ if (uw->status != PXENV_STATUS_SUCCESS) {
+ /* XXX This happens a lot; it shouldn't. */
+ if (uw->status != PXENV_STATUS_FAILURE)
+ printf("sendudp: PXENV_UDP_WRITE failed: 0x%x\n",
+ uw->status);
+ return -1;
+ }
+
+ return len;
+}
+
+/*
+ * Receive a UDP packet and validate it for us.
+ * Caller leaves room for the headers (Ether, IP, UDP).
+ */
+ssize_t
+pxereadudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
+{
+ t_PXENV_UDP_READ *ur = (void *) pxe_command_buf;
+ struct udphdr *uh;
+ struct ip *ip;
+
+ uh = (struct udphdr *)pkt - 1;
+ ip = (struct ip *)uh - 1;
+
+ bzero(ur, sizeof(*ur));
+
+ ur->dest_ip = d->myip.s_addr;
+ ur->d_port = d->myport;
+ ur->buffer_size = len;
+ ur->buffer.segment = VTOPSEG(pkt);
+ ur->buffer.offset = VTOPOFF(pkt);
+
+ /* XXX Timeout unused. */
+
+ pxe_call(PXENV_UDP_READ);
+
+ if (ur->status != PXENV_STATUS_SUCCESS) {
+ /* XXX This happens a lot; it shouldn't. */
+ if (ur->status != PXENV_STATUS_FAILURE)
+ printf("readudp: PXENV_UDP_READ_failed: 0x%0x\n",
+ ur->status);
+ return -1;
+ }
+
+ ip->ip_src.s_addr = ur->src_ip;
+ uh->uh_sport = ur->s_port;
+ uh->uh_dport = d->myport;
+
+ return ur->buffer_size;
+}
+
+/*
+ * netif layer:
+ * open, close, shutdown: called from dev_net.c
+ * socktodesc: called by network protocol modules
+ *
+ * We only allow one open socket.
+ */
+
+static int pxe_inited;
+static struct iodesc desc;
+
+int
+pxe_netif_open()
+{
+ t_PXENV_UDP_OPEN *uo = (void *) pxe_command_buf;
+
+#ifdef NETIF_DEBUG
+ printf("pxe_netif_open()\n");
+#endif
+ if (!pxe_inited) {
+ if (pxe_init(0) != 0)
+ return -1;
+ pxe_inited = 1;
+ }
+ /* BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); */
+
+ bzero(uo, sizeof(*uo));
+
+ uo->src_ip = bootplayer.yip;
+
+ pxe_call(PXENV_UDP_OPEN);
+
+ if (uo->status != PXENV_STATUS_SUCCESS) {
+ printf("pxe_netif_open: PXENV_UDP_OPEN failed: 0x%x\n",
+ uo->status);
+ return -1;
+ }
+
+ bcopy(bootplayer.CAddr, desc.myea, ETHER_ADDR_LEN);
+
+ /*
+ * Since the PXE BIOS has already done DHCP, make sure we
+ * don't reuse any of its transaction IDs.
+ */
+ desc.xid = bootplayer.ident;
+
+ return 0;
+}
+
+void
+pxe_netif_close(sock)
+ int sock;
+{
+ t_PXENV_UDP_CLOSE *uc = (void *) pxe_command_buf;
+
+#ifdef NETIF_DEBUG
+ if (sock != 0)
+ printf("pxe_netif_close: sock=%d\n", sock);
+#endif
+
+ uc->status = 0;
+
+ pxe_call(PXENV_UDP_CLOSE);
+
+ if (uc->status != PXENV_STATUS_SUCCESS)
+ printf("pxe_netif_end: PXENV_UDP_CLOSE failed: 0x%x\n",
+ uc->status);
+}
+
+void
+pxe_netif_shutdown()
+{
+#ifdef NETIF_DEBUG
+ printf("pxe_netif_shutdown()\n");
+#endif
+
+ pxe_shutdown();
+}
+
+struct iodesc *
+pxesocktodesc(sock)
+ int sock;
+{
+
+#ifdef NETIF_DEBUG
+ if (sock != 0)
+ return 0;
+ else
+#endif
+ return &desc;
+}
+
+/*****************************************************************************
+ * PXE initialization and support routines
+ *****************************************************************************/
+
+u_int16_t pxe_command_buf_seg;
+u_int16_t pxe_command_buf_off;
+
+extern u_int16_t bangpxe_off, bangpxe_seg;
+extern u_int16_t pxenv_off, pxenv_seg;
+
+/* static struct btinfo_netif bi_netif; */
+
+void
+pxeprobe(void)
+{
+ if (!pxe_inited) {
+ if (pxe_init(1) == 0) {
+ pxe_inited = 1;
+ }
+ }
+}
+
+int
+pxe_init(int quiet)
+{
+ t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf;
+ pxenv_t *pxenv;
+ pxe_t *pxe;
+ char *cp;
+ int i;
+ u_int8_t cksum, *ucp;
+
+ /*
+ * Checking for the presence of PXE is a machine-dependent
+ * operation. On the IA-32, this can be done two ways:
+ *
+ * Int 0x1a function 0x5650
+ *
+ * Scan memory for the !PXE or PXENV+ signatures
+ *
+ * We do the latter, since the Int method returns a pointer
+ * to a deprecated structure (PXENV+).
+ */
+
+ pxenv = NULL;
+ pxe = NULL;
+
+ for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
+ if (pxenv == NULL) {
+ pxenv = (pxenv_t *)cp;
+ if (memcmp(pxenv->Signature, S_SIZE("PXENV+")) != 0)
+ pxenv = NULL;
+ else {
+ for (i = 0, ucp = (u_int8_t *)cp, cksum = 0;
+ i < pxenv->Length; i++)
+ cksum += ucp[i];
+ if (cksum != 0) {
+ printf("\npxe_init: bad cksum (0x%x) "
+ "for PXENV+ at 0x%lx\n", cksum,
+ (u_long) cp);
+ pxenv = NULL;
+ }
+ }
+ }
+
+ if (pxe == NULL) {
+ pxe = (pxe_t *)cp;
+ if (memcmp(pxe->Signature, S_SIZE("!PXE")) != 0)
+ pxe = NULL;
+ else {
+ for (i = 0, ucp = (u_int8_t *)cp, cksum = 0;
+ i < pxe->StructLength; i++)
+ cksum += ucp[i];
+ if (cksum != 0) {
+ printf("pxe_init: bad cksum (0x%x) "
+ "for !PXE at 0x%lx\n", cksum,
+ (u_long) cp);
+ pxe = NULL;
+ }
+ }
+ }
+
+ if (pxe != NULL && pxenv != NULL)
+ break;
+ }
+
+ if (pxe == NULL && pxenv == NULL) {
+ if (!quiet) printf("pxe_init: No PXE BIOS found.\n");
+ return 1;
+ }
+
+ if (pxenv == NULL) {
+ /* assert(pxe != NULL); */
+
+ printf(quiet ? " pxe!" : "PXE present\n");
+ }
+ else { /* pxenv != NULL */
+ int bang = 0;
+
+ if (pxenv->Version >= 0x0201 && pxe != NULL) {
+ /* 2.1 or greater -- don't use PXENV+ */
+ bang = 1;
+ }
+
+ if (quiet) {
+ printf(" pxe%c[%d.%d]",
+ (bang ? '!' : '+'),
+ (pxenv->Version >> 8) & 0xff,
+ pxenv->Version & 0xff);
+ }
+ else {
+ printf("PXE BIOS Version %d.%d\n",
+ (pxenv->Version >> 8) & 0xff,
+ pxenv->Version & 0xff);
+ }
+
+ if (bang) {
+ pxenv = NULL;
+ }
+ }
+
+ if (pxe != NULL) {
+ pxe_call = pxecall_bangpxe;
+ bangpxe_off = pxe->EntryPointSP.offset;
+ bangpxe_seg = pxe->EntryPointSP.segment;
+ } else {
+ pxe_call = pxecall_pxenv;
+ pxenv_off = pxenv->RMEntry.offset;
+ pxenv_seg = pxenv->RMEntry.segment;
+ }
+
+ /*
+ * Pre-compute the segment/offset of the pxe_command_buf
+ * to make things nicer in the low-level calling glue.
+ */
+ pxe_command_buf_seg = VTOPSEG(pxe_command_buf);
+ pxe_command_buf_off = VTOPOFF(pxe_command_buf);
+
+ /*
+ * Get the cached info from the server's Discovery reply packet.
+ */
+ bzero(gci, sizeof(*gci));
+ gci->PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
+ pxe_call(PXENV_GET_CACHED_INFO);
+
+ if (gci->Status != PXENV_STATUS_SUCCESS) {
+ printf("\npxeinfo: PXENV_GET_CACHED_INFO failed: 0x%x\n",
+ gci->Status);
+ return 1;
+ }
+
+ memcpy(&bootplayer,
+ SEGOFF2FLAT(gci->Buffer.segment, gci->Buffer.offset),
+ gci->BufferSize);
+
+ bcopy(&bootplayer.yip, &myip.s_addr, sizeof(myip.s_addr));
+ bcopy(&bootplayer.sip, &servip.s_addr, sizeof(servip.s_addr));
+
+ /* Compute our "natural" netmask. */
+ if (IN_CLASSA(myip.s_addr))
+ netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(myip.s_addr))
+ netmask = IN_CLASSB_NET;
+ else
+ netmask = IN_CLASSC_NET;
+
+ return 0;
+}
+
+void
+pxeinfo(void)
+{
+ u_int8_t *p;
+#ifdef PXE_DEBUG
+ t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf;
+#endif
+
+ printf(" mac %s", ether_sprintf(bootplayer.CAddr));
+ p = (u_int8_t *)&myip.s_addr;
+ printf(", ip %d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ p = (u_int8_t *)&servip.s_addr;
+ printf(", server %d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+
+#ifdef PXE_DEBUG
+ /*
+ * Get network interface information.
+ */
+ bzero(gnt, sizeof(*gnt));
+ pxe_call(PXENV_UNDI_GET_NIC_TYPE);
+
+ if (gnt->Status != PXENV_STATUS_SUCCESS) {
+ printf("\npxeinfo: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n",
+ gnt->Status);
+ return;
+ }
+
+ switch (gnt->NicType) {
+ case PCI_NIC:
+ case CardBus_NIC:
+ /* strncpy(bi_netif.ifname, "pxe", sizeof(bi_netif.ifname)); */
+ /* bi_netif.bus = BI_BUS_PCI; */
+ /* bi_netif.addr.tag = gnt->info.pci.BusDevFunc; */
+
+ printf("\nPXE: Using %s device at bus %d device %d function %d\n",
+ gnt->NicType == PCI_NIC ? "PCI" : "CardBus",
+ (gnt->info.pci.BusDevFunc >> 8) & 0xff,
+ (gnt->info.pci.BusDevFunc >> 3) & 0x1f,
+ gnt->info.pci.BusDevFunc & 0x7);
+ break;
+
+ case PnP_NIC:
+ /* XXX Make bootinfo work with this. */
+ printf("\nPXE: Using PnP device at 0x%x\n",
+ gnt->info.pnp.CardSelNum);
+ }
+#endif
+}
+
+void
+pxe_shutdown(void)
+{
+ int try;
+ t_PXENV_UNLOAD_STACK *unload = (void *) pxe_command_buf;
+ t_PXENV_UNDI_SHUTDOWN *shutdown = (void *) pxe_command_buf;
+#ifdef PXE_DEBUG
+ t_PXENV_UDP_CLOSE *close = (void *) pxe_command_buf;
+#endif
+
+ if (pxe_call == NULL)
+ return;
+
+ /* Close any open UDP connections. Ignore return value. */
+ pxe_call(PXENV_UDP_CLOSE);
+#ifdef PXE_DEBUG
+ printf("pxe_shutdown: PXENV_UDP_CLOSE returned 0x%x\n", close->status);
+#endif
+
+ /* Sometimes PXENV_UNDI_SHUTDOWN doesn't work at first */
+ for (try = 3; try > 0; try--) {
+ pxe_call(PXENV_UNDI_SHUTDOWN);
+
+ if (shutdown->Status == PXENV_STATUS_SUCCESS)
+ break;
+
+ printf("pxe_shutdown: PXENV_UNDI_SHUTDOWN failed: 0x%x\n",
+ shutdown->Status);
+
+ if (try != 1)
+ sleep(1);
+ }
+
+ /* Have multiple attempts at PXENV_UNLOAD_STACK, too */
+ for (try = 3; try > 0; try--) {
+ pxe_call(PXENV_UNLOAD_STACK);
+
+ if (unload->Status == PXENV_STATUS_SUCCESS)
+ break;
+
+ printf("pxe_shutdown: PXENV_UNLOAD_STACK failed: 0x%x\n",
+ unload->Status);
+
+ if (try != 1)
+ sleep(1);
+ }
+}
diff --git a/sys/arch/i386/stand/libsa/pxe.h b/sys/arch/i386/stand/libsa/pxe.h
new file mode 100644
index 00000000000..37b5ceead0d
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe.h
@@ -0,0 +1,528 @@
+/* $OpenBSD: pxe.h,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD: pxe.h,v 1.1 2002/02/16 03:37:40 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
+ * 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.
+ */
+
+/*
+ * Note that these structures and types are named according to
+ * the Intel PXE documentation.
+ */
+
+#define S_SIZE(s) s, sizeof(s) - 1
+
+#define IP_STR "%d.%d.%d.%d"
+#define IP_ARGS(ip) \
+ (int)(ip >> 24) & 0xff, (int)(ip >> 16) & 0xff, \
+ (int)(ip >> 8) & 0xff, (int)ip & 0xff
+
+#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARGS(mac) \
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
+
+typedef struct {
+ uint16_t offset;
+ uint16_t segment;
+} SEGOFF16_t __attribute__((__packed__));
+
+typedef struct {
+ uint16_t Seg_Addr;
+ uint32_t Phy_Addr;
+ uint16_t Seg_Size;
+} SEGDESC_t __attribute__((__packed__));
+
+typedef uint16_t SEGSEL_t;
+typedef uint16_t PXENV_STATUS_t;
+typedef uint32_t IP4_t;
+typedef uint32_t ADDR32_t;
+typedef uint16_t UDP_PORT_t;
+
+#define MAC_ADDR_LEN 16
+typedef uint8_t MAC_ADDR[MAC_ADDR_LEN];
+
+/* PXENV+ */
+typedef struct {
+ uint8_t Signature[6]; /* 'PXENV+' */
+ uint16_t Version; /* MSB = major, LSB = minor */
+ uint8_t Length; /* structure length */
+ uint8_t Checksum; /* checksum pad */
+ SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */
+ /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */
+ uint32_t PMOffset; /* Protected mode entry */
+ SEGSEL_t PMSelector; /* Protected mode selector */
+ SEGSEL_t StackSeg; /* Stack segment address */
+ uint16_t StackSize; /* Stack segment size (bytes) */
+ SEGSEL_t BC_CodeSeg; /* BC Code segment address */
+ uint16_t BC_CodeSize; /* BC Code segment size (bytes) */
+ SEGSEL_t BC_DataSeg; /* BC Data segment address */
+ uint16_t BC_DataSize; /* BC Data segment size (bytes) */
+ SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */
+ uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */
+ SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */
+ uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */
+ SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct,
+ only present when Version > 2.1 */
+} __attribute__((__packed__)) pxenv_t;
+
+/* !PXE */
+typedef struct {
+ uint8_t Signature[4];
+ uint8_t StructLength;
+ uint8_t StructCksum;
+ uint8_t StructRev;
+ uint8_t reserved_1;
+ SEGOFF16_t UNDIROMID;
+ SEGOFF16_t BaseROMID;
+ SEGOFF16_t EntryPointSP;
+ SEGOFF16_t EntryPointESP;
+ SEGOFF16_t StatusCallout;
+ uint8_t reserved_2;
+ uint8_t SegDescCn;
+ SEGSEL_t FirstSelector;
+ SEGDESC_t Stack;
+ SEGDESC_t UNDIData;
+ SEGDESC_t UNDICode;
+ SEGDESC_t UNDICodeWrite;
+ SEGDESC_t BC_Data;
+ SEGDESC_t BC_Code;
+ SEGDESC_t BC_CodeWrite;
+} __attribute__((__packed__)) pxe_t;
+
+#define PXENV_START_UNDI 0x0000
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t ax;
+ uint16_t bx;
+ uint16_t dx;
+ uint16_t di;
+ uint16_t es;
+} __attribute__((__packed__)) t_PXENV_START_UNDI;
+
+#define PXENV_UNDI_STARTUP 0x0001
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_STARTUP;
+
+#define PXENV_UNDI_CLEANUP 0x0002
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_CLEANUP;
+
+#define PXENV_UNDI_INITIALIZE 0x0003
+typedef struct {
+ PXENV_STATUS_t Status;
+ ADDR32_t ProtocolIni; /* Phys addr of a copy of the
+ driver module */
+ uint8_t reserved[8];
+} __attribute__((__packed__)) t_PXENV_UNDI_INITALIZE;
+
+
+#define MAXNUM_MCADDR 8
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+} __attribute__((__packed__)) t_PXENV_UNDI_MCAST_ADDRESS;
+
+#define PXENV_UNDI_RESET_ADAPTER 0x0004
+typedef struct {
+ PXENV_STATUS_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__((__packed__)) t_PXENV_UNDI_RESET;
+
+#define PXENV_UNDI_SHUTDOWN 0x0005
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_SHUTDOWN;
+
+#define PXENV_UNDI_OPEN 0x0006
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t OpenFlag;
+ uint16_t PktFilter;
+# define FLTR_DIRECTED 0x0001
+# define FLTR_BRDCST 0x0002
+# define FLTR_PRMSCS 0x0003
+# define FLTR_SRC_RTG 0x0004
+
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__((__packed__)) t_PXENV_UNDI_OPEN;
+
+#define PXENV_UNDI_CLOSE 0x0007
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_CLOSE;
+
+#define PXENV_UNDI_TRANSMIT 0x0008
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t Protocol;
+# define P_UNKNOWN 0
+# define P_IP 1
+# define P_ARP 2
+# define P_RARP 3
+
+ uint8_t XmitFlag;
+# define XMT_DESTADDR 0x0000
+# define XMT_BROADCAST 0x0001
+
+ SEGOFF16_t DestAddr;
+ SEGOFF16_t TBD;
+ uint32_t Reserved[2];
+} __attribute__((__packed__)) t_PXENV_UNDI_TRANSMIT;
+
+#define MAX_DATA_BLKS 8
+typedef struct {
+ uint16_t ImmedLength;
+ SEGOFF16_t Xmit;
+ uint16_t DataBlkCount;
+ struct DataBlk {
+ uint8_t TDPtrType;
+ uint8_t TDRsvdByte;
+ uint16_t TDDataLen;
+ SEGOFF16_t TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+} __attribute__((__packed__)) t_PXENV_UNDI_TBD;
+
+#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009
+typedef struct {
+ PXENV_STATUS_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __attribute__((__packed__)) t_PXENV_UNDI_SET_MCAST_ADDR;
+
+#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A
+typedef struct {
+ PXENV_STATUS_t Status;
+ MAC_ADDR StationAddress; /* Temp MAC addres to use */
+} __attribute__((__packed__)) t_PXENV_UNDI_SET_STATION_ADDR;
+
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t filter; /* see UNDI_OPEN (0x0006) */
+} __attribute__((__packed__)) t_PXENV_UNDI_SET_PACKET_FILTER;
+
+#define PXENV_UNDI_GET_INFORMATION 0x000C
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t BaseIo; /* Adapter base I/O address */
+ uint16_t IntNumber; /* Adapter IRQ number */
+ uint16_t MaxTranUnit; /* Adapter maximum transmit
+ unit */
+ uint16_t HwType; /* Type of protocol at the
+ hardware addr */
+# define ETHER_TYPE 1
+# define EXP_ETHER_TYPE 2
+# define IEEE_TYPE 6
+# define ARCNET_TYPE 7
+
+ uint16_t HwAddrLen; /* Length of hardware address */
+ MAC_ADDR CurrentNodeAddress; /* Current hardware address */
+ MAC_ADDR PermNodeAddress; /* Permanent hardware address */
+ SEGSEL_t ROMAddress; /* Real mode ROM segment
+ address */
+ uint16_t RxBufCt; /* Receive queue length */
+ uint16_t TxBufCt; /* Transmit queue length */
+} __attribute__((__packed__)) t_PXENV_UNDI_GET_INFORMATION;
+
+#define PXENV_UNDI_GET_STATISTICS 0x000D
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint32_t XmitGoodFrames; /* Number of successful
+ transmissions */
+ uint32_t RcvGoodFrames; /* Number of good frames
+ received */
+ uint32_t RcvCRCErrors; /* Number of frames with
+ CRC errors */
+ uint32_t RcvResourceErrors; /* Number of frames dropped */
+} __attribute__((__packed__)) t_PXENV_UNDI_GET_STATISTICS;
+
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_CLEAR_STATISTICS;
+
+#define PXENV_UNDI_INITIATE_DIAGS 0x000F
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_INITIATE_DIAGS;
+
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_UNDI_FORCE_INTERRUPT;
+
+#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t InetAddr; /* IP mulicast address */
+ MAC_ADDR MediaAddr; /* MAC multicast address */
+} __attribute__((__packed__)) t_PXENV_UNDI_GET_MCAST_ADDR;
+
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t NicType; /* Type of NIC */
+# define PCI_NIC 2
+# define PnP_NIC 3
+# define CardBus_NIC 4
+
+ union {
+ struct {
+ uint16_t Vendor_ID;
+ uint16_t Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint8_t Rev;
+ uint16_t BusDevFunc;
+ uint16_t SubVendor_ID;
+ uint16_t SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ uint32_t EISA_Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint16_t CardSelNum;
+ } pnp;
+ } info;
+} __attribute__((__packed__)) t_PXENV_UNDI_GET_NIC_TYPE;
+
+#define PXENV_UNDI_GET_IFACE_INFO 0x0013
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */
+ uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */
+ uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */
+ uint32_t Reserved[4]; /* must be 0 */
+} __attribute__((__packed__)) t_PXENV_UNDI_GET_NDIS_INFO;
+
+#define PXENV_UNDI_ISR 0x0014
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */
+ uint16_t BufferLength; /* Length of Frame */
+ uint16_t FrameLength; /* Total length of reciever
+ frame */
+ uint16_t FrameHeaderLength; /* Length of the media header
+ in Frame */
+ SEGOFF16_t Frame; /* receive buffer */
+ uint8_t ProtType; /* Protocol type */
+ uint8_t PktType; /* Packet Type */
+# define PXENV_UNDI_ISR_IN_START 1
+# define PXENV_UNDI_ISR_IN_PROCESS 2
+# define PXENV_UNDI_ISR_IN_GET_NEXT 3
+
+ /* one of these will be returned for PXENV_UNDI_ISR_IN_START */
+# define PXENV_UNDI_ISR_OUT_OURS 0
+# define PXENV_UNDI_ISR_OUT_NOT_OUTS 1
+
+ /*
+ * one of these will bre returnd for PXEND_UNDI_ISR_IN_PROCESS
+ * and PXENV_UNDI_ISR_IN_GET_NEXT
+ */
+# define PXENV_UNDI_ISR_OUT_DONE 0
+# define PXENV_UNDI_ISR_OUT_TRANSMIT 2
+# define PXENV_UNDI_ISR_OUT_RECIEVE 3
+# define PXENV_UNDI_ISR_OUT_BUSY 4
+} __attribute__((__packed__)) t_PXENV_UNDI_ISR;
+
+#define PXENV_STOP_UNDI 0x0015
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_STOP_UNDI;
+
+#define PXENV_TFTP_OPEN 0x0020
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAddress;
+ uint8_t FileName[128];
+ UDP_PORT_t TFTPPort;
+ uint16_t PacketSize;
+} __attribute__((__packed__)) t_PXENV_TFTP_OPEN;
+
+#define PXENV_TFTP_CLOSE 0x0021
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_TFTP_CLOSE;
+
+#define PXENV_TFTP_READ 0x0022
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t PacketNumber;
+ uint16_t BufferSize;
+ SEGOFF16_t Buffer;
+} __attribute__((__packed__)) t_PXENV_TFTP_READ;
+
+#define PXENV_TFTP_READ_FILE 0x0023
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t FileName[128];
+ uint32_t BufferSize;
+ ADDR32_t Buffer;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAddress;
+ IP4_t McastIPAddress;
+ UDP_PORT_t TFTPClntPort;
+ UDP_PORT_t TFTPSrvPort;
+ uint16_t TFTPOpenTimeOut;
+ uint16_t TFTPReopenDelay;
+} __attribute__((__packed__)) t_PXENV_TFTP_READ_FILE;
+
+#define PXENV_TFTP_GET_FSIZE 0x0025
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAddress;
+ uint8_t FileName[128];
+ uint32_t FileSize;
+} __attribute__((__packed__)) t_PXENV_TFTP_GET_FSIZE;
+
+#define PXENV_UDP_OPEN 0x0030
+typedef struct {
+ PXENV_STATUS_t status;
+ IP4_t src_ip; /* IP address of this station */
+} __attribute__((__packed__)) t_PXENV_UDP_OPEN;
+
+#define PXENV_UDP_CLOSE 0x0031
+typedef struct {
+ PXENV_STATUS_t status;
+} __attribute__((__packed__)) t_PXENV_UDP_CLOSE;
+
+#define PXENV_UDP_READ 0x0032
+typedef struct {
+ PXENV_STATUS_t status;
+ IP4_t src_ip; /* IP of sender */
+ IP4_t dest_ip; /* Only accept packets sent to
+ this IP */
+ UDP_PORT_t s_port; /* UDP source port of sender */
+ UDP_PORT_t d_port; /* Only accept packets sent to
+ this port */
+ uint16_t buffer_size; /* Size of the packet buffer */
+ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
+} __attribute__((__packed__)) t_PXENV_UDP_READ;
+
+#define PXENV_UDP_WRITE 0x0033
+typedef struct {
+ PXENV_STATUS_t status;
+ IP4_t ip; /* dest ip addr */
+ IP4_t gw; /* ip gateway */
+ UDP_PORT_t src_port; /* source udp port */
+ UDP_PORT_t dst_port; /* destination udp port */
+ uint16_t buffer_size; /* Size of the packet buffer */
+ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
+} __attribute__((__packed__)) t_PXENV_UDP_WRITE;
+
+#define PXENV_UNLOAD_STACK 0x0070
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t reserved[10];
+} __attribute__((__packed__)) t_PXENV_UNLOAD_STACK;
+
+
+#define PXENV_GET_CACHED_INFO 0x0071
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t PacketType; /* type (defined right here) */
+# define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
+# define PXENV_PACKET_TYPE_DHCP_ACK 2
+# define PXENV_PACKET_TYPE_CACHED_REPLY 3
+ uint16_t BufferSize; /* max to copy, leave at 0 for
+ pointer */
+ SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */
+ uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */
+} __attribute__((__packed__)) t_PXENV_GET_CACHED_INFO;
+
+
+/* structure filled in by PXENV_GET_CACHED_INFO
+ * (how we determine which IP we downloaded the initial bootstrap from)
+ * words can't describe...
+ */
+typedef struct {
+ uint8_t opcode;
+# define BOOTP_REQ 1
+# define BOOTP_REP 2
+ uint8_t Hardware; /* hardware type */
+ uint8_t Hardlen; /* hardware addr len */
+ uint8_t Gatehops; /* zero it */
+ uint32_t ident; /* random number chosen by client */
+ uint16_t seconds; /* seconds since did initial
+ bootstrap */
+ uint16_t Flags; /* seconds since did initial
+ bootstrap */
+# define BOOTP_BCAST 0x8000 /* ? */
+ IP4_t cip; /* Client IP */
+ IP4_t yip; /* Your IP */
+ IP4_t sip; /* IP to use for next boot stage */
+ IP4_t gip; /* Relay IP ? */
+ MAC_ADDR CAddr; /* Client hardware address */
+ uint8_t Sname[64]; /* Server's hostname (Optional) */
+ uint8_t bootfile[128]; /* boot filename */
+ union {
+# if 1
+# define BOOTP_DHCPVEND 1024 /* DHCP extended vendor
+ field size */
+# else
+# define BOOTP_DHCPVEND 312 /* DHCP standard vendor
+ field size */
+# endif
+ uint8_t d[BOOTP_DHCPVEND]; /* raw array of
+ vendor/dhcp options */
+ struct {
+ uint8_t magic[4]; /* DHCP magic cookie */
+# ifndef VM_RFC1048
+# define VM_RFC1048 0x63825363L /* ? */
+# endif
+ uint32_t flags; /* bootp flags/opcodes */
+ uint8_t pad[56]; /* I don't think intel
+ knows what a union
+ does... */
+ } v;
+ } vendor;
+} __attribute__((__packed__)) BOOTPLAYER;
+
+#define PXENV_RESTART_TFTP 0x0073
+#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE
+
+#define PXENV_START_BASE 0x0075
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_START_BASE;
+
+#define PXENV_STOP_BASE 0x0076
+typedef struct {
+ PXENV_STATUS_t Status;
+} __attribute__((__packed__)) t_PXENV_STOP_BASE;
+
+#define PXENV_STATUS_SUCCESS 0
+#define PXENV_STATUS_FAILURE 1
+/* ...there are tons more, but we don't really care about them right now... */
diff --git a/sys/arch/i386/stand/libsa/pxe_call.S b/sys/arch/i386/stand/libsa/pxe_call.S
new file mode 100644
index 00000000000..5085b79b653
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe_call.S
@@ -0,0 +1,202 @@
+/* $OpenBSD: pxe_call.S,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD: pxe_call.S,v 1.2 2002/03/27 17:24:22 kanaoka Exp $ */
+
+/*
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ * Low level PXE BIOS call glue.
+ */
+
+#include <machine/asm.h>
+#include <assym.h>
+
+#include "gidt.h"
+
+ENTRY(pxecall_bangpxe)
+ .code32
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ /* For simplicity, just move all 32 bits. */
+ movl 8(%ebp), %ebx
+
+ pushw _C_LABEL(pxe_command_buf_seg)
+ pushw _C_LABEL(pxe_command_buf_off)
+ pushw %bx
+
+ call prot_to_real /* Enter real mode */
+ .code16
+
+ sti
+ /* The encoding is: 0x9a offlo offhi seglo seghi */
+ lcall $0, $0xffff
+ .globl _C_LABEL(bangpxe_off)
+_C_LABEL(bangpxe_off) = . - 4
+ .globl _C_LABEL(bangpxe_seg)
+_C_LABEL(bangpxe_seg) = . - 2
+
+ cli
+ call real_to_prot /* Leave real mode */
+ .code32
+
+ add $6, %esp
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %ebp
+ ret
+
+ENTRY(pxecall_pxenv)
+ .code32
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %edi
+
+ /* For simplicity, just move all 32 bits. */
+ movl 8(%ebp), %ebx
+
+ call prot_to_real /* Enter real mode */
+ .code16
+
+ /* prot_to_real() has already set %es to BOOTSEG */
+ lea _C_LABEL(pxe_command_buf), %di
+
+ /* The encoding is: 0x9a offlo offhi seglo seghi */
+ lcall $0, $0xffff
+ .globl _C_LABEL(pxenv_off)
+_C_LABEL(pxenv_off) = . - 4
+ .globl _C_LABEL(pxenv_seg)
+_C_LABEL(pxenv_seg) = . - 2
+
+ call real_to_prot /* Leave real mode */
+ .code32
+
+ popl %edi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * prot_to_real()
+ *
+ * Switch the processor back into real mode.
+ */
+ .globl prot_to_real
+prot_to_real:
+ .code32
+ ljmp $S16TEXT, $p2r16 - LINKADDR
+p2r16:
+ .code16
+
+ movw $S16DATA, %ax
+ movw %ax, %ds
+ movw %ax, %es
+
+ movl %cr0, %eax /* Disable protected mode */
+ andl $~CR0_PE, %eax
+ movl %eax, %cr0
+
+ /* reload real cs:ip */
+ data32 ljmp $(LINKADDR >> 4), $p2r16real - LINKADDR
+p2r16real:
+ xorw %ax, %ax /* Reset segment registers: */
+ movw %ax, %ds /* %ds: so we can get at Idtr_real */
+ movw %ax, %ss /* %ss: for our stack */
+
+ .extern Idtr_real
+ data32 addr32 lidt Idtr_real; /* Set up IDT for real mode */
+
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %es /* Set %ds = %es = %cs */
+
+ /*
+ * We were called from 32-bit mode, so there's a 32-bit
+ * return address on the stack. No segment. This is within
+ * the flat memory model, so we need to adjust it back so
+ * that it's relative to our 16-bit %cs.
+ */
+ popl %eax
+ subl $LINKADDR, %eax
+ pushw %ax
+ ret
+
+/*
+ * real_to_prot()
+ *
+ * Switch the processor back into protected mode.
+ */
+ .globl real_to_prot
+real_to_prot:
+ .code16
+
+ xorw %ax, %ax
+ movw %ax, %ds /* Load %ds so we can get at Gdtr */
+ data32 addr32 lgdt Gdtr /* Load the GDT */
+
+ movl %cr0, %eax /* Enable protected mode */
+ orl $CR0_PE, %eax
+ movl %eax, %cr0
+
+ data32 ljmp $S32TEXT, $r2p32 /* Reload %cs, flush pipeline */
+r2p32:
+ .code32
+ /* Reload 32-bit %ds, %ss, %es */
+ movl $S32DATA, %eax
+ mov %ax, %ds
+ mov %ax, %ss
+ mov %ax, %es
+
+ /* Load IDT for debugger and DOS/BIOS interface */
+ .extern Idtr
+ lidt Idtr
+
+ xorl %eax, %eax
+ popw %ax /* 16-bit return addr on stack */
+ addl $LINKADDR, %eax
+ pushl %eax /* Now have correct 32-bit ret addr */
+ ret
+
+ .end
diff --git a/sys/arch/i386/stand/libsa/pxe_net.c b/sys/arch/i386/stand/libsa/pxe_net.c
new file mode 100644
index 00000000000..df252771486
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe_net.c
@@ -0,0 +1,184 @@
+/* $OpenBSD: pxe_net.c,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD: dev_net.c,v 1.4 2003/03/12 13:15:08 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * This module implements a "raw device" interface suitable for
+ * use by the stand-alone I/O library NFS and TFTP code. This interface
+ * does not support any "block" access, and exists only for the
+ * purpose of initializing the network interface and getting boot
+ * parameters.
+ *
+ * At open time, this does:
+ *
+ * find interface - netif_open()
+ * BOOTP for IP address - bootp()
+ */
+
+#include <machine/stdarg.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libsa/net.h>
+#include "pxe_netif.h"
+#include "pxe_net.h"
+
+static int netdev_sock = -1;
+static int netdev_opens;
+
+int net_getparams(int);
+
+/*
+ * Called by devopen after it sets f->f_dev to our devsw entry.
+ * This opens the low-level device and sets f->f_devdata.
+ * This is declared with variable arguments...
+ */
+int
+net_open(struct open_file *f, ...)
+{
+ int error = 0;
+
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open()\n");
+#endif
+
+ /* On first open, do netif open, mount, etc. */
+ if (netdev_opens == 0) {
+ /* Find network interface. */
+ if (netdev_sock < 0) {
+ netdev_sock = pxe_netif_open();
+ if (netdev_sock < 0) {
+ printf("net_open: netif_open() failed\n");
+ return ENXIO;
+ }
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open: netif_open() succeeded\n");
+#endif
+ }
+#ifdef notyet
+ if (rootip.s_addr == 0) {
+ /* Get root IP address, and path, etc. */
+ error = net_getparams(netdev_sock);
+ if (error) {
+ /* getparams makes its own noise */
+ pxe_netif_close(netdev_sock);
+ netdev_sock = -1;
+ return error;
+ }
+ }
+#endif
+ }
+ netdev_opens++;
+ f->f_devdata = &netdev_sock;
+ return error;
+}
+
+int
+net_close(struct open_file *f)
+{
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_close: opens=%d\n", netdev_opens);
+#endif
+
+ /* On last close, do netif close, etc. */
+ f->f_devdata = NULL;
+ /* Extra close call? */
+ if (netdev_opens <= 0)
+ return 0;
+ netdev_opens--;
+ /* Not last close? */
+ if (netdev_opens > 0)
+ return 0;
+ rootip.s_addr = 0;
+ if (netdev_sock >= 0) {
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_close: calling netif_close()\n");
+#endif
+ pxe_netif_close(netdev_sock);
+ netdev_sock = -1;
+ }
+ return 0;
+}
+
+int
+net_ioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return EIO;
+}
+
+int
+net_strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ return EIO;
+}
+
+
+/*
+ * Get info for network boot: our IP address, our hostname,
+ * server IP address, and our root path on the server.
+ */
+extern int bootp(int);
+
+int
+net_getparams(int sock)
+{
+ /*
+ * Try to get boot info using BOOTP. If we succeed, then
+ * the server IP address, gateway, and root path will all
+ * be initialized. If any remain uninitialized, we will
+ * use RARP and RPC/bootparam (the Sun way) to get them.
+ */
+ bootp(sock);
+ if (myip.s_addr != 0)
+ return 0;
+ if (debug)
+ printf("net_getparams: BOOTP failed\n");
+
+ return EIO;
+}
diff --git a/sys/arch/i386/stand/libsa/pxe_net.h b/sys/arch/i386/stand/libsa/pxe_net.h
new file mode 100644
index 00000000000..406c15599c4
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe_net.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: pxe_net.h,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* pxe_net.c */
+int net_open(struct open_file *, ...);
+int net_close(struct open_file *);
+int net_ioctl(struct open_file *, u_long, void *);
+int net_strategy(void *, int , daddr_t , size_t, void *, size_t *);
diff --git a/sys/arch/i386/stand/libsa/pxe_netif.h b/sys/arch/i386/stand/libsa/pxe_netif.h
new file mode 100644
index 00000000000..b8cddcc9cc9
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxe_netif.h
@@ -0,0 +1,43 @@
+/* $OpenBSD: pxe_netif.h,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* pxe.c */
+int pxe_netif_open(void);
+void pxe_netif_close(int);
+void pxe_netif_shutdown(void);
diff --git a/sys/arch/i386/stand/libsa/pxeboot.h b/sys/arch/i386/stand/libsa/pxeboot.h
new file mode 100644
index 00000000000..e2a6a28f05c
--- /dev/null
+++ b/sys/arch/i386/stand/libsa/pxeboot.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: pxeboot.h,v 1.1 2004/03/19 13:48:18 tom Exp $ */
+/* $NetBSD$ */
+
+/*
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/* Flat address space for [pxe]boot in protected mode */
+#define VTOPSEG(vaddr) (((u_int32_t) vaddr) >> 4)
+#define VTOPOFF(vaddr) (((u_int32_t) vaddr) & 0xf)
+
+#define SEGOFF2FLAT(seg, off) ((void *)((((u_int32_t)(seg))<<4) + \
+ ((u_int32_t)(off))))
+
+void pxeprobe(void);
+void pxeinfo(void);
+
+ssize_t pxesendudp(struct iodesc *, void *, size_t);
+ssize_t pxereadudp(struct iodesc *, void *, size_t, time_t);
+
+int pxe_init(int);
+void pxe_shutdown(void);
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