diff options
Diffstat (limited to 'cfe/cfe/main/cfe_autoboot.c')
-rw-r--r-- | cfe/cfe/main/cfe_autoboot.c | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/cfe/cfe/main/cfe_autoboot.c b/cfe/cfe/main/cfe_autoboot.c new file mode 100644 index 0000000..14f3d3c --- /dev/null +++ b/cfe/cfe/main/cfe_autoboot.c @@ -0,0 +1,456 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Automatic OS bootstrap File: cfe_autoboot.c + * + * This module handles OS bootstrap stuff. We use this version + * to do "automatic" booting; walking down a list of possible boot + * options, trying them until something good happens. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "bsp_config.h" +#include "cfe_boot.h" + +#include "cfe_loader.h" + +#include "cfe_autoboot.h" + +/* ********************************************************************* + * data + ********************************************************************* */ + +queue_t cfe_autoboot_list = {&cfe_autoboot_list,&cfe_autoboot_list}; + +extern cfe_loadargs_t cfe_loadargs; /* from cfe_boot.c */ +extern const char *bootvar_device; +extern const char *bootvar_file; +extern const char *bootvar_flags; + +extern char *varchars; + +/* ********************************************************************* + * macroexpand(instr,outstr) + * + * Expand environment variables in "instr" to "outstr" + * + * Input parameters: + * instr - to be expanded + * outstr - expanded. + * + * Return value: + * nothing + ********************************************************************* */ + +static void macroexpand(char *instr,char *outstr) +{ + char macroname[50]; + char *m; + + while (*instr) { + if (*instr == '$') { + instr++; + m = macroname; + while (*instr && strchr(varchars,*instr)) { + *m++ = *instr++; + } + *m = '\0'; + m = env_getenv(macroname); + if (m) { + while (*m) *outstr++ = *m++; + } + } + else { + *outstr++ = *instr++; + } + } + + *outstr = '\0'; +} + +/* ********************************************************************* + * cfe_tryauto_common(method,loadargs) + * + * Common portion of autoboot + * + * Input parameters: + * method - details on device to boot from + * filename - canonical name of file to load + * loadargs - cfe_loadargs_t of digested load parameters. + * + * Return value: + * does not return if successful + ********************************************************************* */ + +static int cfe_tryauto_common(cfe_autoboot_method_t *method, + char *filename, + cfe_loadargs_t *la) +{ + int res; + + la->la_filename = filename; + la->la_options = env_getenv(bootvar_flags); + la->la_filesys = method->ab_filesys; + la->la_device = method->ab_dev; + la->la_flags = method->ab_flags | LOADFLG_NOISY | LOADFLG_EXECUTE; + la->la_address = 0; + la->la_maxsize = 0; + la->la_entrypt = 0; + + /* okay, go for it. */ + + xprintf("Loader:%s Filesys:%s Dev:%s File:%s Options:%s\n", + method->ab_loader,la->la_filesys,la->la_device,la->la_filename,la->la_options); + + res = cfe_boot(method->ab_loader,&cfe_loadargs); + + return res; + +} + + +/* ********************************************************************* + * cfe_tryauto_network(method) + * + * Try to autoboot from a network device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ + +#if CFG_NETWORK +static int cfe_tryauto_network(cfe_autoboot_method_t *method) +{ + int res; + dhcpreply_t *reply = NULL; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *x; + + /* + * First turn off any network interface that is currently active. + */ + + net_uninit(); + + /* + * Now activate the network hardware. + */ + + res = net_init(method->ab_dev); + if (res < 0) { + printf("Could not initialize network device %s: %s\n", + method->ab_dev, + cfe_errortext(res)); + return res; + } + + /* + * Do a DHCP query. + */ + + res = dhcp_bootrequest(&reply); + if (res < 0) { + printf("DHCP request failed on device %s: %s\n",method->ab_dev, + cfe_errortext(res)); + net_uninit(); + return res; + } + + net_setparam(NET_IPADDR,reply->dr_ipaddr); + net_setparam(NET_NETMASK,reply->dr_netmask); + net_setparam(NET_GATEWAY,reply->dr_gateway); + net_setparam(NET_NAMESERVER,reply->dr_nameserver); + net_setparam(NET_DOMAIN,reply->dr_domainname); + + /* Set all our environment variables. */ + net_setnetvars(); + dhcp_set_envvars(reply); + + if (reply) dhcp_free_reply(reply); + + /* + * Interface is now configured and ready, we can + * load programs now. + */ + + /* + * Construct the file name to load. If the method does not + * specify a file name directly, get it from DHCP. + * + * For network booting, the format of the file name + * is 'hostname:filename' + * + * If the method's filename includes a hostname, ignore + * BOOT_SERVER. Otherwise, combine BOOT_SERVER with the + * filename. This way we can provide the name here + * but have the file come off the server specified in the + * DHCP message. + */ + + if (method->ab_file && strchr(method->ab_file,':')) { + macroexpand(method->ab_file,buffer); + } + else { + buffer[0] = '\0'; + x = env_getenv("BOOT_SERVER"); + if (x) { + strcat(buffer,x); + strcat(buffer,":"); + } + + x = method->ab_file; + if (!x) x = env_getenv(bootvar_file); + if (x) { + strcat(buffer,x); + } + } + + /* Okay, do it. */ + + cfe_tryauto_common(method,buffer,la); + + /* If we get here, something bad happened. */ + + net_uninit(); + + return res; + +} + +#endif + + +/* ********************************************************************* + * cfe_tryauto_disk(method) + * + * Try to autoboot from a disk device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ +static int cfe_tryauto_disk(cfe_autoboot_method_t *method) +{ + int res; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *filename; + + buffer[0] = '\0'; + + if (method->ab_file) { + macroexpand(method->ab_file,buffer); + filename = buffer; + } + else { + filename = env_getenv("BOOT_FILE"); + if (filename) strcpy(buffer,filename); + } + + res = cfe_tryauto_common(method,filename,la); + + return res; +} + +/* ********************************************************************* + * cfe_tryauto(method) + * + * Try a single autoboot method. + * + * Input parameters: + * method - autoboot method to try + * + * Return value: + * does not return if bootstrap is successful + * else error code + ********************************************************************* */ + +static int cfe_tryauto(cfe_autoboot_method_t *method) +{ + switch (method->ab_type) { +#if CFG_NETWORK + case CFE_AUTOBOOT_NETWORK: + return cfe_tryauto_network(method); + break; +#endif + + case CFE_AUTOBOOT_DISK: + case CFE_AUTOBOOT_RAW: + return cfe_tryauto_disk(method); + break; + } + + return -1; +} + +/* ********************************************************************* + * cfe_autoboot(dev,flags) + * + * Try to perform an automatic system bootstrap + * + * Input parameters: + * dev - if not NULL, restrict bootstrap to named device + * flags - controls behaviour of cfe_autoboot + * + * Return value: + * should not return if bootstrap is successful, otherwise + * error code + ********************************************************************* */ +int cfe_autoboot(char *dev,int flags) +{ + queue_t *qb; + cfe_autoboot_method_t *method; + int res; + cfe_timer_t timer; + int forever; + int pollconsole; + + forever = (flags & CFE_AUTOFLG_TRYFOREVER) ? 1 : 0; + pollconsole = (flags & CFE_AUTOFLG_POLLCONSOLE) ? 1 : 0; + + do { /* potentially forever */ + for (qb = cfe_autoboot_list.q_next; qb != &cfe_autoboot_list; qb = qb->q_next) { + + method = (cfe_autoboot_method_t *) qb; + + /* + * Skip other devices if we passed in a specific one. + */ + + if (dev && (strcmp(dev,method->ab_dev) != 0)) continue; + + printf("\n*** Autoboot: Trying device '%s' ", method->ab_dev); + if (method->ab_file) printf("file %s ",method->ab_file); + printf("(%s,%s)\n\n",method->ab_dev,method->ab_filesys,method->ab_loader); + + /* + * Scan keyboard if requested. + */ + if (pollconsole) { + TIMER_SET(timer,CFE_HZ); + while (!TIMER_EXPIRED(timer)) { + POLL(); + if (console_status()) goto done; + } + } + + /* + * Try something. may not return. + */ + + res = cfe_tryauto(method); + } + } while (forever); + + /* bail. */ +done: + + printf("\n*** Autoboot failed.\n\n"); + + return -1; +} + + +/* ********************************************************************* + * cfe_add_autoboot(type,flags,dev,loader,filesys,file) + * + * Add an autoboot method to the table. + * This is typically called in the board_finalinit one or more + * times to provide a list of bootstrap methods to try for autoboot + * + * Input parameters: + * type - CFE_AUTOBOOT_xxx (disk,network,raw) + * flags - loader flags (LOADFLG_xxx) + * loader - loader string (elf, raw, srec) + * filesys - file system string (raw, tftp, fat) + * file - name of file to load (if null, will try to guess) + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int cfe_add_autoboot(int type,int flags,char *dev,char *loader,char *filesys,char *file) +{ + cfe_autoboot_method_t *method; + + method = (cfe_autoboot_method_t *) KMALLOC(sizeof(cfe_autoboot_method_t),0); + + if (!method) return CFE_ERR_NOMEM; + + method->ab_type = type; + method->ab_flags = flags; + method->ab_dev = dev; + method->ab_loader = loader; + method->ab_filesys = filesys; + method->ab_file = file; + + q_enqueue(&cfe_autoboot_list,(queue_t *)method); + return 0; +} |