1 /* $NetBSD: boot.c,v 1.24 2007/03/04 06:00:47 christos 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 46 #include "bootinfo.h" 47 48 extern void prom_patch(void); /* prompatch.c */ 49 50 static int bootoptions(const char *); 51 52 int boothowto; 53 int debug; 54 int netif_debug; 55 56 char fbuf[80], dbuf[128]; 57 paddr_t bstart, bend; /* physical start & end address of the boot program */ 58 59 int compatmode = 0; /* For loading older kernels */ 60 u_long loadaddrmask = -1UL; 61 62 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 63 64 int main(void); 65 typedef void (*entry_t)(void *, int, int, int, long, long); 66 67 /* 68 * Boot device is derived from ROM provided information, or if there is none, 69 * this list is used in sequence, to find a kernel. 70 */ 71 char *kernels[] = { 72 "netbsd", 73 "netbsd.gz", 74 "netbsd.old", 75 "netbsd.old.gz", 76 "onetbsd", 77 "onetbsd.gz", 78 "vmunix", 79 #ifdef notyet 80 "netbsd.pl", 81 "netbsd.pl.gz", 82 "netbsd.el", 83 "netbsd.el.gz", 84 #endif 85 NULL 86 }; 87 88 int 89 bootoptions(const char *ap) 90 { 91 int v = 0; 92 if (ap == NULL || *ap++ != '-') 93 return (0); 94 95 while (*ap != '\0' && *ap != ' ' && *ap != '\t' && *ap != '\n') { 96 BOOT_FLAG(*ap, v); 97 if (*ap == 'C') 98 compatmode = 1; 99 ap++; 100 } 101 102 if ((v & RB_KDB) != 0) 103 debug = 1; 104 105 return (v); 106 } 107 108 static paddr_t 109 getphysmem(u_long size) 110 { 111 struct memarr *pmemarr; /* physical memory regions */ 112 int npmemarr; /* number of entries in pmemarr */ 113 struct memarr *mp; 114 int i; 115 extern char start[]; /* top of stack (see srt0.S) */ 116 117 /* 118 * Find the physical memory area that's in use by the boot loader. 119 * Our stack grows down from label `start'; assume we need no more 120 * than 16K of stack space. 121 * The top of the boot loader is the next 4MB boundary. 122 */ 123 if (pmap_extract((vaddr_t)start - (16*1024), &bstart) != 0) 124 return ((paddr_t)-1); 125 126 bend = roundup(bstart, 0x400000); 127 128 /* 129 * Get available physical memory from the prom. 130 */ 131 npmemarr = prom_makememarr(NULL, 0, MEMARR_AVAILPHYS); 132 pmemarr = alloc(npmemarr*sizeof(struct memarr)); 133 if (pmemarr == NULL) 134 return ((paddr_t)-1); 135 npmemarr = prom_makememarr(pmemarr, npmemarr, MEMARR_AVAILPHYS); 136 137 /* 138 * Find a suitable loading address. 139 */ 140 for (mp = pmemarr, i = npmemarr; --i >= 0; mp++) { 141 paddr_t pa = (paddr_t)pmemarr[i].addr; 142 u_long len = (u_long)pmemarr[i].len; 143 144 /* Check whether it will fit in front of us */ 145 if (pa < bstart && len >= size && (bstart - pa) >= size) 146 return (pa); 147 148 /* Skip the boot program memory */ 149 if (pa < bend) { 150 if (len < bend - pa) 151 /* Not large enough */ 152 continue; 153 154 /* Shrink this segment */ 155 len -= bend - pa; 156 pa = bend; 157 } 158 159 /* Does it fit in the remainder of this segment? */ 160 if (len >= size) 161 return (pa); 162 } 163 return ((paddr_t)-1); 164 } 165 166 static int 167 loadk(char *kernel, u_long *marks) 168 { 169 int fd, error; 170 vaddr_t va; 171 paddr_t pa; 172 u_long size; 173 174 if ((fd = open(kernel, 0)) < 0) 175 return (errno ? errno : ENOENT); 176 177 marks[MARK_START] = 0; 178 if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0) 179 goto out; 180 181 size = marks[MARK_END] - marks[MARK_START]; 182 183 /* We want that leading 16K in front of the kernel image */ 184 size += PROM_LOADADDR; 185 va = marks[MARK_START] - PROM_LOADADDR; 186 187 /* 188 * Extra space for bootinfo and kernel bootstrap. 189 * In compat mode, we get to re-use the space occupied by the 190 * boot program. Traditionally, we've silently assumed that 191 * is enough for the kernel to work with. 192 */ 193 size += BOOTINFO_SIZE; 194 if (!compatmode) 195 size += 512 * 1024; 196 197 /* Get a physical load address */ 198 pa = getphysmem(size); 199 if (pa == (paddr_t)-1) { 200 error = EFBIG; 201 goto out; 202 } 203 204 if (boothowto & AB_VERBOSE) 205 printf("Loading at physical address %lx\n", pa); 206 if (pmap_map(va, pa, size) != 0) { 207 error = EFAULT; 208 goto out; 209 } 210 211 /* XXX - to do: inspect kernel image and set compat mode */ 212 if (compatmode) { 213 /* Double-map at VA 0 for compatibility */ 214 if (pa + size >= bstart) { 215 printf("%s: too large for compat mode\n", kernel); 216 error = EFBIG; 217 goto out; 218 } 219 220 if (pa != 0 && pmap_map(0, pa, size) != 0) { 221 error = EFAULT; 222 goto out; 223 } 224 loadaddrmask = 0x07ffffffUL; 225 } 226 227 marks[MARK_START] = 0; 228 error = fdloadfile(fd, marks, LOAD_KERNEL); 229 out: 230 close(fd); 231 return (error); 232 } 233 234 int 235 main(void) 236 { 237 int error, i; 238 char kernel[MAX_PROM_PATH]; 239 const char *k; 240 u_long marks[MARK_MAX], bootinfo; 241 struct btinfo_symtab bi_sym; 242 void *arg; 243 244 #ifdef HEAP_VARIABLE 245 { 246 extern char end[]; 247 setheap((void *)ALIGN(end), (void *)0xffffffff); 248 } 249 #endif 250 prom_init(); 251 mmu_init(); 252 253 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 254 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 255 256 /* massage machine prom */ 257 prom_patch(); 258 259 /* 260 * get default kernel. 261 */ 262 k = prom_getbootfile(); 263 if (k != NULL && *k != '\0') { 264 i = -1; /* not using the kernels */ 265 strcpy(kernel, k); 266 } else { 267 i = 0; 268 strcpy(kernel, kernels[i]); 269 } 270 271 k = prom_getbootpath(); 272 if (k && *k) 273 strcpy(prom_bootdevice, k); 274 boothowto = bootoptions(prom_getbootargs()); 275 276 for (;;) { 277 /* 278 * ask for a kernel first .. 279 */ 280 if (boothowto & RB_ASKNAME) { 281 printf("device[%s] (\"halt\" to halt): ", 282 prom_bootdevice); 283 gets(dbuf); 284 if (strcmp(dbuf, "halt") == 0) 285 _rtt(); 286 if (dbuf[0]) 287 strcpy(prom_bootdevice, dbuf); 288 printf("boot (press RETURN to try default list): "); 289 gets(fbuf); 290 if (fbuf[0]) 291 strcpy(kernel, fbuf); 292 else { 293 boothowto &= ~RB_ASKNAME; 294 i = 0; 295 strcpy(kernel, kernels[i]); 296 } 297 } 298 299 printf("Booting %s\n", kernel); 300 if ((error = loadk(kernel, marks)) == 0) 301 break; 302 303 if (error != ENOENT) { 304 printf("Cannot load %s: error=%d\n", kernel, error); 305 boothowto |= RB_ASKNAME; 306 } 307 308 /* 309 * if we have are not in askname mode, and we aren't using the 310 * prom bootfile, try the next one (if it exits). otherwise, 311 * go into askname mode. 312 */ 313 if ((boothowto & RB_ASKNAME) == 0 && 314 i != -1 && kernels[++i]) { 315 strcpy(kernel, kernels[i]); 316 printf(": trying %s...\n", kernel); 317 } else { 318 printf("\n"); 319 boothowto |= RB_ASKNAME; 320 } 321 } 322 323 marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(u_long) - 1)) & 324 (-sizeof(u_long)); 325 arg = (prom_version() == PROM_OLDMON) ? (void *)PROM_LOADADDR : romp; 326 327 /* Setup boot info structure at the end of the kernel image */ 328 bootinfo = bi_init(marks[MARK_END] & loadaddrmask); 329 330 /* Add kernel symbols to bootinfo */ 331 bi_sym.nsym = marks[MARK_NSYM] & loadaddrmask; 332 bi_sym.ssym = marks[MARK_SYM] & loadaddrmask; 333 bi_sym.esym = marks[MARK_END] & loadaddrmask; 334 bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym)); 335 336 /* Add kernel path to bootinfo */ 337 i = sizeof(struct btinfo_common) + strlen(kernel) + 1; 338 /* Impose limit (somewhat arbitrary) */ 339 if (i < BOOTINFO_SIZE / 2) { 340 union { 341 struct btinfo_kernelfile bi_file; 342 char x[i]; 343 } U; 344 strcpy(U.bi_file.name, kernel); 345 bi_add(&U.bi_file, BTINFO_KERNELFILE, i); 346 } 347 348 (*(entry_t)marks[MARK_ENTRY])(arg, 0, 0, 0, bootinfo, DDB_MAGIC2); 349 _rtt(); 350 } 351