1 /* $NetBSD: boot.c,v 1.15 2003/03/01 13:01:56 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)boot.c 8.1 (Berkeley) 6/10/93 36 */ 37 38 #include <sys/param.h> 39 #include <sys/reboot.h> 40 #include <sys/boot_flag.h> 41 #include <sys/exec.h> 42 43 #include <lib/libsa/stand.h> 44 #include <lib/libsa/loadfile.h> 45 46 #include <machine/promlib.h> 47 #include <sparc/stand/common/promdev.h> 48 49 #include "bootinfo.h" 50 51 extern void prom_patch __P((void)); /* prompatch.c */ 52 53 static int bootoptions __P((char *)); 54 55 int boothowto; 56 int debug; 57 int netif_debug; 58 59 char fbuf[80], dbuf[128]; 60 paddr_t bstart, bend; /* physical start & end address of the boot program */ 61 62 int compatmode = 0; /* For loading older kernels */ 63 u_long loadaddrmask = -1UL; 64 65 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 66 67 int main __P((void)); 68 typedef void (*entry_t)__P((caddr_t, int, int, int, long, long)); 69 70 /* 71 * Boot device is derived from ROM provided information, or if there is none, 72 * this list is used in sequence, to find a kernel. 73 */ 74 char *kernels[] = { 75 "netbsd", 76 "netbsd.gz", 77 "netbsd.old", 78 "netbsd.old.gz", 79 "onetbsd", 80 "onetbsd.gz", 81 "vmunix", 82 #ifdef notyet 83 "netbsd.pl", 84 "netbsd.pl.gz", 85 "netbsd.el", 86 "netbsd.el.gz", 87 #endif 88 NULL 89 }; 90 91 int 92 bootoptions(ap) 93 char *ap; 94 { 95 int v = 0; 96 if (ap == NULL || *ap++ != '-') 97 return (0); 98 99 while (*ap != '\0' && *ap != ' ' && *ap != '\t' && *ap != '\n') { 100 BOOT_FLAG(*ap, v); 101 ap++; 102 } 103 104 if ((v & RB_KDB) != 0) 105 debug = 1; 106 107 return (v); 108 } 109 110 static paddr_t 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 175 if ((fd = open(kernel, 0)) < 0) 176 return (errno ? errno : ENOENT); 177 178 marks[MARK_START] = 0; 179 if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0) 180 goto out; 181 182 size = marks[MARK_END] - marks[MARK_START]; 183 184 /* We want that leading 4K in front of the kernel image */ 185 size += PROM_LOADADDR; 186 va = marks[MARK_START] - PROM_LOADADDR; 187 188 /* Extra space for bootinfo and kernel bootstrap */ 189 size += 512 * 1024; 190 191 /* Get a physical load address */ 192 pa = getphysmem(size); 193 if (pa == (paddr_t)-1) { 194 error = EFBIG; 195 goto out; 196 } 197 198 if (boothowto & AB_VERBOSE) 199 printf("Loading at physical address %lx\n", pa); 200 if (pmap_map(va, pa, size) != 0) { 201 error = EFAULT; 202 goto out; 203 } 204 205 /* XXX - to do: inspect kernel image and set compat mode */ 206 if (compatmode) { 207 /* Double-map at VA 0 for compatibility; ignore errors */ 208 if (pa + size < bstart) 209 (void)pmap_map(0, pa, size); 210 loadaddrmask = 0x07ffffffUL; 211 } 212 213 marks[MARK_START] = 0; 214 error = fdloadfile(fd, marks, LOAD_KERNEL); 215 out: 216 close(fd); 217 return (error); 218 } 219 220 int 221 main() 222 { 223 int error, i; 224 char *kernel; 225 u_long marks[MARK_MAX], bootinfo; 226 struct btinfo_symtab bi_sym; 227 void *arg; 228 229 #ifdef HEAP_VARIABLE 230 { 231 extern char end[]; 232 setheap((void *)ALIGN(end), (void *)0xffffffff); 233 } 234 #endif 235 prom_init(); 236 mmu_init(); 237 238 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 239 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 240 241 /* massage machine prom */ 242 prom_patch(); 243 244 /* 245 * get default kernel. 246 */ 247 prom_bootdevice = prom_getbootpath(); 248 kernel = prom_getbootfile(); 249 boothowto = bootoptions(prom_getbootargs()); 250 251 if (kernel != NULL && *kernel != '\0') { 252 i = -1; /* not using the kernels */ 253 } else { 254 i = 0; 255 kernel = kernels[i]; 256 } 257 258 for (;;) { 259 /* 260 * ask for a kernel first .. 261 */ 262 if (boothowto & RB_ASKNAME) { 263 printf("device[%s] (\"halt\" to halt): ", 264 prom_bootdevice); 265 gets(dbuf); 266 if (strcmp(dbuf, "halt") == 0) 267 _rtt(); 268 if (dbuf[0]) 269 prom_bootdevice = dbuf; 270 printf("boot (press RETURN to try default list): "); 271 gets(fbuf); 272 if (fbuf[0]) 273 kernel = fbuf; 274 else { 275 boothowto &= ~RB_ASKNAME; 276 i = 0; 277 kernel = kernels[i]; 278 } 279 } 280 281 printf("Booting %s\n", kernel); 282 if ((error = loadk(kernel, marks)) == 0) 283 break; 284 285 if (error != ENOENT) { 286 printf("Cannot load %s: error=%d\n", kernel, error); 287 boothowto |= RB_ASKNAME; 288 } 289 290 /* 291 * if we have are not in askname mode, and we aren't using the 292 * prom bootfile, try the next one (if it exits). otherwise, 293 * go into askname mode. 294 */ 295 if ((boothowto & RB_ASKNAME) == 0 && 296 i != -1 && kernels[++i]) { 297 kernel = kernels[i]; 298 printf(": trying %s...\n", kernel); 299 } else { 300 printf("\n"); 301 boothowto |= RB_ASKNAME; 302 } 303 } 304 305 marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(u_long) - 1)) & 306 (-sizeof(u_long)); 307 arg = (prom_version() == PROM_OLDMON) ? (caddr_t)PROM_LOADADDR : romp; 308 309 /* Setup boot info structure at the end of the kernel image */ 310 bootinfo = bi_init(marks[MARK_END] & loadaddrmask); 311 312 /* Add kernel symbols to bootinfo */ 313 bi_sym.nsym = marks[MARK_NSYM] & loadaddrmask; 314 bi_sym.ssym = marks[MARK_SYM] & loadaddrmask; 315 bi_sym.esym = marks[MARK_END] & loadaddrmask; 316 bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym)); 317 318 /* Add kernel path to bootinfo */ 319 i = sizeof(struct btinfo_common) + strlen(kernel) + 1; 320 /* Impose limit (somewhat arbitrary) */ 321 if (i < BOOTINFO_SIZE / 2) { 322 union { 323 struct btinfo_kernelfile bi_file; 324 char x[i]; 325 } U; 326 strcpy(U.bi_file.name, kernel); 327 bi_add(&U.bi_file, BTINFO_KERNELFILE, i); 328 } 329 330 (*(entry_t)marks[MARK_ENTRY])(arg, 0, 0, 0, bootinfo, DDB_MAGIC2); 331 _rtt(); 332 } 333