boot.c revision 1.4
1/* $NetBSD: boot.c,v 1.4 2015/12/13 18:24:50 christos 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 */ 51char *kernelnames[] = { 52 "netbsd", "netbsd.gz", 53 "netbsd.old", 54 "onetbsd", 55 "gennetbsd", 56 "nfsnetbsd", 57 NULL 58}; 59 60 61void main (char *); 62char *getboot(char *, char*); 63static int devcanon(char *); 64 65#define OPT_MAX PATH_MAX /* way overkill */ 66 67static int loadit(char *name, u_long *marks) 68{ 69 printf("Loading: %s\n", name); 70 memset(marks, 0, sizeof(*marks) * MARK_MAX); 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 */ 78void 79main(char *stack_top) 80{ 81 int autoboot = 1, win; 82 char *name, **namep, *dev, *kernel; 83 char bootpath[PATH_MAX], options[OPT_MAX]; 84 uint32_t entry; 85 u_long marks[MARK_MAX]; 86 struct btinfo_symtab bi_syms; 87 struct btinfo_bootpath bi_bpath; 88 89 /* Init all peripherals, esp USART for printf and memory */ 90 init_board(); 91 92 /* On account of compression, we need a fairly large heap. 93 * To keep things simple, take one meg just below the 16 meg mark. 94 * That allows for a large kernel, and a 16MB configuration still works. 95 */ 96 setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000); 97 98 /* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete 99 * and switching the serial line to PuTTY as console. Get a char to pause. 100 * This delay is also the practice on PCs so. 101 */ 102 Delay(200000); 103 printf("Hit any char to boot.."); 104 (void)GetChar(); 105 106 /* print a banner */ 107 printf("\n"); 108 printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n", 109 bootprog_rev); 110 111 /* initialise bootinfo structure early */ 112 bi_init(BOOTINFO_ADDR); 113 114 /* Default is to auto-boot from the first disk */ 115 dev = "0/ace(0,0)/"; 116 kernel = kernelnames[0]; 117 options[0] = 0; 118 119 win = 0; 120 for (;!win;) { 121 strcpy(bootpath, dev); 122 strcat(bootpath, kernel); 123 name = getboot(bootpath,options); 124 125 if (name != NULL) { 126 win = (loadit(name, marks) == 0); 127 } else if (autoboot) 128 break; 129 autoboot = 0; 130 } 131 132 if (!win) { 133 for (namep = kernelnames, win = 0; *namep != NULL && !win; 134 namep++) { 135 kernel = *namep; 136 strcpy(bootpath, dev); 137 strcat(bootpath, kernel); 138 win = (loadit(bootpath, marks) == 0); 139 if (win) { 140 name = bootpath; 141 } 142 } 143 } 144 if (!win) 145 goto fail; 146 147 strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN); 148 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); 149 150 entry = marks[MARK_ENTRY]; 151 bi_syms.nsym = marks[MARK_NSYM]; 152 bi_syms.ssym = marks[MARK_SYM]; 153 bi_syms.esym = marks[MARK_END]; 154 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); 155 156 printf("Starting at 0x%x\n\n", entry); 157 call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo); 158 (void)printf("KERNEL RETURNED!\n"); 159 160fail: 161 (void)printf("Boot failed! Halting...\n"); 162} 163 164static inline int 165parse(char *cmd, char *kname, char *optarg) 166{ 167 char *arg = cmd; 168 char *ep, *p; 169 int c, i; 170 171 while ((c = *arg++)) { 172 /* skip leading blanks */ 173 if (c == ' ' || c == '\t' || c == '\n') 174 continue; 175 /* find separator, or eol */ 176 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 177 ep = p; 178 /* trim if separator */ 179 if (*p) 180 *p++ = 0; 181 /* token is either "-opts" or "kernelname" */ 182 if (c == '-') { 183 /* no overflow because whole line same length as optarg anyways */ 184 while ((c = *arg++)) { 185 *optarg++ = c; 186 } 187 *optarg = 0; 188 } else { 189 arg--; 190 if ((i = ep - arg)) { 191 if ((size_t)i >= PATH_MAX) 192 return -1; 193 memcpy(kname, arg, i + 1); 194 } 195 } 196 arg = p; 197 } 198 return 0; 199} 200 201/* String returned is zero-terminated and at most PATH_MAX chars */ 202static inline void 203getstr(char *cmd, int c) 204{ 205 char *s; 206 207 s = cmd; 208 if (c == 0) 209 c = GetChar(); 210 for (;;) { 211 switch (c) { 212 case 0: 213 break; 214 case '\177': 215 case '\b': 216 if (s > cmd) { 217 s--; 218 printf("\b \b"); 219 } 220 break; 221 case '\n': 222 case '\r': 223 *s = 0; 224 return; 225 default: 226 if ((s - cmd) < (PATH_MAX - 1)) 227 *s++ = c; 228 xputchar(c); 229 } 230 c = GetChar(); 231 } 232} 233 234char *getboot(char *kname, char* optarg) 235{ 236 char c = 0; 237 char cmd[PATH_MAX]; 238 239 printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname); 240 if ((c = GetChar()) == -1) 241 return NULL; 242 243 cmd[0] = 0; 244 getstr(cmd,c); 245 xputchar('\n'); 246 if (parse(cmd,kname,optarg)) 247 xputchar('\a'); 248 else if (devcanon(kname) == 0) 249 return kname; 250 return NULL; 251} 252 253/* 254 * Make bootpath canonical, provides defaults when missing 255 */ 256static int 257devcanon(char *fname) 258{ 259 int ctlr = 0, unit = 0, part = 0; 260 int c; 261 char device_name[20]; 262 char file_name[PATH_MAX]; 263 const char *cp; 264 char *ncp; 265 266 //printf("devcanon(%s)\n",fname); 267 268 cp = fname; 269 ncp = device_name; 270 271 /* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file 272 * Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none> 273 */ 274 275 /* get controller number */ 276 if ((c = *cp) >= '0' && c <= '9') { 277 ctlr = c - '0'; 278 c = *++cp; 279 if (c != '/') 280 return (ENXIO); 281 c = *++cp; 282 } 283 284 /* get device name */ 285 while ((c = *cp) != '\0') { 286 if ((c == '(') || (c == '/')) { 287 cp++; 288 break; 289 } 290 if (ncp < device_name + sizeof(device_name) - 1) 291 *ncp++ = c; 292 cp++; 293 } 294 /* set default if missing */ 295 if (ncp == device_name) { 296 strcpy(device_name,"ace"); 297 ncp += 3; 298 } 299 300 /* get device number */ 301 if ((c = *cp) >= '0' && c <= '9') { 302 unit = c - '0'; 303 c = *++cp; 304 } 305 306 if (c == ',') { 307 /* get partition number */ 308 if ((c = *++cp) >= '0' && c <= '9') { 309 part = c - '0'; 310 c = *++cp; 311 } 312 } 313 314 if (c == ')') 315 c = *++cp; 316 if (c == '/') 317 cp++; 318 319 *ncp = '\0'; 320 321 /* Copy kernel name before we overwrite, then do it */ 322 strcpy(file_name, (*cp) ? cp : kernelnames[0]); 323 snprintf(fname, PATH_MAX, "%c/%s(%c,%c)/%s", 324 ctlr + '0', device_name, unit + '0', part + '0', file_name); 325 326 //printf("devcanon -> %s\n",fname); 327 328 return (0); 329} 330