boot.c revision 1.2 1 /* $NetBSD: boot.c,v 1.2 1998/07/13 17:38:37 tsubai Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
41 * Copyright (C) 1995, 1996 TooLs GmbH.
42 * All rights reserved.
43 *
44 * ELF support derived from NetBSD/alpha's boot loader, written
45 * by Christopher G. Demetriou.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 * must display the following acknowledgement:
57 * This product includes software developed by TooLs GmbH.
58 * 4. The name of TooLs GmbH may not be used to endorse or promote products
59 * derived from this software without specific prior written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
64 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
65 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
66 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
67 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
68 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
69 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
70 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
71 */
72
73 /*
74 * First try for the boot code
75 *
76 * Input syntax is:
77 * [promdev[{:|,}partition]]/[filename] [flags]
78 */
79
80 #define ELFSIZE 32 /* We use 32-bit ELF. */
81
82 #include <sys/param.h>
83 #include <sys/exec.h>
84 #include <sys/exec_elf.h>
85 #include <sys/reboot.h>
86 #include <sys/disklabel.h>
87
88 #include <lib/libsa/stand.h>
89 #include <lib/libkern/libkern.h>
90
91 #include <machine/cpu.h>
92 #include <machine/machine_type.h>
93
94 #include "ofdev.h"
95 #include "openfirm.h"
96
97 char bootdev[128];
98 char bootfile[128];
99 int boothowto;
100 int debug;
101
102 #ifdef POWERPC_BOOT_ELF
103 int elf_exec __P((int, Elf_Ehdr *, u_int32_t *, void **));
104 #endif
105
106 #ifdef POWERPC_BOOT_AOUT
107 int aout_exec __P((int, struct exec *, u_int32_t *, void **));
108 #endif
109
110 static void
111 prom2boot(dev)
112 char *dev;
113 {
114 char *cp;
115
116 for (cp = dev; *cp != '\0'; cp++)
117 if (*cp == ':') {
118 *cp = '\0';
119 return;
120 }
121 }
122
123 static void
124 parseargs(str, howtop)
125 char *str;
126 int *howtop;
127 {
128 char *cp;
129
130 /* Allow user to drop back to the PROM. */
131 if (strcmp(str, "exit") == 0)
132 OF_exit();
133
134 *howtop = 0;
135 for (cp = str; *cp; cp++)
136 if (*cp == ' ' || *cp == '-')
137 break;
138 if (!*cp)
139 return;
140
141 *cp++ = 0;
142 while (*cp) {
143 switch (*cp++) {
144 case 'a':
145 *howtop |= RB_ASKNAME;
146 break;
147 case 's':
148 *howtop |= RB_SINGLE;
149 break;
150 case 'd':
151 *howtop |= RB_KDB;
152 debug = 1;
153 break;
154 }
155 }
156 }
157
158 static void
159 chain(entry, args, esym)
160 void (*entry)();
161 char *args;
162 void *esym;
163 {
164 extern char end[];
165 int l, machine_tag;
166
167 freeall();
168
169 /*
170 * Stash pointer to end of symbol table after the argument
171 * strings.
172 */
173 l = strlen(args) + 1;
174 bcopy(&esym, args + l, sizeof(esym));
175 l += sizeof(esym);
176
177 /*
178 * Tell the kernel we're an OpenFirmware system.
179 */
180 machine_tag = POWERPC_MACHINE_OPENFIRMWARE;
181 bcopy(&machine_tag, args + l, sizeof(machine_tag));
182 l += sizeof(machine_tag);
183
184 OF_chain((void *)RELOC, end - (char *)RELOC, entry, args, l);
185 panic("chain");
186 }
187
188 int
189 loadfile(fd, args)
190 int fd;
191 char *args;
192 {
193 union {
194 #ifdef POWERPC_BOOT_AOUT
195 struct exec aout;
196 #endif
197 #ifdef POWERPC_BOOT_ELF
198 Elf_Ehdr elf;
199 #endif
200 } hdr;
201 int rval;
202 u_int32_t entry;
203 void *esym;
204
205 rval = 1;
206 esym = NULL;
207
208 /* Load the header. */
209 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
210 printf("read header: %s\n", strerror(errno));
211 goto err;
212 }
213
214 /* Determine file type, load kernel. */
215 #ifdef POWERPC_BOOT_AOUT
216 if (N_BADMAG(hdr.aout) == 0 && N_GETMID(hdr.aout) == MID_POWERPC) {
217 rval = aout_exec(fd, &hdr.aout, &entry, &esym);
218 } else
219 #endif
220 #ifdef POWERPC_BOOT_ELF
221 if (memcmp(Elf_e_ident, hdr.elf.e_ident, Elf_e_siz) == 0) {
222 rval = elf_exec(fd, &hdr.elf, &entry, &esym);
223 } else
224 #endif
225 {
226 printf("unknown executable format\n");
227 }
228
229 if (rval)
230 goto err;
231
232 printf(" start=0x%x\n", entry);
233
234 close(fd);
235
236 /* XXX this should be replaced w/ a mountroothook. */
237 if (floppyboot) {
238 printf("Please insert root disk and press ENTER ");
239 getchar();
240 printf("\n");
241 }
242
243 chain((void *)entry, args, esym);
244 /* NOTREACHED */
245
246 err:
247 close(fd);
248 return (rval);
249 }
250
251 __dead void
252 _rtt()
253 {
254
255 OF_exit();
256 }
257
258 #ifdef POWERPC_BOOT_AOUT
259 int
260 aout_exec(fd, hdr, entryp, esymp)
261 int fd;
262 struct exec *hdr;
263 u_int32_t *entryp;
264 void **esymp;
265 {
266 void *addr;
267 int n, *paddr;
268
269 /* Display the load address (entry point) for a.out. */
270 printf("Booting %s @ 0x%lx\n", opened_name, hdr->a_entry);
271 addr = (void *)(hdr->a_entry);
272
273 /*
274 * Determine memory needed for kernel and allocate it from
275 * the firmware.
276 */
277 n = hdr->a_text + hdr->a_data + hdr->a_bss + hdr->a_syms + sizeof(int);
278 if ((paddr = OF_claim(addr, n, 0)) == (int *)-1)
279 panic("cannot claim memory");
280
281 /* Load text. */
282 lseek(fd, N_TXTOFF(*hdr), SEEK_SET);
283 printf("%lu", hdr->a_text);
284 if (read(fd, paddr, hdr->a_text) != hdr->a_text) {
285 printf("read text: %s\n", strerror(errno));
286 return (1);
287 }
288 syncicache((void *)paddr, hdr->a_text);
289
290 /* Load data. */
291 printf("+%lu", hdr->a_data);
292 if (read(fd, (void *)paddr + hdr->a_text, hdr->a_data) != hdr->a_data) {
293 printf("read data: %s\n", strerror(errno));
294 return (1);
295 }
296
297 /* Zero BSS. */
298 printf("+%lu", hdr->a_bss);
299 bzero((void *)paddr + hdr->a_text + hdr->a_data, hdr->a_bss);
300
301 /* Symbols. */
302 *esymp = paddr;
303 paddr = (int *)((void *)paddr + hdr->a_text + hdr->a_data + hdr->a_bss);
304 *paddr++ = hdr->a_syms;
305 if (hdr->a_syms) {
306 printf(" [%lu", hdr->a_syms);
307 if (read(fd, paddr, hdr->a_syms) != hdr->a_syms) {
308 printf("read symbols: %s\n", strerror(errno));
309 return (1);
310 }
311 paddr = (int *)((void *)paddr + hdr->a_syms);
312 if (read(fd, &n, sizeof(int)) != sizeof(int)) {
313 printf("read symbols: %s\n", strerror(errno));
314 return (1);
315 }
316 if (OF_claim((void *)paddr, n + sizeof(int), 0) == (void *)-1)
317 panic("cannot claim memory");
318 *paddr++ = n;
319 if (read(fd, paddr, n - sizeof(int)) != n - sizeof(int)) {
320 printf("read symbols: %s\n", strerror(errno));
321 return (1);
322 }
323 printf("+%d]", n - sizeof(int));
324 *esymp = paddr + (n - sizeof(int));
325 }
326
327 *entryp = hdr->a_entry;
328 return (0);
329 }
330 #endif /* POWERPC_BOOT_AOUT */
331
332 #ifdef POWERPC_BOOT_ELF
333 int
334 elf_exec(fd, elf, entryp, esymp)
335 int fd;
336 Elf_Ehdr *elf;
337 u_int32_t *entryp;
338 void **esymp;
339 {
340 Elf32_Shdr *shp;
341 Elf32_Off off;
342 void *addr;
343 size_t size;
344 int i, first = 1;
345 int n;
346
347 /*
348 * Don't display load address for ELF; it's encoded in
349 * each section.
350 */
351 printf("Booting %s\n", opened_name);
352
353 for (i = 0; i < elf->e_phnum; i++) {
354 Elf_Phdr phdr;
355 (void)lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET);
356 if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) {
357 printf("read phdr: %s\n", strerror(errno));
358 return (1);
359 }
360 if (phdr.p_type != Elf_pt_load ||
361 (phdr.p_flags & (Elf_pf_w|Elf_pf_x)) == 0)
362 continue;
363
364 /* Read in segment. */
365 printf("%s%lu@0x%lx", first ? "" : "+", phdr.p_filesz,
366 (u_long)phdr.p_vaddr);
367 (void)lseek(fd, phdr.p_offset, SEEK_SET);
368 if (OF_claim((void *)phdr.p_vaddr, phdr.p_memsz, 0) ==
369 (void *)-1)
370 panic("cannot claim memory");
371 if (read(fd, (void *)phdr.p_vaddr, phdr.p_filesz) !=
372 phdr.p_filesz) {
373 printf("read segment: %s\n", strerror(errno));
374 return (1);
375 }
376 syncicache((void *)phdr.p_vaddr, phdr.p_filesz);
377
378 /* Zero BSS. */
379 if (phdr.p_filesz < phdr.p_memsz) {
380 printf("+%lu@0x%lx", phdr.p_memsz - phdr.p_filesz,
381 (u_long)(phdr.p_vaddr + phdr.p_filesz));
382 bzero((void *)phdr.p_vaddr + phdr.p_filesz,
383 phdr.p_memsz - phdr.p_filesz);
384 }
385 first = 0;
386 }
387
388 printf(" \n");
389
390 #if 0 /* I want to rethink this... --thorpej (at) netbsd.org */
391 /*
392 * Compute the size of the symbol table.
393 */
394 size = sizeof(Elf_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
395 shp = addr = alloc(elf->e_shnum * sizeof(Elf32_Shdr));
396 (void)lseek(fd, elf->e_shoff, SEEK_SET);
397 if (read(fd, addr, elf->e_shnum * sizeof(Elf32_Shdr)) !=
398 elf->e_shnum * sizeof(Elf32_Shdr)) {
399 printf("read section headers: %s\n", strerror(errno));
400 return (1);
401 }
402 for (i = 0; i < elf->e_shnum; i++, shp++) {
403 if (shp->sh_type == Elf_sht_null)
404 continue;
405 if (shp->sh_type != Elf_sht_symtab
406 && shp->sh_type != Elf_sht_strtab) {
407 shp->sh_offset = 0;
408 shp->sh_type = Elf_sht_nobits;
409 continue;
410 }
411 size += shp->sh_size;
412 }
413 shp = addr;
414
415 /*
416 * Reserve memory for the symbols.
417 */
418 if ((addr = OF_claim(0, size, NBPG)) == (void *)-1)
419 panic("no space for symbol table");
420
421 /*
422 * Copy the headers.
423 */
424 elf->e_phoff = 0;
425 elf->e_shoff = sizeof(Elf_Ehdr);
426 elf->e_phentsize = 0;
427 elf->e_phnum = 0;
428 bcopy(elf, addr, sizeof(Elf_Ehdr));
429 bcopy(shp, addr + sizeof(Elf_Ehdr), elf->e_shnum * sizeof(Elf32_Shdr));
430 free(shp, elf->e_shnum * sizeof(Elf32_Shdr));
431 *ssymp = addr;
432
433 /*
434 * Now load the symbol sections themselves.
435 */
436 shp = addr + sizeof(Elf_Ehdr);
437 addr += sizeof(Elf_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
438 off = sizeof(Elf_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
439 for (first = 1, i = 0; i < elf->e_shnum; i++, shp++) {
440 if (shp->sh_type == Elf_sht_symtab
441 || shp->sh_type == Elf_sht_strtab) {
442 if (first)
443 printf("symbols @ 0x%lx ", (u_long)addr);
444 printf("%s%d", first ? "" : "+", shp->sh_size);
445 (void)lseek(fd, shp->sh_offset, SEEK_SET);
446 if (read(fd, addr, shp->sh_size) != shp->sh_size) {
447 printf("read symbols: %s\n", strerror(errno));
448 return (1);
449 }
450 addr += shp->sh_size;
451 shp->sh_offset = off;
452 off += shp->sh_size;
453 first = 0;
454 }
455 }
456 *esymp = addr;
457 #endif /* 0 */
458
459 *entryp = elf->e_entry;
460 return (0);
461 }
462 #endif /* POWERPC_BOOT_ELF */
463
464 void
465 main()
466 {
467 extern char bootprog_name[], bootprog_rev[],
468 bootprog_maker[], bootprog_date[];
469 int chosen, options;
470 char bootline[512]; /* Should check size? */
471 char *cp;
472 int fd;
473
474 printf("\n");
475 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
476 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
477
478 /*
479 * Get the boot arguments from Openfirmware
480 */
481 if ((chosen = OF_finddevice("/chosen")) == -1 ||
482 OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 ||
483 OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) {
484 printf("Invalid Openfirmware environment\n");
485 OF_exit();
486 }
487
488 /*
489 * Some versions of Openfirmware sets bootpath to "".
490 * We use boot-device instead if it occurs.
491 */
492 if (bootdev[0] == 0) {
493 printf("Cannot use bootpath\n");
494 if ((options = OF_finddevice("/options")) == -1 ||
495 OF_getprop(options, "boot-device", bootdev,
496 sizeof bootdev) < 0) {
497 printf("Invalid Openfirmware environment\n");
498 OF_exit();
499 }
500 printf("Using boot-device instead\n");
501 }
502
503 prom2boot(bootdev);
504 parseargs(bootline, &boothowto);
505
506 for (;;) {
507 if (boothowto & RB_ASKNAME) {
508 printf("Boot: ");
509 gets(bootline);
510 parseargs(bootline, &boothowto);
511 }
512 if ((fd = open(bootline, 0)) >= 0)
513 break;
514 if (errno)
515 printf("open %s: %s\n", opened_name, strerror(errno));
516 boothowto |= RB_ASKNAME;
517 }
518 #ifdef __notyet__
519 OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1);
520 cp = bootline;
521 #else
522 strcpy(bootline, opened_name);
523 cp = bootline + strlen(bootline);
524 *cp++ = ' ';
525 #endif
526 *cp = '-';
527 if (boothowto & RB_ASKNAME)
528 *++cp = 'a';
529 if (boothowto & RB_SINGLE)
530 *++cp = 's';
531 if (boothowto & RB_KDB)
532 *++cp = 'd';
533 if (*cp == '-')
534 #ifdef __notyet__
535 *cp = 0;
536 #else
537 *--cp = 0;
538 #endif
539 else
540 *++cp = 0;
541 #ifdef __notyet__
542 OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1);
543 #endif
544 /* XXX void, for now */
545 (void)loadfile(fd, bootline);
546
547 OF_exit();
548 }
549