/* $NetBSD: boot.c,v 1.4 2015/12/13 18:24:50 christos Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code was written by Alessandro Forin and Neil Pittman * at Microsoft Research and contributed to The NetBSD Foundation * by Microsoft Corporation. * * 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 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. */ #include #include #include #include #include #include #include "common.h" #include "bootinfo.h" #include "start.h" /* * We won't go overboard with gzip'd kernel names. After all we can * still boot a gzip'd kernel called "netbsd.emips" - it doesn't need * the .gz suffix. */ char *kernelnames[] = { "netbsd", "netbsd.gz", "netbsd.old", "onetbsd", "gennetbsd", "nfsnetbsd", NULL }; void main (char *); char *getboot(char *, char*); static int devcanon(char *); #define OPT_MAX PATH_MAX /* way overkill */ static int loadit(char *name, u_long *marks) { printf("Loading: %s\n", name); memset(marks, 0, sizeof(*marks) * MARK_MAX); return (loadfile(name, marks, LOAD_ALL)); } /* * The locore in start.S calls us with an 8KB stack carved after _end. * */ void main(char *stack_top) { int autoboot = 1, win; char *name, **namep, *dev, *kernel; char bootpath[PATH_MAX], options[OPT_MAX]; uint32_t entry; u_long marks[MARK_MAX]; struct btinfo_symtab bi_syms; struct btinfo_bootpath bi_bpath; /* Init all peripherals, esp USART for printf and memory */ init_board(); /* On account of compression, we need a fairly large heap. * To keep things simple, take one meg just below the 16 meg mark. * That allows for a large kernel, and a 16MB configuration still works. */ setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000); /* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete * and switching the serial line to PuTTY as console. Get a char to pause. * This delay is also the practice on PCs so. */ Delay(200000); printf("Hit any char to boot.."); (void)GetChar(); /* print a banner */ printf("\n"); printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n", bootprog_rev); /* initialise bootinfo structure early */ bi_init(BOOTINFO_ADDR); /* Default is to auto-boot from the first disk */ dev = "0/ace(0,0)/"; kernel = kernelnames[0]; options[0] = 0; win = 0; for (;!win;) { strcpy(bootpath, dev); strcat(bootpath, kernel); name = getboot(bootpath,options); if (name != NULL) { win = (loadit(name, marks) == 0); } else if (autoboot) break; autoboot = 0; } if (!win) { for (namep = kernelnames, win = 0; *namep != NULL && !win; namep++) { kernel = *namep; strcpy(bootpath, dev); strcat(bootpath, kernel); win = (loadit(bootpath, marks) == 0); if (win) { name = bootpath; } } } if (!win) goto fail; strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN); bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); entry = marks[MARK_ENTRY]; bi_syms.nsym = marks[MARK_NSYM]; bi_syms.ssym = marks[MARK_SYM]; bi_syms.esym = marks[MARK_END]; bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); printf("Starting at 0x%x\n\n", entry); call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo); (void)printf("KERNEL RETURNED!\n"); fail: (void)printf("Boot failed! Halting...\n"); } static inline int parse(char *cmd, char *kname, char *optarg) { char *arg = cmd; char *ep, *p; int c, i; while ((c = *arg++)) { /* skip leading blanks */ if (c == ' ' || c == '\t' || c == '\n') continue; /* find separator, or eol */ for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); ep = p; /* trim if separator */ if (*p) *p++ = 0; /* token is either "-opts" or "kernelname" */ if (c == '-') { /* no overflow because whole line same length as optarg anyways */ while ((c = *arg++)) { *optarg++ = c; } *optarg = 0; } else { arg--; if ((i = ep - arg)) { if ((size_t)i >= PATH_MAX) return -1; memcpy(kname, arg, i + 1); } } arg = p; } return 0; } /* String returned is zero-terminated and at most PATH_MAX chars */ static inline void getstr(char *cmd, int c) { char *s; s = cmd; if (c == 0) c = GetChar(); for (;;) { switch (c) { case 0: break; case '\177': case '\b': if (s > cmd) { s--; printf("\b \b"); } break; case '\n': case '\r': *s = 0; return; default: if ((s - cmd) < (PATH_MAX - 1)) *s++ = c; xputchar(c); } c = GetChar(); } } char *getboot(char *kname, char* optarg) { char c = 0; char cmd[PATH_MAX]; printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname); if ((c = GetChar()) == -1) return NULL; cmd[0] = 0; getstr(cmd,c); xputchar('\n'); if (parse(cmd,kname,optarg)) xputchar('\a'); else if (devcanon(kname) == 0) return kname; return NULL; } /* * Make bootpath canonical, provides defaults when missing */ static int devcanon(char *fname) { int ctlr = 0, unit = 0, part = 0; int c; char device_name[20]; char file_name[PATH_MAX]; const char *cp; char *ncp; //printf("devcanon(%s)\n",fname); cp = fname; ncp = device_name; /* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file * Defaults: ctrl=0, name='ace', unit=0, part=0, file= */ /* get controller number */ if ((c = *cp) >= '0' && c <= '9') { ctlr = c - '0'; c = *++cp; if (c != '/') return (ENXIO); c = *++cp; } /* get device name */ while ((c = *cp) != '\0') { if ((c == '(') || (c == '/')) { cp++; break; } if (ncp < device_name + sizeof(device_name) - 1) *ncp++ = c; cp++; } /* set default if missing */ if (ncp == device_name) { strcpy(device_name,"ace"); ncp += 3; } /* get device number */ if ((c = *cp) >= '0' && c <= '9') { unit = c - '0'; c = *++cp; } if (c == ',') { /* get partition number */ if ((c = *++cp) >= '0' && c <= '9') { part = c - '0'; c = *++cp; } } if (c == ')') c = *++cp; if (c == '/') cp++; *ncp = '\0'; /* Copy kernel name before we overwrite, then do it */ strcpy(file_name, (*cp) ? cp : kernelnames[0]); snprintf(fname, PATH_MAX, "%c/%s(%c,%c)/%s", ctlr + '0', device_name, unit + '0', part + '0', file_name); //printf("devcanon -> %s\n",fname); return (0); }