1 /* $NetBSD: boot.c,v 1.30 2016/06/11 06:43:16 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)boot.c 8.1 (Berkeley) 6/10/93 32 */ 33 34 #include <sys/param.h> 35 #include <sys/reboot.h> 36 #include <sys/boot_flag.h> 37 #include <sys/exec.h> 38 39 #include <lib/libsa/stand.h> 40 #include <lib/libsa/loadfile.h> 41 #include <lib/libkern/libkern.h> 42 43 #include <machine/promlib.h> 44 #include <sparc/stand/common/promdev.h> 45 #include <sparc/stand/common/isfloppy.h> 46 47 #include "bootinfo.h" 48 49 extern void prom_patch(void); /* prompatch.c */ 50 51 static int bootoptions(const char *); 52 53 int boothowto; 54 int debug; 55 int netif_debug; 56 57 char fbuf[80], dbuf[128]; 58 paddr_t bstart, bend; /* physical start & end address of the boot program */ 59 60 int compatmode = 0; /* For loading older kernels */ 61 u_long loadaddrmask = -1UL; 62 63 extern char bootprog_name[], bootprog_rev[]; 64 65 int main(void); 66 typedef void (*entry_t)(void *, int, int, int, long, long); 67 68 /* 69 * Boot device is derived from ROM provided information, or if there is none, 70 * this list is used in sequence, to find a kernel. 71 */ 72 char *kernels[] = { 73 "netbsd", 74 "netbsd.gz", 75 "netbsd.old", 76 "netbsd.old.gz", 77 "onetbsd", 78 "onetbsd.gz", 79 "vmunix", 80 #ifdef notyet 81 "netbsd.pl", 82 "netbsd.pl.gz", 83 "netbsd.el", 84 "netbsd.el.gz", 85 #endif 86 NULL 87 }; 88 89 int 90 bootoptions(const char *ap) 91 { 92 int v = 0; 93 if (ap == NULL || *ap++ != '-') 94 return (0); 95 96 while (*ap != '\0' && *ap != ' ' && *ap != '\t' && *ap != '\n') { 97 BOOT_FLAG(*ap, v); 98 if (*ap == 'C') 99 compatmode = 1; 100 ap++; 101 } 102 103 if ((v & RB_KDB) != 0) 104 debug = 1; 105 106 return (v); 107 } 108 109 static paddr_t 110 getphysmem(u_long size) 111 { 112 struct memarr *pmemarr; /* physical memory regions */ 113 int npmemarr; /* number of entries in pmemarr */ 114 struct memarr *mp; 115 int i; 116 extern char start[]; /* top of stack (see srt0.S) */ 117 118 /* 119 * Find the physical memory area that's in use by the boot loader. 120 * Our stack grows down from label `start'; assume we need no more 121 * than 16K of stack space. 122 * The top of the boot loader is the next 4MB boundary. 123 */ 124 if (pmap_extract((vaddr_t)start - (16*1024), &bstart) != 0) 125 return ((paddr_t)-1); 126 127 bend = roundup(bstart, 0x400000); 128 129 /* 130 * Get available physical memory from the prom. 131 */ 132 npmemarr = prom_makememarr(NULL, 0, MEMARR_AVAILPHYS); 133 pmemarr = alloc(npmemarr*sizeof(struct memarr)); 134 if (pmemarr == NULL) 135 return ((paddr_t)-1); 136 npmemarr = prom_makememarr(pmemarr, npmemarr, MEMARR_AVAILPHYS); 137 138 /* 139 * Find a suitable loading address. 140 */ 141 for (mp = pmemarr, i = npmemarr; --i >= 0; mp++) { 142 paddr_t pa = (paddr_t)pmemarr[i].addr; 143 u_long len = (u_long)pmemarr[i].len; 144 145 /* Check whether it will fit in front of us */ 146 if (pa < bstart && len >= size && (bstart - pa) >= size) 147 return (pa); 148 149 /* Skip the boot program memory */ 150 if (pa < bend) { 151 if (len < bend - pa) 152 /* Not large enough */ 153 continue; 154 155 /* Shrink this segment */ 156 len -= bend - pa; 157 pa = bend; 158 } 159 160 /* Does it fit in the remainder of this segment? */ 161 if (len >= size) 162 return (pa); 163 } 164 return ((paddr_t)-1); 165 } 166 167 static int 168 loadk(char *kernel, u_long *marks) 169 { 170 int fd, error; 171 vaddr_t va; 172 paddr_t pa; 173 u_long size; 174 int flags = LOAD_KERNEL; 175 176 if ((fd = open(kernel, 0)) < 0) 177 return (errno ? errno : ENOENT); 178 179 marks[MARK_START] = 0; 180 if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0) 181 goto out; 182 183 size = marks[MARK_END] - marks[MARK_START]; 184 185 /* We want that leading 16K in front of the kernel image */ 186 size += PROM_LOADADDR; 187 va = marks[MARK_START] - PROM_LOADADDR; 188 189 /* 190 * Extra space for bootinfo and kernel bootstrap. 191 * In compat mode, we get to re-use the space occupied by the 192 * boot program. Traditionally, we've silently assumed that 193 * is enough for the kernel to work with. 194 */ 195 size += BOOTINFO_SIZE; 196 if (!compatmode) 197 size += 512 * 1024; 198 199 /* Get a physical load address */ 200 pa = getphysmem(size); 201 if (pa == (paddr_t)-1) { 202 error = EFBIG; 203 goto out; 204 } 205 206 if (boothowto & AB_VERBOSE) 207 printf("Loading at physical address %lx\n", pa); 208 if (pmap_map(va, pa, size) != 0) { 209 error = EFAULT; 210 goto out; 211 } 212 213 /* XXX - to do: inspect kernel image and set compat mode */ 214 if (compatmode) { 215 /* Double-map at VA 0 for compatibility */ 216 if (pa + size >= bstart) { 217 printf("%s: too large for compat mode\n", kernel); 218 error = EFBIG; 219 goto out; 220 } 221 222 if (pa != 0 && pmap_map(0, pa, size) != 0) { 223 error = EFAULT; 224 goto out; 225 } 226 loadaddrmask = 0x07ffffffUL; 227 } 228 229 if (bootdev_isfloppy(prom_bootdevice)) 230 flags &= ~LOAD_BACKWARDS; 231 232 marks[MARK_START] = 0; 233 error = fdloadfile(fd, marks, flags); 234 out: 235 close(fd); 236 return (error); 237 } 238 239 int 240 main(void) 241 { 242 int error, i; 243 char kernel[MAX_PROM_PATH]; 244 const char *k; 245 u_long marks[MARK_MAX], bootinfo; 246 struct btinfo_symtab bi_sym; 247 struct btinfo_boothowto bi_howto; 248 void *arg; 249 250 #ifdef HEAP_VARIABLE 251 { 252 extern char end[]; 253 setheap((void *)ALIGN(end), (void *)0xffffffff); 254 } 255 #endif 256 prom_init(); 257 mmu_init(); 258 259 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 260 261 /* massage machine prom */ 262 prom_patch(); 263 264 /* 265 * get default kernel. 266 */ 267 k = prom_getbootfile(); 268 if (k != NULL && *k != '\0') { 269 i = -1; /* not using the kernels */ 270 strcpy(kernel, k); 271 } else { 272 i = 0; 273 strcpy(kernel, kernels[i]); 274 } 275 276 k = prom_getbootpath(); 277 if (k && *k) 278 strcpy(prom_bootdevice, k); 279 boothowto = bootoptions(prom_getbootargs()); 280 281 for (;;) { 282 /* 283 * ask for a kernel first .. 284 */ 285 if (boothowto & RB_ASKNAME) { 286 printf("device[%s] (\"halt\" to halt): ", 287 prom_bootdevice); 288 kgets(dbuf, sizeof(dbuf)); 289 if (strcmp(dbuf, "halt") == 0) 290 _rtt(); 291 if (dbuf[0]) 292 strcpy(prom_bootdevice, dbuf); 293 printf("boot (press RETURN to try default list): "); 294 kgets(fbuf, sizeof(fbuf)); 295 if (fbuf[0]) 296 strcpy(kernel, fbuf); 297 else { 298 boothowto &= ~RB_ASKNAME; 299 i = 0; 300 strcpy(kernel, kernels[i]); 301 } 302 } 303 304 printf("Booting %s\n", kernel); 305 if ((error = loadk(kernel, marks)) == 0) 306 break; 307 308 if (error != ENOENT) { 309 printf("Cannot load %s: error=%d\n", kernel, error); 310 boothowto |= RB_ASKNAME; 311 } 312 313 /* 314 * if we have are not in askname mode, and we aren't using the 315 * prom bootfile, try the next one (if it exits). otherwise, 316 * go into askname mode. 317 */ 318 if ((boothowto & RB_ASKNAME) == 0 && 319 i != -1 && kernels[++i]) { 320 strcpy(kernel, kernels[i]); 321 printf(": trying %s...\n", kernel); 322 } else { 323 printf("\n"); 324 boothowto |= RB_ASKNAME; 325 } 326 } 327 328 marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(u_long) - 1)) & 329 (-sizeof(u_long)); 330 arg = (prom_version() == PROM_OLDMON) ? (void *)PROM_LOADADDR : romp; 331 332 /* Setup boot info structure at the end of the kernel image */ 333 bootinfo = bi_init(marks[MARK_END] & loadaddrmask); 334 335 /* Add kernel symbols to bootinfo */ 336 bi_sym.nsym = marks[MARK_NSYM] & loadaddrmask; 337 bi_sym.ssym = marks[MARK_SYM] & loadaddrmask; 338 bi_sym.esym = marks[MARK_END] & loadaddrmask; 339 bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym)); 340 341 /* Add boothowto */ 342 bi_howto.boothowto = boothowto; 343 bi_add(&bi_howto, BTINFO_BOOTHOWTO, sizeof(bi_howto)); 344 345 /* Add kernel path to bootinfo */ 346 i = sizeof(struct btinfo_common) + strlen(kernel) + 1; 347 /* Impose limit (somewhat arbitrary) */ 348 if (i < BOOTINFO_SIZE / 2) { 349 union { 350 struct btinfo_kernelfile bi_file; 351 char x[BOOTINFO_SIZE / 2]; 352 } U; 353 strcpy(U.bi_file.name, kernel); 354 bi_add(&U.bi_file, BTINFO_KERNELFILE, i); 355 } 356 357 (*(entry_t)marks[MARK_ENTRY])(arg, 0, 0, 0, bootinfo, DDB_MAGIC2); 358 _rtt(); 359 } 360