boot.c revision 1.1 1 /* $NetBSD: boot.c,v 1.1 2000/08/20 14:58:37 mrg Exp $ */
2 #define DEBUG
3 /*
4 * Copyright (c) 1997, 1999 Eduardo E. Horvath. All rights reserved.
5 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
6 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7 * Copyright (C) 1995, 1996 TooLs GmbH.
8 * All rights reserved.
9 *
10 * ELF support derived from NetBSD/alpha's boot loader, written
11 * by Christopher G. Demetriou.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by TooLs GmbH.
24 * 4. The name of TooLs GmbH may not be used to endorse or promote products
25 * derived from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * First try for the boot code
41 *
42 * Input syntax is:
43 * [promdev[{:|,}partition]]/[filename] [flags]
44 */
45
46 #ifdef ELFSIZE
47 #undef ELFSIZE /* We use both. */
48 #endif
49
50 #include <lib/libsa/stand.h>
51 #include <lib/libkern/libkern.h>
52
53 #include <sys/param.h>
54 #include <sys/exec.h>
55 #include <sys/exec_elf.h>
56 #include <sys/reboot.h>
57 #include <sys/disklabel.h>
58
59 #include <machine/cpu.h>
60
61 #include "ofdev.h"
62 #include "openfirm.h"
63
64 #define MEG (1024*1024)
65
66 /*
67 * Boot device is derived from ROM provided information, or if there is none,
68 * this list is used in sequence, to find a kernel.
69 */
70 char *kernels[] = {
71 "netbsd ",
72 "netbsd.gz ",
73 "netbsd.old ",
74 "netbsd.old.gz ",
75 "onetbsd ",
76 "onetbsd.gz ",
77 "vmunix ",
78 #ifdef notyet
79 "netbsd.pl ",
80 "netbsd.pl.gz ",
81 "netbsd.el ",
82 "netbsd.el.gz ",
83 #endif
84 NULL
85 };
86
87 char *kernelname;
88 char bootdev[128];
89 char bootfile[128];
90 int boothowto;
91 int debug;
92
93
94 #ifdef SPARC_BOOT_ELF
95 int elf32_exec __P((int, Elf32_Ehdr *, u_int64_t *, void **, void **));
96 int elf64_exec __P((int, Elf64_Ehdr *, u_int64_t *, void **, void **));
97 #endif
98
99 #ifdef SPARC_BOOT_AOUT
100 int aout_exec __P((int, struct exec *, u_int64_t *, void **));
101 #endif
102
103 #if 0
104 static void
105 prom2boot(dev)
106 char *dev;
107 {
108 char *cp, *lp = 0;
109 int handle;
110 char devtype[16];
111
112 for (cp = dev; *cp; cp++)
113 if (*cp == ':')
114 lp = cp;
115 if (!lp)
116 lp = cp;
117 *lp = 0;
118 }
119 #endif
120
121 static void
122 parseargs(str, howtop)
123 char *str;
124 int *howtop;
125 {
126 char *cp;
127 int i;
128
129 /* Allow user to drop back to the PROM. */
130 if (strcmp(str, "exit") == 0)
131 _rtt();
132
133 /* Insert the kernel name if it is not there. */
134 if (str[0] == 0 || str[0] == '-') {
135 /* Move args down the string */
136 i=0;
137 for (cp = str + strlen(kernelname); str[i]; i++)
138 cp[i] = str[i];
139 /* Copy over kernelname */
140 for (i = 0; kernelname[i]; i++)
141 str[i] = kernelname[i];
142 }
143 *howtop = 0;
144 for (cp = str; *cp; cp++)
145 if (*cp == ' ' || *cp == '-')
146 break;
147 if (!*cp)
148 return;
149
150 *cp++ = 0;
151 while (*cp) {
152 switch (*cp++) {
153 case 'a':
154 *howtop |= RB_ASKNAME;
155 break;
156 case 's':
157 *howtop |= RB_SINGLE;
158 break;
159 case 'd':
160 *howtop |= RB_KDB;
161 if (!debug) debug = 1;
162 break;
163 case 'D':
164 debug = 2;
165 break;
166 case 'v':
167 if (!debug) debug = 1;
168 break;
169 }
170 }
171 }
172
173
174 static void
175 chain(pentry, args, ssym, esym)
176 u_int64_t pentry;
177 char *args;
178 void *ssym;
179 void *esym;
180 {
181 extern char end[];
182 void (*entry)();
183 int l, machine_tag;
184 long newargs[3];
185
186 entry = (void*)(long)pentry;
187
188 freeall();
189 /*
190 * When we come in args consists of a pointer to the boot
191 * string. We need to fix it so it takes into account
192 * other params such as romp.
193 */
194
195 /*
196 * Stash pointer to end of symbol table after the argument
197 * strings.
198 */
199 l = strlen(args) + 1;
200 bcopy(&esym, args + l, sizeof(esym));
201 l += sizeof(esym);
202
203 /*
204 * Tell the kernel we're an OpenFirmware system.
205 */
206 #define SPARC_MACHINE_OPENFIRMWARE 0x44444230
207 machine_tag = SPARC_MACHINE_OPENFIRMWARE;
208 bcopy(&machine_tag, args + l, sizeof(machine_tag));
209 l += sizeof(machine_tag);
210
211 /*
212 * Since we don't need the boot string (we can get it from /chosen)
213 * we won't pass it in. Just pass in esym and magic #
214 */
215 newargs[0] = SPARC_MACHINE_OPENFIRMWARE;
216 newargs[1] = (long)esym;
217 newargs[2] = (long)ssym;
218 args = (char *)newargs;
219 l = sizeof(newargs);
220
221 #ifdef DEBUG
222 printf("chain: calling OF_chain(%x, %x, %x, %x, %x)\n",
223 (void *)RELOC, end - (char *)RELOC, entry, args, l);
224 #endif
225 /* if -D is set then pause in the PROM. */
226 if (debug > 1) OF_enter();
227 OF_chain((void *)RELOC, ((end - (char *)RELOC)+NBPG)%NBPG, entry, args, l);
228 panic("chain");
229 }
230
231 int
232 loadfile(fd, args)
233 int fd;
234 char *args;
235 {
236 union {
237 #ifdef SPARC_BOOT_AOUT
238 struct exec aout;
239 #endif
240 #ifdef SPARC_BOOT_ELF
241 Elf32_Ehdr elf32;
242 Elf64_Ehdr elf64;
243 #endif
244 } hdr;
245 int rval;
246 u_int64_t entry = 0;
247 void *ssym;
248 void *esym;
249
250 rval = 1;
251 ssym = NULL;
252 esym = NULL;
253
254 /* Load the header. */
255 #ifdef DEBUG
256 printf("loadfile: reading header\n");
257 #endif
258 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
259 printf("read header: %s\n", strerror(errno));
260 goto err;
261 }
262
263 /* Determine file type, load kernel. */
264 #ifdef SPARC_BOOT_AOUT
265 if (N_BADMAG(hdr.aout) == 0 && N_GETMID(hdr.aout) == MID_SPARC) {
266 rval = aout_exec(fd, &hdr.aout, &entry, &esym);
267 } else
268 #endif
269 #ifdef SPARC_BOOT_ELF
270 if (bcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
271 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
272 rval = elf32_exec(fd, &hdr.elf32, &entry, &ssym, &esym);
273 } else
274 if (bcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
275 hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
276 rval = elf64_exec(fd, &hdr.elf64, &entry, &ssym, &esym);
277 } else
278 #endif
279 {
280 printf("unknown executable format\n");
281 }
282
283 if (rval)
284 goto err;
285
286 printf(" start=0x%lx\n", (unsigned long)entry);
287
288 close(fd);
289
290 /* XXX this should be replaced w/ a mountroothook. */
291 if (floppyboot) {
292 printf("Please insert root disk and press ENTER ");
293 getchar();
294 printf("\n");
295 }
296
297 chain(entry, args, ssym, esym);
298 /* NOTREACHED */
299
300 err:
301 close(fd);
302 return (rval);
303 }
304
305 #ifdef SPARC_BOOT_AOUT
306 int
307 aout_exec(fd, hdr, entryp, esymp)
308 int fd;
309 struct exec *hdr;
310 u_int64_t *entryp;
311 void **esymp;
312 {
313 void *addr;
314 int n, *paddr;
315
316 #ifdef DEBUG
317 printf("auout_exec: ");
318 #endif
319 /* Display the load address (entry point) for a.out. */
320 printf("Booting %s @ 0x%lx\n", opened_name, hdr->a_entry);
321 addr = (void *)(hdr->a_entry);
322
323 /*
324 * Determine memory needed for kernel and allocate it from
325 * the firmware.
326 */
327 n = hdr->a_text + hdr->a_data + hdr->a_bss + hdr->a_syms + sizeof(int);
328 if ((paddr = OF_claim(addr, n, 0)) == (int *)-1)
329 panic("cannot claim memory");
330
331 /* Load text. */
332 lseek(fd, N_TXTOFF(*hdr), SEEK_SET);
333 printf("%lu", hdr->a_text);
334 if (read(fd, paddr, hdr->a_text) != hdr->a_text) {
335 printf("read text: %s\n", strerror(errno));
336 return (1);
337 }
338 syncicache((void *)paddr, hdr->a_text);
339
340 /* Load data. */
341 printf("+%lu", hdr->a_data);
342 if (read(fd, (void *)paddr + hdr->a_text, hdr->a_data) != hdr->a_data) {
343 printf("read data: %s\n", strerror(errno));
344 return (1);
345 }
346
347 /* Zero BSS. */
348 printf("+%lu", hdr->a_bss);
349 bzero((void *)paddr + hdr->a_text + hdr->a_data, hdr->a_bss);
350
351 /* Symbols. */
352 *esymp = paddr;
353 paddr = (int *)((void *)paddr + hdr->a_text + hdr->a_data + hdr->a_bss);
354 *paddr++ = hdr->a_syms;
355 if (hdr->a_syms) {
356 printf(" [%lu", hdr->a_syms);
357 if (read(fd, paddr, hdr->a_syms) != hdr->a_syms) {
358 printf("read symbols: %s\n", strerror(errno));
359 return (1);
360 }
361 paddr = (int *)((void *)paddr + hdr->a_syms);
362 if (read(fd, &n, sizeof(int)) != sizeof(int)) {
363 printf("read symbols: %s\n", strerror(errno));
364 return (1);
365 }
366 if (OF_claim((void *)paddr, n + sizeof(int), 0) == (void *)-1)
367 panic("cannot claim memory");
368 *paddr++ = n;
369 if (read(fd, paddr, n - sizeof(int)) != n - sizeof(int)) {
370 printf("read symbols: %s\n", strerror(errno));
371 return (1);
372 }
373 printf("+%d]", n - sizeof(int));
374 *esymp = paddr + (n - sizeof(int));
375 }
376
377 *entryp = hdr->a_entry;
378 return (0);
379 }
380 #endif /* SPARC_BOOT_AOUT */
381
382 #ifdef SPARC_BOOT_ELF
383 #if 1
384 /* New style */
385
386 #ifdef ELFSIZE
387 #undef ELFSIZE
388 #endif
389
390 #define ELFSIZE 32
391 #include "elfXX_exec.c"
392
393 #undef ELFSIZE
394 #define ELFSIZE 64
395 #include "elfXX_exec.c"
396
397 #else
398 /* Old style */
399 int
400 elf32_exec(fd, elf, entryp, ssymp, esymp)
401 int fd;
402 Elf32_Ehdr *elf;
403 u_int64_t *entryp;
404 void **ssymp;
405 void **esymp;
406 {
407 Elf32_Shdr *shp;
408 Elf32_Off off;
409 void *addr;
410 size_t size;
411 int i, first = 1;
412 long align;
413 int n;
414
415 /*
416 * Don't display load address for ELF; it's encoded in
417 * each section.
418 */
419 #ifdef DEBUG
420 printf("elf_exec: ");
421 #endif
422 printf("Booting %s\n", opened_name);
423
424 for (i = 0; i < elf->e_phnum; i++) {
425 Elf32_Phdr phdr;
426 (void)lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET);
427 if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) {
428 printf("read phdr: %s\n", strerror(errno));
429 return (1);
430 }
431 if (phdr.p_type != PT_LOAD ||
432 (phdr.p_flags & (PF_W|PF_X)) == 0)
433 continue;
434
435 /* Read in segment. */
436 printf("%s%lu@0x%lx", first ? "" : "+", phdr.p_filesz,
437 (u_long)phdr.p_vaddr);
438 (void)lseek(fd, phdr.p_offset, SEEK_SET);
439
440 /*
441 * If the segment's VA is aligned on a 4MB boundary, align its
442 * request 4MB aligned physical memory. Otherwise use default
443 * alignment.
444 */
445 align = phdr.p_align;
446 if ((phdr.p_vaddr & (4*MEG-1)) == 0)
447 align = 4*MEG;
448 if (OF_claim((void *)phdr.p_vaddr, phdr.p_memsz, phdr.p_align) ==
449 (void *)-1)
450 panic("cannot claim memory");
451 if (read(fd, (void *)phdr.p_vaddr, phdr.p_filesz) !=
452 phdr.p_filesz) {
453 printf("read segment: %s\n", strerror(errno));
454 return (1);
455 }
456 syncicache((void *)phdr.p_vaddr, phdr.p_filesz);
457
458 /* Zero BSS. */
459 if (phdr.p_filesz < phdr.p_memsz) {
460 printf("+%lu@0x%lx", phdr.p_memsz - phdr.p_filesz,
461 (u_long)(phdr.p_vaddr + phdr.p_filesz));
462 bzero((void*)phdr.p_vaddr + phdr.p_filesz,
463 phdr.p_memsz - phdr.p_filesz);
464 }
465 first = 0;
466 }
467
468 printf(" \n");
469
470 #if 1 /* I want to rethink this... --thorpej (at) netbsd.org */
471 /*
472 * Compute the size of the symbol table.
473 */
474 size = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
475 shp = addr = alloc(elf->e_shnum * sizeof(Elf32_Shdr));
476 (void)lseek(fd, elf->e_shoff, SEEK_SET);
477 if (read(fd, addr, elf->e_shnum * sizeof(Elf32_Shdr)) !=
478 elf->e_shnum * sizeof(Elf32_Shdr)) {
479 printf("read section headers: %s\n", strerror(errno));
480 return (1);
481 }
482 for (i = 0; i < elf->e_shnum; i++, shp++) {
483 if (shp->sh_type == SHT_NULL)
484 continue;
485 if (shp->sh_type != SHT_SYMTAB
486 && shp->sh_type != SHT_STRTAB) {
487 shp->sh_offset = 0;
488 shp->sh_type = SHT_NOBITS;
489 continue;
490 }
491 size += shp->sh_size;
492 }
493 shp = addr;
494
495 /*
496 * Reserve memory for the symbols.
497 */
498 if ((addr = OF_claim(0, size, NBPG)) == (void *)-1)
499 panic("no space for symbol table");
500
501 /*
502 * Copy the headers.
503 */
504 elf->e_phoff = 0;
505 elf->e_shoff = sizeof(Elf32_Ehdr);
506 elf->e_phentsize = 0;
507 elf->e_phnum = 0;
508 bcopy(elf, addr, sizeof(Elf32_Ehdr));
509 bcopy(shp, addr + sizeof(Elf32_Ehdr), elf->e_shnum * sizeof(Elf32_Shdr));
510 free(shp, elf->e_shnum * sizeof(Elf32_Shdr));
511 *ssymp = addr;
512
513 /*
514 * Now load the symbol sections themselves.
515 */
516 shp = addr + sizeof(Elf32_Ehdr);
517 addr += sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
518 off = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
519 for (first = 1, i = 0; i < elf->e_shnum; i++, shp++) {
520 if (shp->sh_type == SHT_SYMTAB
521 || shp->sh_type == SHT_STRTAB) {
522 if (first)
523 printf("symbols @ 0x%lx ", (u_long)addr);
524 printf("%s%d", first ? "" : "+", shp->sh_size);
525 (void)lseek(fd, shp->sh_offset, SEEK_SET);
526 if (read(fd, addr, shp->sh_size) != shp->sh_size) {
527 printf("read symbols: %s\n", strerror(errno));
528 return (1);
529 }
530 addr += (shp->sh_size+3)&(~3);
531 shp->sh_offset = off;
532 off += (shp->sh_size+3)&(~3);
533 first = 0;
534 }
535 }
536 *esymp = addr;
537 #endif /* 0 */
538
539 *entryp = elf->e_entry;
540 return (0);
541 }
542 #endif
543 #endif /* SPARC_BOOT_ELF */
544
545 void
546 main()
547 {
548 extern char bootprog_name[], bootprog_rev[],
549 bootprog_maker[], bootprog_date[];
550 int chosen;
551 char bootline[512]; /* Should check size? */
552 char *cp;
553 int i, fd;
554
555 /* Initialize kernelname */
556 kernelname = kernels[0];
557
558 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
559 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
560
561 /*
562 * Get the boot arguments from Openfirmware
563 */
564 if ((chosen = OF_finddevice("/chosen")) == -1
565 || OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0
566 || OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) {
567 printf("Invalid Openfirmware environment\n");
568 exit();
569 }
570 /*prom2boot(bootdev);*/
571 kernelname = kernels[0];
572 parseargs(bootline, &boothowto);
573 for (i=0;;) {
574 kernelname = kernels[i];
575 if (boothowto & RB_ASKNAME) {
576 printf("Boot: ");
577 gets(bootline);
578 parseargs(bootline, &boothowto);
579 }
580 if ((fd = open(bootline, 0)) >= 0)
581 break;
582 if (errno)
583 printf("open %s: %s\n", opened_name, strerror(errno));
584 /*
585 * if we have are not in askname mode, and we aren't using the
586 * prom bootfile, try the next one (if it exits). otherwise,
587 * go into askname mode.
588 */
589 if ((boothowto & RB_ASKNAME) == 0 &&
590 i != -1 && kernels[++i]) {
591 printf(": trying %s...\n", kernels[i]);
592 } else {
593 printf("\n");
594 boothowto |= RB_ASKNAME;
595 }
596 }
597 #ifdef __notyet__
598 OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1);
599 cp = bootline;
600 #else
601 strcpy(bootline, opened_name);
602 cp = bootline + strlen(bootline);
603 *cp++ = ' ';
604 #endif
605 *cp = '-';
606 if (boothowto & RB_ASKNAME)
607 *++cp = 'a';
608 if (boothowto & RB_SINGLE)
609 *++cp = 's';
610 if (boothowto & RB_KDB)
611 *++cp = 'd';
612 if (*cp == '-')
613 #ifdef __notyet__
614 *cp = 0;
615 #else
616 *--cp = 0;
617 #endif
618 else
619 *++cp = 0;
620 #ifdef __notyet__
621 OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1);
622 #endif
623 /* XXX void, for now */
624 #ifdef DEBUG
625 if (debug)
626 printf("main: Calling loadfile(fd, %s)\n", bootline);
627 #endif
628 (void)loadfile(fd, bootline);
629
630 _rtt();
631 }
632