1 /* $NetBSD: boot.c,v 1.19 2004/04/08 07:35:34 pk 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 __P((void)); /* prompatch.c */ 49 50 static int bootoptions __P((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 __P((void)); 65 typedef void (*entry_t)__P((caddr_t, 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(ap) 90 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 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() 236 { 237 int error, i; 238 char *kernel; 239 u_long marks[MARK_MAX], bootinfo; 240 struct btinfo_symtab bi_sym; 241 void *arg; 242 243 #ifdef HEAP_VARIABLE 244 { 245 extern char end[]; 246 setheap((void *)ALIGN(end), (void *)0xffffffff); 247 } 248 #endif 249 prom_init(); 250 mmu_init(); 251 252 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 253 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 254 255 /* massage machine prom */ 256 prom_patch(); 257 258 /* 259 * get default kernel. 260 */ 261 prom_bootdevice = prom_getbootpath(); 262 kernel = prom_getbootfile(); 263 boothowto = bootoptions(prom_getbootargs()); 264 265 if (kernel != NULL && *kernel != '\0') { 266 i = -1; /* not using the kernels */ 267 } else { 268 i = 0; 269 kernel = kernels[i]; 270 } 271 272 for (;;) { 273 /* 274 * ask for a kernel first .. 275 */ 276 if (boothowto & RB_ASKNAME) { 277 printf("device[%s] (\"halt\" to halt): ", 278 prom_bootdevice); 279 gets(dbuf); 280 if (strcmp(dbuf, "halt") == 0) 281 _rtt(); 282 if (dbuf[0]) 283 prom_bootdevice = dbuf; 284 printf("boot (press RETURN to try default list): "); 285 gets(fbuf); 286 if (fbuf[0]) 287 kernel = fbuf; 288 else { 289 boothowto &= ~RB_ASKNAME; 290 i = 0; 291 kernel = kernels[i]; 292 } 293 } 294 295 printf("Booting %s\n", kernel); 296 if ((error = loadk(kernel, marks)) == 0) 297 break; 298 299 if (error != ENOENT) { 300 printf("Cannot load %s: error=%d\n", kernel, error); 301 boothowto |= RB_ASKNAME; 302 } 303 304 /* 305 * if we have are not in askname mode, and we aren't using the 306 * prom bootfile, try the next one (if it exits). otherwise, 307 * go into askname mode. 308 */ 309 if ((boothowto & RB_ASKNAME) == 0 && 310 i != -1 && kernels[++i]) { 311 kernel = kernels[i]; 312 printf(": trying %s...\n", kernel); 313 } else { 314 printf("\n"); 315 boothowto |= RB_ASKNAME; 316 } 317 } 318 319 marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(u_long) - 1)) & 320 (-sizeof(u_long)); 321 arg = (prom_version() == PROM_OLDMON) ? (caddr_t)PROM_LOADADDR : romp; 322 323 /* Setup boot info structure at the end of the kernel image */ 324 bootinfo = bi_init(marks[MARK_END] & loadaddrmask); 325 326 /* Add kernel symbols to bootinfo */ 327 bi_sym.nsym = marks[MARK_NSYM] & loadaddrmask; 328 bi_sym.ssym = marks[MARK_SYM] & loadaddrmask; 329 bi_sym.esym = marks[MARK_END] & loadaddrmask; 330 bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym)); 331 332 /* Add kernel path to bootinfo */ 333 i = sizeof(struct btinfo_common) + strlen(kernel) + 1; 334 /* Impose limit (somewhat arbitrary) */ 335 if (i < BOOTINFO_SIZE / 2) { 336 union { 337 struct btinfo_kernelfile bi_file; 338 char x[i]; 339 } U; 340 strcpy(U.bi_file.name, kernel); 341 bi_add(&U.bi_file, BTINFO_KERNELFILE, i); 342 } 343 344 (*(entry_t)marks[MARK_ENTRY])(arg, 0, 0, 0, bootinfo, DDB_MAGIC2); 345 _rtt(); 346 } 347