/* ************************************************************************** * * Boot-ROM-Code to load an operating system across a TCP/IP network. * * Module: boot.c * Purpose: Perform the actual booting process * Entries: do_boot * ************************************************************************** * * Copyright (C) 1995-2003 Gero Kuhlmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: boot.c,v 1.6 2003/01/25 23:29:41 gkminix Exp $ */ #include #include #include #include #include #include #include "bootpriv.h" #include "menu.h" #include "load.h" /* ************************************************************************** * * Variables local to this module */ static jmp_buf restartenv; /* setjmp buffer for restart */ /* ************************************************************************** * * Print an IP number. Note that the IP address should be in network * order. */ static void printip(ip) t_ipaddr ip; { register unsigned char *cp = (unsigned char *)&ip; printf("%u.%u.%u.%u", cp[0], cp[1], cp[2], cp[3]); } /* ************************************************************************** * * Set parameters from BOOTP record */ static int setparams() { register unsigned char *cp; register int len; unsigned char *sname; int snamlen; int overload = 0; cur_bootp_buf = BOOTP_REPLY; memset(&ldparams, 0, sizeof(ldparams)); /* Get the overloading tag */ if ((cp = get_vend(VEND_OVERLOAD)) != NULL) overload = *(cp + 1); /* Determine the IP address of the TFTP server */ if ((cp = get_vend(VEND_SERVER)) != NULL) ldparams.tftp.server = *((t_ipaddr *)(cp + 1)); else ldparams.tftp.server = bootp_bufs[BOOTP_REPLY]->bp_siaddr; if (ldparams.tftp.server == n_IP_ANY) return(PXENV_STATUS_DHCP_NO_IP_ADDR); /* Determine name of server the boot image file will come from */ if ((cp = get_vend(VEND_TFTPNAME)) != NULL) { sname = cp + 1; snamlen = *cp; } else if (!(overload & VEND_OVR_SNAME)) { sname = bootp_bufs[BOOTP_REPLY]->bp_sname; snamlen = BOOTP_SNAME_SIZE; } else sname = NULL; /* Determine name of boot image file to load */ if ((cp = get_vend(VEND_BOOTFILE)) != NULL) { len = *cp; if (len > sizeof(ldparams.tftp.filename)) len = sizeof(ldparams.tftp.filename); memcpy(ldparams.tftp.filename, cp + 1, len); } else if (!(overload & VEND_OVR_FILE)) memcpy(ldparams.tftp.filename, bootp_bufs[BOOTP_REPLY]->bp_file, sizeof(ldparams.tftp.filename)); if (ldparams.tftp.filename[0] == '\0') return(PXENV_STATUS_DHCP_NO_FILE); /* Get any router information */ if ((cp = get_vend(VEND_ROUTER)) != NULL) ldparams.tftp.gateway = *((t_ipaddr *)(cp + 1)); /* Print some of the information we got so far */ printf("\n\nLocal IP: "); printip(myipaddr); printf("\nServer IP: "); printip(ldparams.tftp.server); if (sname != NULL) printf(" (%ls)", sname, snamlen); if (ldparams.tftp.gateway != n_IP_ANY) { printf("\nGateway IP: "); printip(ldparams.tftp.gateway); } printf("\n"); return(PXENV_STATUS_SUCCESS); } /* ************************************************************************** * * Actually perform the booting process by first calling the BOOTP client, * and then loading the operating system using TFTP. This routine gets * called from the assembler startup code. * */ int do_boot() { int ret; /* Wait some seconds for the network card to settle down */ set_timeout(3); while (!chk_timeout()) ; /* Now start the network booting process */ if ((ret = bootp()) == PXENV_STATUS_SUCCESS) { #ifndef NOMENU if (domenu() != MENU_ABORT) { #endif while ((ret = setparams()) == PXENV_STATUS_SUCCESS) { if ((ret = load(FALSE)) != PXENV_STATUS_SUCCESS) break; printf("\n\nStarting image...\n"); setjmp(&restartenv); if (!exec_image(ldparams.mode, ldparams.exec, ldparams.header, bootp_bufs[BOOTP_REPLY], ldparams.drive)) { ret = PXENV_STATUS_SUCCESS; break; } } #ifndef NOMENU } #endif } return(ret); } /* ************************************************************************** * * Restart TFTP PXE function */ int pxe_restart(params) t_tftp_read_file *params; { register int ret = PXENV_STATUS_FAILURE; memset(&ldparams, 0, sizeof(ldparams)); memcpy(&ldparams.tftp, params, sizeof(ldparams.tftp)); if ((ret = load(TRUE)) == PXENV_STATUS_SUCCESS) /* * We have to use longjump here to jump back to the original * bootrom loader code. Otherwise, the bootrom stack will * overflow with multiple calls of this routine. */ longjmp(&restartenv, 0); return(ret); } /* ************************************************************************** * * Return BOOTP/DHCP information */ int pxe_get_binl_info(params) t_gen_get_binl_info *params; { register unsigned char *cp = NULL; unsigned int len, limit, ret; ret = PXENV_STATUS_FAILURE; if (params->packet_type >= GEN_PACKET_DHCP_DISCOVER && params->packet_type <= GEN_PACKET_BINL_REPLY) { cur_bootp_buf = params->packet_type - 1; cp = (unsigned char *)(bootp_bufs[cur_bootp_buf]); limit = bootp_sizes[cur_bootp_buf]; len = get_vend(VEND_END) - cp; if ((params->buffer_offset + params->buffer_segment + params->buffer_size) == 0) { params->buffer_size = len; params->buffer_offset = (unsigned int)cp; params->buffer_segment = getds(); params->buffer_limit = limit; ret = PXENV_STATUS_SUCCESS; } else if (params->buffer_size >= len) { fmemcpy(params->buffer_offset, params->buffer_segment, cp, len); params->buffer_size = len; params->buffer_limit = limit; ret = PXENV_STATUS_SUCCESS; } } return(ret); }