1 /* $NetBSD: boot.c,v 1.1 2011/01/26 01:18:54 pooka 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