diff options
27 files changed, 3482 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 diff --git a/sys/lib/libsa/tftp.c b/sys/lib/libsa/tftp.c new file mode 100644 index 00000000000..c5c8ccc4bba --- /dev/null +++ b/sys/lib/libsa/tftp.c @@ -0,0 +1,434 @@ +/* $OpenBSD: tftp.c,v 1.1 2004/03/19 13:48:20 tom Exp $ */ +/* $NetBSD: tftp.c,v 1.15 2003/08/18 15:45:29 dsl Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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. + */ + +/* + * Simple TFTP implementation for libsa. + * Assumes: + * - socket descriptor (int) at open_file->f_devdata + * - server host IP in global servip + * Restrictions: + * - read only + * - lseek only with SEEK_SET or SEEK_CUR + * - no big time differences between transfers (<tftp timeout) + */ + +/* + * XXX Does not currently implement: + * XXX + * XXX LIBSA_NO_FS_CLOSE + * XXX LIBSA_NO_FS_SEEK + * XXX LIBSA_NO_FS_WRITE + * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?) + * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?) + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netinet/udp.h> +#include <netinet/in_systm.h> +#include <lib/libkern/libkern.h> + +#include "stand.h" +#include "net.h" +#include "netif.h" + +#include "tftp.h" + +extern struct in_addr servip; + +static int tftpport = 2000; + +#define RSPACE 520 /* max data packet, rounded up */ + +struct tftp_handle { + struct iodesc *iodesc; + int currblock; /* contents of lastdata */ + int islastblock; /* flag */ + int validsize; + int off; + const char *path; /* saved for re-requests */ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + u_char space[RSPACE]; + } lastdata; +}; + +static const int tftperrors[8] = { + 0, /* ??? */ + ENOENT, + EPERM, + ENOSPC, + EINVAL, /* ??? */ + EINVAL, /* ??? */ + EEXIST, + EINVAL /* ??? */ +}; + +ssize_t recvtftp(struct iodesc *, void *, size_t, time_t); +int tftp_makereq(struct tftp_handle *); +int tftp_getnextblock(struct tftp_handle *); +#ifndef TFTP_NOTERMINATE +void tftp_terminate(struct tftp_handle *); +#endif + +ssize_t +recvtftp(struct iodesc *d, void *pkt, size_t len, time_t tleft) +{ + ssize_t n; + struct tftphdr *t; + + errno = 0; + + n = readudp(d, pkt, len, tleft); + + if (n < 4) + return -1; + + t = (struct tftphdr *) pkt; + switch (ntohs(t->th_opcode)) { + case DATA: + if (htons(t->th_block) != d->xid) { + /* + * Expected block? + */ + return -1; + } + if (d->xid == 1) { + /* + * First data packet from new port. + */ + struct udphdr *uh; + uh = (struct udphdr *) pkt - 1; + d->destport = uh->uh_sport; + } /* else check uh_sport has not changed??? */ + return (n - (t->th_data - (char *)t)); + case ERROR: + if ((unsigned) ntohs(t->th_code) >= 8) { + printf("illegal tftp error %d\n", ntohs(t->th_code)); + errno = EIO; + } else { +#ifdef DEBUG + printf("tftp-error %d\n", ntohs(t->th_code)); +#endif + errno = tftperrors[ntohs(t->th_code)]; + } + return -1; + default: +#ifdef DEBUG + printf("tftp type %d not handled\n", ntohs(t->th_opcode)); +#endif + return -1; + } +} + +/* send request, expect first block (or error) */ +int +tftp_makereq(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + u_char space[FNAME_SIZE + 6]; + } wbuf; + char *wtail; + int l; + ssize_t res; + struct tftphdr *t; + + bzero(&wbuf, sizeof(wbuf)); + + wbuf.t.th_opcode = htons((u_short) RRQ); + wtail = wbuf.t.th_stuff; + l = strlen(h->path); + bcopy(h->path, wtail, l + 1); + wtail += l + 1; + bcopy("octet", wtail, 6); + wtail += 6; + + t = &h->lastdata.t; + + /* h->iodesc->myport = htons(--tftpport); */ + h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); + h->iodesc->destport = htons(IPPORT_TFTP); + h->iodesc->xid = 1; /* expected block */ + + res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + recvtftp, t, sizeof(*t) + RSPACE); + + if (res == -1) + return errno; + + h->currblock = 1; + h->validsize = res; + h->islastblock = 0; + if (res < SEGSIZE) + h->islastblock = 1; /* very short file */ + return 0; +} + +/* ack block, expect next */ +int +tftp_getnextblock(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + } wbuf; + char *wtail; + int res; + struct tftphdr *t; + + bzero(&wbuf, sizeof(wbuf)); + + wbuf.t.th_opcode = htons((u_short) ACK); + wbuf.t.th_block = htons((u_short) h->currblock); + wtail = (char *) &wbuf.t.th_data; + + t = &h->lastdata.t; + + h->iodesc->xid = h->currblock + 1; /* expected block */ + + res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + recvtftp, t, sizeof(*t) + RSPACE); + + if (res == -1) /* 0 is OK! */ + return errno; + + h->currblock++; + h->validsize = res; + if (res < SEGSIZE) + h->islastblock = 1; /* EOF */ + return 0; +} + +#ifndef TFTP_NOTERMINATE +void +tftp_terminate(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + } wbuf; + char *wtail; + + bzero(&wbuf, sizeof(wbuf)); + + if (h->islastblock) { + wbuf.t.th_opcode = htons((u_short) ACK); + wbuf.t.th_block = htons((u_short) h->currblock); + } else { + wbuf.t.th_opcode = htons((u_short) ERROR); + wbuf.t.th_code = htons((u_short) ENOSPACE); /* ??? */ + } + wtail = (char *) &wbuf.t.th_data; + + (void) sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); +} +#endif + +int +tftp_open(char *path, struct open_file *f) +{ + struct tftp_handle *tftpfile; + struct iodesc *io; + int res; + + tftpfile = (struct tftp_handle *) alloc(sizeof(*tftpfile)); + if (tftpfile == NULL) + return ENOMEM; + + tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); + io->destip = servip; + tftpfile->off = 0; + tftpfile->path = path; /* XXXXXXX we hope it's static */ + + res = tftp_makereq(tftpfile); + + if (res) { + free(tftpfile, sizeof(*tftpfile)); + return res; + } + f->f_fsdata = (void *) tftpfile; + return 0; +} + +int +tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + struct tftp_handle *tftpfile; +#if !defined(LIBSA_NO_TWIDDLE) + static int tc = 0; +#endif + tftpfile = (struct tftp_handle *) f->f_fsdata; + + while (size > 0) { + int needblock; + size_t count; + + needblock = tftpfile->off / SEGSIZE + 1; + + if (tftpfile->currblock > needblock) { /* seek backwards */ +#ifndef TFTP_NOTERMINATE + tftp_terminate(tftpfile); +#endif + /* Don't bother to check retval: it worked for open() */ + tftp_makereq(tftpfile); + } + + while (tftpfile->currblock < needblock) { + int res; + +#if !defined(LIBSA_NO_TWIDDLE) + if ((tc++ % 16) == 0) + twiddle(); +#endif + res = tftp_getnextblock(tftpfile); + if (res) { /* no answer */ +#ifdef DEBUG + printf("tftp: read error (block %d->%d)\n", + tftpfile->currblock, needblock); +#endif + return res; + } + if (tftpfile->islastblock) + break; + } + + if (tftpfile->currblock == needblock) { + size_t offinblock, inbuffer; + + offinblock = tftpfile->off % SEGSIZE; + + inbuffer = tftpfile->validsize - offinblock; + if (inbuffer < 0) { +#ifdef DEBUG + printf("tftp: invalid offset %d\n", + tftpfile->off); +#endif + return EINVAL; + } + count = (size < inbuffer ? size : inbuffer); + bcopy(tftpfile->lastdata.t.th_data + offinblock, + addr, count); + + addr = (caddr_t)addr + count; + tftpfile->off += count; + size -= count; + + if ((tftpfile->islastblock) && (count == inbuffer)) + break; /* EOF */ + } else { +#ifdef DEBUG + printf("tftp: block %d not found\n", needblock); +#endif + return EINVAL; + } + + } + + if (resid != NULL) + *resid = size; + return 0; +} + +int +tftp_close(struct open_file *f) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + +#ifdef TFTP_NOTERMINATE + /* let it time out ... */ +#else + tftp_terminate(tftpfile); +#endif + + free(tftpfile, sizeof(*tftpfile)); + return 0; +} + +int +tftp_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + return EROFS; +} + +int +tftp_stat(struct open_file *f, struct stat *sb) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + sb->st_mode = 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_size = -1; + + return 0; +} + +off_t +tftp_seek(struct open_file *f, off_t offset, int where) +{ + struct tftp_handle *tftpfile; + tftpfile = (struct tftp_handle *) f->f_fsdata; + + switch (where) { + case SEEK_SET: + tftpfile->off = offset; + break; + case SEEK_CUR: + tftpfile->off += offset; + break; + default: + errno = EOFFSET; + return -1; + } + + return (tftpfile->off); +} + +/* + * Not implemented. + */ +#ifndef NO_READDIR +int +tftp_readdir(struct open_file *f, char *name) +{ + return EROFS; +} +#endif diff --git a/sys/lib/libsa/tftp.h b/sys/lib/libsa/tftp.h new file mode 100644 index 00000000000..d72b2c16234 --- /dev/null +++ b/sys/lib/libsa/tftp.h @@ -0,0 +1,120 @@ +/* $OpenBSD: tftp.h,v 1.1 2004/03/19 13:48:20 tom Exp $ */ +/* $NetBSD: tftp.h,v 1.3 2003/08/07 16:32:30 agc Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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. + * + */ + +/* NetBSD: tftp.h,v 1.6 2000/10/18 01:35:46 dogcow Exp */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)tftp.h 8.1 (Berkeley) 6/2/93 + */ +/* + * Trivial File Transfer Protocol (IEN-133) + */ +#define SEGSIZE 512 /* data segment size */ + +/* + * Packet types. + */ +#define RRQ 01 /* read request */ +#define WRQ 02 /* write request */ +#define DATA 03 /* data packet */ +#define ACK 04 /* acknowledgement */ +#define ERROR 05 /* error code */ + +struct tftphdr { + short th_opcode; /* packet type */ + union { + unsigned short tu_block; /* block # */ + short tu_code; /* error code */ + char tu_stuff[1]; /* request packet stuff */ + } th_u; + char th_data[1]; /* data or error string */ +}; + +#define th_block th_u.tu_block +#define th_code th_u.tu_code +#define th_stuff th_u.tu_stuff +#define th_msg th_data + +/* + * Error codes. + */ +#define EUNDEF 0 /* not defined */ +#define ENOTFOUND 1 /* file not found */ +#define EACCESS 2 /* access violation */ +#define ENOSPACE 3 /* disk full or allocation exceeded */ +#define EBADOP 4 /* illegal TFTP operation */ +#define EBADID 5 /* unknown transfer ID */ +#define EEXISTS 6 /* file already exists */ +#define ENOUSER 7 /* no such user */ + +/* FS_DEF(tftp); */ + +int tftp_open(char *, struct open_file *); +int tftp_close(struct open_file *); +int tftp_read(struct open_file *, void *, size_t, size_t *); +int tftp_write(struct open_file *, void *, size_t, size_t *); +off_t tftp_seek(struct open_file *, off_t, int); +int tftp_stat(struct open_file *, struct stat *); +int tftp_mount(int, struct in_addr, char *); +int tftp_readdir(struct open_file *, char *); + +#define IPPORT_TFTP 69 |