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