Home | History | Annotate | Line # | Download | only in common
boot.c revision 1.1.2.2
      1 /*	$NetBSD: boot.c,v 1.1.2.2 2011/02/08 18:05:10 bouyer Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      6  * All rights reserved.
      7  *
      8  * This code was written by Alessandro Forin and Neil Pittman
      9  * at Microsoft Research and contributed to The NetBSD Foundation
     10  * by Microsoft Corporation.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <lib/libsa/stand.h>
     35 #include <lib/libsa/loadfile.h>
     36 #include <lib/libkern/libkern.h>
     37 
     38 #include <sys/param.h>
     39 #include <sys/exec.h>
     40 #include <sys/exec_elf.h>
     41 
     42 #include "common.h"
     43 #include "bootinfo.h"
     44 #include "start.h"
     45 
     46 /*
     47  * We won't go overboard with gzip'd kernel names.  After all we can
     48  * still boot a gzip'd kernel called "netbsd.emips" - it doesn't need
     49  * the .gz suffix.
     50  */
     51 char *kernelnames[] = {
     52 	"netbsd",	"netbsd.gz",
     53 	"netbsd.old",
     54 	"onetbsd",
     55 	"gennetbsd",
     56     "nfsnetbsd",
     57 	NULL
     58 };
     59 
     60 
     61 void main (char *);
     62 char *getboot(char *, char*);
     63 static int devcanon(char *);
     64 
     65 #define OPT_MAX PATH_MAX /* way overkill */
     66 
     67 static int loadit(char *name, u_long marks[MARK_MAX])
     68 {
     69     printf("Loading: %s\n", name);
     70     memset(marks, 0, sizeof marks);
     71     return (loadfile(name, marks, LOAD_ALL));
     72 }
     73 
     74 /*
     75  * The locore in start.S calls us with an 8KB stack carved after _end.
     76  *
     77  */
     78 void
     79 main(char *stack_top)
     80 {
     81 	int argc;
     82     int autoboot = 1, win;
     83 	char *name, **namep, *dev, *kernel;
     84 	char bootname[PATH_MAX], bootpath[PATH_MAX], options[OPT_MAX];
     85 	uint32_t entry;
     86 	u_long marks[MARK_MAX];
     87 	struct btinfo_symtab bi_syms;
     88 	struct btinfo_bootpath bi_bpath;
     89 
     90     /* Init all peripherals, esp USART for printf and memory */
     91     init_board();
     92 
     93     /* On account of compression, we need a fairly large heap.
     94      * To keep things simple, take one meg just below the 16 meg mark.
     95      * That allows for a large kernel, and a 16MB configuration still works.
     96      */
     97     setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000);
     98 
     99     /* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete
    100      * and switching the serial line to PuTTY as console. Get a char to pause.
    101      * This delay is also the practice on PCs so.
    102      */
    103     Delay(200000);
    104     printf("Hit any char to boot..");
    105     argc = GetChar();
    106 
    107 	/* print a banner */
    108 	printf("\n");
    109 	printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n",
    110 	    bootprog_rev);
    111 
    112 	/* initialise bootinfo structure early */
    113 	bi_init(BOOTINFO_ADDR);
    114 
    115     /* Default is to auto-boot from the first disk */
    116     dev = "0/ace(0,0)/";
    117 	kernel = kernelnames[0];
    118     options[0] = 0;
    119 
    120     win = 0;
    121     for (;!win;) {
    122         strcpy(bootpath, dev);
    123         strcat(bootpath, kernel);
    124         name = getboot(bootpath,options);
    125 
    126         if (name != NULL) {
    127             win = (loadit(name, marks) == 0);
    128         } else if (autoboot)
    129             break;
    130         autoboot = 0;
    131     }
    132 
    133     if (!win) {
    134 		for (namep = kernelnames, win = 0; *namep != NULL && !win;
    135 		    namep++) {
    136 			kernel = *namep;
    137 			strcpy(bootpath, dev);
    138 			strcat(bootpath, kernel);
    139 			win = (loadit(bootpath, marks) == 0);
    140 			if (win) {
    141 				name = bootpath;
    142 			}
    143 		}
    144 	}
    145 	if (!win)
    146 		goto fail;
    147 
    148 	strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN);
    149 	bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
    150 
    151 	entry = marks[MARK_ENTRY];
    152 	bi_syms.nsym = marks[MARK_NSYM];
    153 	bi_syms.ssym = marks[MARK_SYM];
    154 	bi_syms.esym = marks[MARK_END];
    155 	bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
    156 
    157 	printf("Starting at 0x%x\n\n", entry);
    158     call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo);
    159 	(void)printf("KERNEL RETURNED!\n");
    160 
    161 fail:
    162 	(void)printf("Boot failed!  Halting...\n");
    163 }
    164 
    165 static inline int
    166 parse(char *cmd, char *kname, char *optarg)
    167 {
    168     char *arg = cmd;
    169     char *ep, *p;
    170     int c, i;
    171 
    172     while ((c = *arg++)) {
    173         /* skip leading blanks */
    174         if (c == ' ' || c == '\t' || c == '\n')
    175             continue;
    176         /* find separator, or eol */
    177         for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
    178         ep = p;
    179         /* trim if separator */
    180         if (*p)
    181             *p++ = 0;
    182         /* token is either "-opts" or "kernelname" */
    183         if (c == '-') {
    184             /* no overflow because whole line same length as optarg anyways */
    185             while ((c = *arg++)) {
    186                 *optarg++ = c;
    187             }
    188             *optarg = 0;
    189         } else {
    190             arg--;
    191             if ((i = ep - arg)) {
    192                 if ((size_t)i >= PATH_MAX)
    193                     return -1;
    194                 memcpy(kname, arg, i + 1);
    195             }
    196         }
    197         arg = p;
    198     }
    199     return 0;
    200 }
    201 
    202 /* String returned is zero-terminated and at most PATH_MAX chars */
    203 static inline void
    204 getstr(char *cmd, int c)
    205 {
    206     char *s;
    207 
    208     s = cmd;
    209     if (c == 0)
    210         c = GetChar();
    211     for (;;) {
    212         switch (c) {
    213         case 0:
    214             break;
    215         case '\177':
    216         case '\b':
    217             if (s > cmd) {
    218                 s--;
    219                 printf("\b \b");
    220             }
    221             break;
    222         case '\n':
    223         case '\r':
    224             *s = 0;
    225             return;
    226         default:
    227             if ((s - cmd) < (PATH_MAX - 1))
    228                 *s++ = c;
    229             xputchar(c);
    230         }
    231         c = GetChar();
    232     }
    233 }
    234 
    235 char *getboot(char *kname, char* optarg)
    236 {
    237     char c = 0;
    238     char cmd[PATH_MAX];
    239 
    240     printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname);
    241     if ((c = GetChar()) == -1)
    242         return NULL;
    243 
    244     cmd[0] = 0;
    245     getstr(cmd,c);
    246     xputchar('\n');
    247     if (parse(cmd,kname,optarg))
    248         xputchar('\a');
    249     else if (devcanon(kname) == 0)
    250         return kname;
    251     return NULL;
    252 }
    253 
    254 /*
    255  * Make bootpath canonical, provides defaults when missing
    256  */
    257 static int
    258 devcanon(char *fname)
    259 {
    260 	int ctlr = 0, unit = 0, part = 0;
    261 	int c, rc;
    262 	char device_name[20];
    263     char file_name[PATH_MAX];
    264 	const char *cp;
    265 	char *ncp;
    266 
    267     //printf("devcanon(%s)\n",fname);
    268 
    269 	cp = fname;
    270 	ncp = device_name;
    271 
    272     /* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file
    273      * Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none>
    274      */
    275 
    276     /* get controller number */
    277     if ((c = *cp) >= '0' && c <= '9') {
    278         ctlr = c - '0';
    279         c = *++cp;
    280         if (c != '/')
    281             return (ENXIO);
    282         c = *++cp;
    283     }
    284 
    285     /* get device name */
    286     while ((c = *cp) != '\0') {
    287         if ((c == '(') || (c == '/')) {
    288             cp++;
    289             break;
    290         }
    291         if (ncp < device_name + sizeof(device_name) - 1)
    292             *ncp++ = c;
    293         cp++;
    294     }
    295     /* set default if missing */
    296     if (ncp == device_name) {
    297         strcpy(device_name,"ace");
    298         ncp += 3;
    299     }
    300 
    301     /* get device number */
    302     if ((c = *cp) >= '0' && c <= '9') {
    303         unit = c - '0';
    304         c = *++cp;
    305     }
    306 
    307     if (c == ',') {
    308         /* get partition number */
    309         if ((c = *++cp) >= '0' && c <= '9') {
    310             part = c - '0';
    311             c = *++cp;
    312         }
    313     }
    314 
    315     if (c == ')')
    316         c = *++cp;
    317     if (c == '/')
    318         cp++;
    319 
    320 	*ncp = '\0';
    321 
    322     /* Copy kernel name before we overwrite, then do it */
    323     strcpy(file_name, (*cp) ? cp : kernelnames[0]);
    324     sprintf(fname,"%c/%s(%c,%c)/%s",
    325             ctlr + '0', device_name, unit + '0', part + '0', file_name);
    326 
    327     //printf("devcanon -> %s\n",fname);
    328 
    329 	return (0);
    330 }
    331