diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ RELOC= 0x0 .PATH.S: ${.CURDIR}/../pxeboot .endif -SRCS= main.c dev_net.c devopen.c conf.c exec.c pxe.c pxe_call.S +SRCS= main.c dev_net.c devopen.c conf.c exec.c if_pxe.c pxe_call.S # use our own nfs implementation .PATH: ${.CURDIR}/../libsa SRCS+= nfs.c @@ -58,6 +58,7 @@ CPPFLAGS+= -DSUPPORT_SERIAL=CONSDEV_COM0 -DDIRECT_SERIAL CPPFLAGS+= -DSUPPORT_BOOTP -DSUPPORT_DHCP CPPFLAGS+= -DSUPPORT_TFTP CPPFLAGS+= -DSUPPORT_NFS +CPPFLAGS+= -DSUPPORT_HTTP #CPPFLAGS+= -DNFS_NOSYMLINK CPPFLAGS+= -DPASS_MEMMAP diff --git a/conf.c b/conf.c --- a/conf.c +++ b/conf.c @@ -43,9 +43,15 @@ #ifdef SUPPORT_NFS #include #endif + #ifdef SUPPORT_TFTP #include #endif + +#ifdef SUPPORT_HTTP +#include +#endif + #include #include "pxeboot.h" @@ -58,6 +64,10 @@ struct fs_ops file_system_nfs = FS_OPS(nfs); struct fs_ops file_system_tftp = FS_OPS(tftp); #endif +#ifdef SUPPORT_HTTP +struct fs_ops file_system_http = FS_OPS(http); +#endif + struct pxeboot_fstab pxeboot_fstab[] = { #ifdef SUPPORT_NFS { "nfs", &file_system_nfs }, @@ -65,6 +75,9 @@ struct pxeboot_fstab pxeboot_fstab[] = { #ifdef SUPPORT_TFTP { "tftp", &file_system_tftp }, #endif +#ifdef SUPPORT_HTTP + { "http", &file_system_http }, +#endif }; int npxeboot_fstab = sizeof(pxeboot_fstab) / sizeof(pxeboot_fstab[0]); @@ -76,3 +89,11 @@ struct devsw devsw[] = { { "net", net_strategy, net_open, net_close, net_ioctl }, }; int ndevs = sizeof(devsw) / sizeof(devsw[0]); +extern struct netif_driver pxe_netif_driver; + +struct netif_driver *netif_drivers[] = { + &pxe_netif_driver, +}; + +int n_netif_drivers = (sizeof(netif_drivers) / sizeof(netif_drivers[0])); + diff --git a/dev_net.c b/dev_net.c --- a/dev_net.c +++ b/dev_net.c @@ -53,7 +53,7 @@ #include #include -#include "pxe_netif.h" +#include #include "dev_net.h" static int netdev_sock = -1; @@ -71,16 +71,11 @@ 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(); + netdev_sock = netif_open(NULL); if (netdev_sock < 0) { printf("net_open: netif_open() failed\n"); return (ENXIO); @@ -93,7 +88,7 @@ net_open(struct open_file *f, ...) error = net_getparams(netdev_sock); if (error) { /* getparams makes its own noise */ - pxe_netif_close(netdev_sock); + netif_close(netdev_sock); netdev_sock = -1; return (error); } @@ -127,7 +122,7 @@ net_close(f) if (netdev_sock >= 0) { if (debug) printf("net_close: calling netif_close()\n"); - pxe_netif_close(netdev_sock); + netif_close(netdev_sock); //pxe_netif_shutdown(); /* XXX shouldn't be done here */ netdev_sock = -1; } diff --git a/if_pxe.c b/if_pxe.c --- /dev/null +++ b/if_pxe.c @@ -0,0 +1,492 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2010 Zoltan Arnold NAGY + * 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 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 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 + * All rights reserved. + * Copyright (c) 2000 Paul Saab + * All rights reserved. + * Copyright (c) 2000 John Baldwin + * 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. + */ + +/* + * a general netif driver for PXE, using it's UNDI network device + * should allow complete libsa integration, and this replaces + * the old UDP-only PXE driver (which was almost independent of libsa) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _STANDALONE +#include +#else +#include +#endif + + +int pxenetif_probe(struct netif *, void *); +int pxenetif_match(struct netif *, void *); +void pxenetif_init(struct iodesc *, void *); +int pxenetif_get(struct iodesc *, void *, size_t, time_t); +int pxenetif_put(struct iodesc *, void *, size_t); +void pxenetif_end(struct netif *); + +extern struct netif_stats pxenetif_stats[]; + +struct netif_dif pxenetif_ifs[] = { +/* dif_unit dif_nsel dif_stats dif_private */ + {0, 1, &pxenetif_stats[0], 0,}, +}; +#define PXENETIF_IFS (sizeof(pxenetif_ifs) / sizeof(pxenetif_ifs[0])) +#define VTOPSEG(vaddr) (vtophys(vaddr) >> 4) +#define VTOPOFF(vaddr) (vtophys(vaddr) & 0xf) + +struct netif_stats pxenetif_stats[PXENETIF_IFS]; + +struct netif_driver pxe_netif_driver = { + "pxe", + pxenetif_match, + pxenetif_probe, + pxenetif_init, + pxenetif_get, + pxenetif_put, + pxenetif_end, + pxenetif_ifs, + PXENETIF_IFS +}; +#include "pxe.h" + +void (*pxe_call) (uint16_t); + +void pxecall_bangpxe(uint16_t); /* pxe_call.S */ +void pxecall_pxenv(uint16_t); /* pxe_call.S */ + +static int pxe_inited; +static struct btinfo_netif bi_netif; +BOOTPLAYER bootplayer; +char pxe_command_buf[256]; + +int pxe_netif_open(struct iodesc *); +int pxe_init(void); +void pxe_netif_close(int); +void pxe_netif_shutdown(void); + +int +pxenetif_match(struct netif * nif, void *machdep_hint) +{ +#ifdef UNDI_DEBUG + printf("pxenetif_match called\n"); +#endif + return 1; +} + +int +pxenetif_probe(struct netif * nif, void *machdep_hint) +{ +#ifdef UNDI_DEBUG + printf("pxenetif_probe called\n"); +#endif + return 0; +} + +void +pxenetif_init(struct iodesc * desc, void *machdep_hint) +{ +#ifdef UNDI_DEBUG + printf("pxenetif_init called\n"); +#endif + if (!pxe_inited) { + if (pxe_init() != 0) + return; + pxe_inited = 1; + } +#ifdef UNDI_DEBUG + printf("general PXE stack initialization completed, setting up UNDI\n"); +#endif + pxe_netif_open(desc); +#ifdef UNDI_DEBUG + printf("UNDI initialization completed\n"); +#endif +} + +int +pxenetif_put(struct iodesc * desc, void *pkt, size_t len) +{ +#ifdef UNDI_DEBUG + printf("pxenetif_put called, len: %d\n", len); +#endif + t_PXENV_UNDI_TBD tbd; + memset(&tbd, 0, sizeof(t_PXENV_UNDI_TBD)); + tbd.ImmedLength = len; + tbd.Xmit.segment = VTOPSEG(pkt); + tbd.Xmit.offset = VTOPOFF(pkt); + tbd.DataBlkCount = 0; + + t_PXENV_UNDI_TRANSMIT *uo = (void *) pxe_command_buf; + memset(uo, 0, sizeof(t_PXENV_UNDI_TRANSMIT)); + + uo->Protocol = P_UNKNOWN; + if (strcmp(inet_ntoa(desc->destip), "255.255.255.255") == 0) + uo->XmitFlag = XMT_BROADCAST; + else { + uo->XmitFlag = XMT_DESTADDR; + } + uo->TBD.segment = VTOPSEG(&tbd); + uo->TBD.offset = VTOPOFF(&tbd); + + pxe_call(PXENV_UNDI_TRANSMIT); + + if (uo->Status != PXENV_STATUS_SUCCESS) { + printf("undi_startup: PXENV_UNDI_TRANSMIT failed: 0x%x\n", + uo->Status); + return -1; + } else { +#ifdef UNDI_DEBUG + printf("undi_startup: PXENV_UNDI_TRANSMIT succeeded\n"); +#endif + return len; + } +} + + +#define VIRTUAL(x,y) ((((x) << 4) + (y))) + +static int isr_state = 0; + +int +pxenetif_get(struct iodesc * desc, void *pkt, size_t len, time_t timeout) +{ +#ifdef UNDI_DEBUG + printf("pxenetif_get called, len: %d\n", len); +#endif + t_PXENV_UNDI_ISR *uo = (void *) pxe_command_buf; + memset(uo, 0, sizeof(t_PXENV_UNDI_ISR)); + + if (isr_state == 0) { + while (1) { + uo->FuncFlag = PXENV_UNDI_ISR_IN_START; + pxe_call(PXENV_UNDI_ISR); + if (uo->Status != PXENV_STATUS_SUCCESS) { + printf("undi_startup: PXENV_UNDI_ISR failed: 0x%x\n", uo->Status); + return -1; + } + if (uo->FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OUTS) { + return -1; + } + isr_state = 1; + break; + } + } + int rc = 0; + if (isr_state == 1) + uo->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; + else if (isr_state == 2) + uo->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + + pxe_call(PXENV_UNDI_ISR); + if (uo->Status != PXENV_STATUS_SUCCESS) { + printf("pxenetif_get: PXENV_UNDI_ISR_IN_PROCESS failed: 0x%x\n", uo->Status); + isr_state = 0; + return -1; + } +#ifdef UNDI_DEBUG + printf("-- bufferlength: %d, framelength: %d\n", uo->BufferLength, uo->FrameLength); +#endif + if (uo->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { +#ifdef UNDI_DEBUG + printf("pxenetif_get: PXENV_UNDI_ISR_OUT_DONE\n"); +#endif + isr_state = 0; + } else if (uo->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) { +#ifdef UNDI_DEBUG + printf("pxenetif_get: PXENV_UNDI_ISR_OUT_TRANSMIT\n"); +#endif + uo->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + } else if (uo->FuncFlag == PXENV_UNDI_ISR_OUT_RECIEVE) { + pvbcopy((void *) ((uo->Frame.segment << 4) + uo->Frame.offset), pkt + rc, uo->BufferLength); + rc = uo->BufferLength; + isr_state = 2; + } else if (uo->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) { +#ifdef UNDI_DEBUG + printf("pxenetif_get: PXENV_UNDI_ISR_OUT_BUSY\n"); +#endif + isr_state = 0; + return -1; + } +#ifdef UNDI_DEBUG + printf("bufferlength: %d, framelength: %d\n", uo->BufferLength, uo->FrameLength); + printf("received UNDI packet, total length: %d\n", rc); +#endif + return rc; +} + +void +pxenetif_end(struct netif * nif) +{ + printf("pxenetif_end called!\n"); +} + +void undi_open(void); + +void +undi_open() +{ + t_PXENV_UNDI_OPEN *uo = (void *) pxe_command_buf; + pxe_call(PXENV_UNDI_OPEN); + if (uo->Status != PXENV_STATUS_SUCCESS) { + printf("undi_startup: PXENV_UNDI_OPEN failed: 0x%x\n", uo->Status); + } else + printf("undi_startup: PXENV_UNDI_OPEN succeeded\n"); +} + +int +pxe_netif_open(struct iodesc * desc) +{ + BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); + bcopy(bootplayer.CAddr, desc->myea, ETHER_ADDR_LEN); + desc->xid = bootplayer.ident; + undi_open(); + return 0; +} + +uint16_t pxe_command_buf_seg; +uint16_t pxe_command_buf_off; + +extern uint16_t bangpxe_off, bangpxe_seg; +extern uint16_t pxenv_off, pxenv_seg; + +static struct btinfo_netif bi_netif; + +int +pxe_init(void) +{ + t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf; + t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf; + pxenv_t *pxenv; + pxe_t *pxe; + char *cp; + int i; + uint8_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 (MEMSTRCMP(pxenv->Signature, "PXENV+")) + pxenv = NULL; + else { + for (i = 0, ucp = (uint8_t *) cp, cksum = 0; + i < pxenv->Length; i++) + cksum += ucp[i]; + if (cksum != 0) { + printf("pxe_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 (MEMSTRCMP(pxe->Signature, "!PXE")) + pxe = NULL; + else { + for (i = 0, ucp = (uint8_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) { + printf("pxe_init: No PXE BIOS found.\n"); + return (1); + } + if (pxenv != NULL) { + printf("PXE BIOS Version %d.%d\n", + (pxenv->Version >> 8) & 0xff, pxenv->Version & 0xff); + if (pxenv->Version >= 0x0201 && pxe != NULL) { + /* 2.1 or greater -- don't use PXENV+ */ + 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_BINL_REPLY; + pxe_call(PXENV_GET_CACHED_INFO); + if (gci->Status != PXENV_STATUS_SUCCESS) { + printf("pxe_init: PXENV_GET_CACHED_INFO failed: 0x%x\n", + gci->Status); + return (1); + } + pvbcopy((void *) ((gci->Buffer.segment << 4) + gci->Buffer.offset), &bootplayer, gci->BufferSize); + + /* + * Get network interface information. + */ + bzero(gnt, sizeof(*gnt)); + pxe_call(PXENV_UNDI_GET_NIC_TYPE); + + if (gnt->Status != PXENV_STATUS_SUCCESS) { + printf("pxe_init: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n", + gnt->Status); + return (0); + } + 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("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("Using PnP device at 0x%x\n", gnt->info.pnp.CardSelNum); + } + + printf("Ethernet address %s\n", ether_sprintf(bootplayer.CAddr)); + + return (0); +} diff --git a/main.c b/main.c --- a/main.c +++ b/main.c @@ -114,7 +114,9 @@ main(void) printf("Press return to boot now, any other key for boot menu\n"); printf("Starting in "); - + + boot_params.bp_timeout = 0; + c = awaitkey(boot_params.bp_timeout, 1); if ((c != '\r') && (c != '\n') && (c != '\0')) { printf("type \"?\" or \"help\" for help.\n"); diff --git a/pxe.c b/pxe.c --- a/pxe.c +++ /dev/null @@ -1,447 +0,0 @@ -/* $NetBSD: pxe.c,v 1.10 2006/04/14 05:32:26 dyoung 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 - * All rights reserved. - * Copyright (c) 2000 Paul Saab - * All rights reserved. - * Copyright (c) 2000 John Baldwin - * 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 -#include - -#ifdef _STANDALONE -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "pxeboot.h" -#include "pxe.h" -#include "pxe_netif.h" - -void (*pxe_call)(uint16_t); - -void pxecall_bangpxe(uint16_t); /* pxe_call.S */ -void pxecall_pxenv(uint16_t); /* pxe_call.S */ - -char pxe_command_buf[256]; - -BOOTPLAYER bootplayer; - -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 -sendudp(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 -readudp(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; - - if (!pxe_inited) { - if (pxe_init() != 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_probe: 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() -{ - - pxe_fini(); -} - -struct iodesc * -socktodesc(sock) - int sock; -{ - -#ifdef NETIF_DEBUG - if (sock != 0) - return (0); - else -#endif - return (&desc); -} - -/***************************************************************************** - * PXE initialization and support routines - *****************************************************************************/ - -uint16_t pxe_command_buf_seg; -uint16_t pxe_command_buf_off; - -extern uint16_t bangpxe_off, bangpxe_seg; -extern uint16_t pxenv_off, pxenv_seg; - -static struct btinfo_netif bi_netif; - -int -pxe_init(void) -{ - t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf; - t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf; - pxenv_t *pxenv; - pxe_t *pxe; - char *cp; - int i; - uint8_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 (MEMSTRCMP(pxenv->Signature, "PXENV+")) - pxenv = NULL; - else { - for (i = 0, ucp = (uint8_t *)cp, cksum = 0; - i < pxenv->Length; i++) - cksum += ucp[i]; - if (cksum != 0) { - printf("pxe_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 (MEMSTRCMP(pxe->Signature, "!PXE")) - pxe = NULL; - else { - for (i = 0, ucp = (uint8_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) { - printf("pxe_init: No PXE BIOS found.\n"); - return (1); - } - - if (pxenv != NULL) { - printf("PXE BIOS Version %d.%d\n", - (pxenv->Version >> 8) & 0xff, pxenv->Version & 0xff); - if (pxenv->Version >= 0x0201 && pxe != NULL) { - /* 2.1 or greater -- don't use PXENV+ */ - 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_BINL_REPLY; - pxe_call(PXENV_GET_CACHED_INFO); - if (gci->Status != PXENV_STATUS_SUCCESS) { - printf("pxe_init: PXENV_GET_CACHED_INFO failed: 0x%x\n", - gci->Status); - return (1); - } - pvbcopy((void *)((gci->Buffer.segment << 4) + gci->Buffer.offset), - &bootplayer, gci->BufferSize); - - /* - * Get network interface information. - */ - bzero(gnt, sizeof(*gnt)); - pxe_call(PXENV_UNDI_GET_NIC_TYPE); - - if (gnt->Status != PXENV_STATUS_SUCCESS) { - printf("pxe_init: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n", - gnt->Status); - return (0); - } - - 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("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("Using PnP device at 0x%x\n", gnt->info.pnp.CardSelNum); - } - - printf("Ethernet address %s\n", ether_sprintf(bootplayer.CAddr)); - - return (0); -} - -void -pxe_fini(void) -{ - t_PXENV_UNDI_SHUTDOWN *shutdown = (void *) pxe_command_buf; - - if (pxe_call == NULL) - return; - - pxe_call(PXENV_UNDI_SHUTDOWN); - - if (shutdown->Status != PXENV_STATUS_SUCCESS) - printf("pxe_fini: PXENV_UNDI_SHUTDOWN failed: 0x%x\n", - shutdown->Status); -}