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