xref: /netbsd/sys/arch/sparc/stand/ofwboot/boot.c (revision c4a72b64)
1 /*	$NetBSD: boot.c,v 1.5 2002/10/20 20:55:38 martin 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 #include <sys/boot_flag.h>
59 
60 #include <machine/cpu.h>
61 
62 #include "ofdev.h"
63 #include "openfirm.h"
64 
65 #define	MEG	(1024*1024)
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 char *kernelname;
89 char bootdev[128];
90 char bootfile[128];
91 int boothowto;
92 int debug;
93 
94 
95 #ifdef SPARC_BOOT_ELF
96 int	elf32_exec __P((int, Elf32_Ehdr *, u_int64_t *, void **, void **));
97 int	elf64_exec __P((int, Elf64_Ehdr *, u_int64_t *, void **, void **));
98 #endif
99 
100 #ifdef SPARC_BOOT_AOUT
101 int	aout_exec __P((int, struct exec *, u_int64_t *, void **));
102 #endif
103 
104 #if 0
105 static void
106 prom2boot(dev)
107 	char *dev;
108 {
109 	char *cp, *lp = 0;
110 	int handle;
111 	char devtype[16];
112 
113 	for (cp = dev; *cp; cp++)
114 		if (*cp == ':')
115 			lp = cp;
116 	if (!lp)
117 		lp = cp;
118 	*lp = 0;
119 }
120 #endif
121 
122 static void
123 parseargs(str, howtop)
124 	char *str;
125 	int *howtop;
126 {
127 	char *cp;
128 	int i;
129 
130 	/* Allow user to drop back to the PROM. */
131 	if (strcmp(str, "exit") == 0 || strcmp(str, "halt") == 0)
132 		_rtt();
133 
134 	/* Insert the kernel name if it is not there. */
135 	if (str[0] == 0 || str[0] == '-') {
136 		/* Move args down the string */
137 		i=0;
138 		for (cp = str + strlen(kernelname); str[i]; i++)
139 			cp[i] = str[i];
140 		/* Copy over kernelname */
141 		for (i = 0; kernelname[i]; i++)
142 			str[i] = kernelname[i];
143 	}
144 	*howtop = 0;
145 	for (cp = str; *cp; cp++)
146 		if (*cp == ' ')
147 			break;
148 	if (!*cp)
149 		return;
150 
151 	*cp++ = 0;
152 	while (*cp) {
153 		BOOT_FLAG(*cp, *howtop);
154 		/* handle specialties */
155 		switch (*cp++) {
156 		case 'd':
157 			if (!debug) debug = 1;
158 			break;
159 		case 'D':
160 			debug = 2;
161 			break;
162 		default:
163 			break;
164 		}
165 	}
166 }
167 
168 
169 static void
170 chain(pentry, args, ssym, esym)
171 	u_int64_t pentry;
172 	char *args;
173 	void *ssym;
174 	void *esym;
175 {
176 	extern char end[];
177 	void (*entry)();
178 	int l, machine_tag;
179 	long newargs[3];
180 
181 	entry = (void*)(long)pentry;
182 
183 	freeall();
184 	/*
185 	 * When we come in args consists of a pointer to the boot
186 	 * string.  We need to fix it so it takes into account
187 	 * other params such as romp.
188 	 */
189 
190 	/*
191 	 * Stash pointer to end of symbol table after the argument
192 	 * strings.
193 	 */
194 	l = strlen(args) + 1;
195 	bcopy(&esym, args + l, sizeof(esym));
196 	l += sizeof(esym);
197 
198 	/*
199 	 * Tell the kernel we're an OpenFirmware system.
200 	 */
201 #define SPARC_MACHINE_OPENFIRMWARE		0x44444230
202 	machine_tag = SPARC_MACHINE_OPENFIRMWARE;
203 	bcopy(&machine_tag, args + l, sizeof(machine_tag));
204 	l += sizeof(machine_tag);
205 
206 	/*
207 	 * Since we don't need the boot string (we can get it from /chosen)
208 	 * we won't pass it in.  Just pass in esym and magic #
209 	 */
210 	newargs[0] = SPARC_MACHINE_OPENFIRMWARE;
211 	newargs[1] = (long)esym;
212 	newargs[2] = (long)ssym;
213 	args = (char *)newargs;
214 	l = sizeof(newargs);
215 
216 #ifdef DEBUG
217 	printf("chain: calling OF_chain(%x, %x, %x, %x, %x)\n",
218 	       (void *)RELOC, end - (char *)RELOC, entry, args, l);
219 #endif
220 	/* if -D is set then pause in the PROM. */
221 	if (debug > 1) OF_enter();
222 	OF_chain((void *)RELOC, ((end - (char *)RELOC)+NBPG)%NBPG, entry, args, l);
223 	panic("chain");
224 }
225 
226 int
227 loadfile(fd, args)
228 	int fd;
229 	char *args;
230 {
231 	union {
232 #ifdef SPARC_BOOT_AOUT
233 		struct exec aout;
234 #endif
235 #ifdef SPARC_BOOT_ELF
236 		Elf32_Ehdr elf32;
237 		Elf64_Ehdr elf64;
238 #endif
239 	} hdr;
240 	int rval;
241 	u_int64_t entry = 0;
242 	void *ssym;
243 	void *esym;
244 
245 	rval = 1;
246 	ssym = NULL;
247 	esym = NULL;
248 
249 	/* Load the header. */
250 #ifdef DEBUG
251 	printf("loadfile: reading header\n");
252 #endif
253 	if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
254 		printf("read header: %s\n", strerror(errno));
255 		goto err;
256 	}
257 
258 	/* Determine file type, load kernel. */
259 #ifdef SPARC_BOOT_AOUT
260 	if (N_BADMAG(hdr.aout) == 0 && N_GETMID(hdr.aout) == MID_SPARC) {
261 		rval = aout_exec(fd, &hdr.aout, &entry, &esym);
262 	} else
263 #endif
264 #ifdef SPARC_BOOT_ELF
265 	if (bcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
266 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
267 		rval = elf32_exec(fd, &hdr.elf32, &entry, &ssym, &esym);
268 	} else
269 	if (bcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
270 	    hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
271 		rval = elf64_exec(fd, &hdr.elf64, &entry, &ssym, &esym);
272 	} else
273 #endif
274 	{
275 		printf("unknown executable format\n");
276 	}
277 
278 	if (rval)
279 		goto err;
280 
281 	printf(" start=0x%lx\n", (unsigned long)entry);
282 
283 	close(fd);
284 
285 	/* XXX this should be replaced w/ a mountroothook. */
286 	if (floppyboot) {
287 		printf("Please insert root disk and press ENTER ");
288 		getchar();
289 		printf("\n");
290 	}
291 
292 	chain(entry, args, ssym, esym);
293 	/* NOTREACHED */
294 
295  err:
296 	close(fd);
297 	return (rval);
298 }
299 
300 #ifdef SPARC_BOOT_AOUT
301 int
302 aout_exec(fd, hdr, entryp, esymp)
303 	int fd;
304 	struct exec *hdr;
305 	u_int64_t *entryp;
306 	void **esymp;
307 {
308 	void *addr;
309 	int n, *paddr;
310 
311 #ifdef DEBUG
312 	printf("auout_exec: ");
313 #endif
314 	/* Display the load address (entry point) for a.out. */
315 	printf("Booting %s @ 0x%lx\n", opened_name, hdr->a_entry);
316 	addr = (void *)(hdr->a_entry);
317 
318 	/*
319 	 * Determine memory needed for kernel and allocate it from
320 	 * the firmware.
321 	 */
322 	n = hdr->a_text + hdr->a_data + hdr->a_bss + hdr->a_syms + sizeof(int);
323 	if ((paddr = OF_claim(addr, n, 0)) == (int *)-1)
324 		panic("cannot claim memory");
325 
326 	/* Load text. */
327 	lseek(fd, N_TXTOFF(*hdr), SEEK_SET);
328 	printf("%lu", hdr->a_text);
329 	if (read(fd, paddr, hdr->a_text) != hdr->a_text) {
330 		printf("read text: %s\n", strerror(errno));
331 		return (1);
332 	}
333 	syncicache((void *)paddr, hdr->a_text);
334 
335 	/* Load data. */
336 	printf("+%lu", hdr->a_data);
337 	if (read(fd, (void *)paddr + hdr->a_text, hdr->a_data) != hdr->a_data) {
338 		printf("read data: %s\n", strerror(errno));
339 		return (1);
340 	}
341 
342 	/* Zero BSS. */
343 	printf("+%lu", hdr->a_bss);
344 	bzero((void *)paddr + hdr->a_text + hdr->a_data, hdr->a_bss);
345 
346 	/* Symbols. */
347 	*esymp = paddr;
348 	paddr = (int *)((void *)paddr + hdr->a_text + hdr->a_data + hdr->a_bss);
349 	*paddr++ = hdr->a_syms;
350 	if (hdr->a_syms) {
351 		printf(" [%lu", hdr->a_syms);
352 		if (read(fd, paddr, hdr->a_syms) != hdr->a_syms) {
353 			printf("read symbols: %s\n", strerror(errno));
354 			return (1);
355 		}
356 		paddr = (int *)((void *)paddr + hdr->a_syms);
357 		if (read(fd, &n, sizeof(int)) != sizeof(int)) {
358 			printf("read symbols: %s\n", strerror(errno));
359 			return (1);
360 		}
361 		if (OF_claim((void *)paddr, n + sizeof(int), 0) == (void *)-1)
362 			panic("cannot claim memory");
363 		*paddr++ = n;
364 		if (read(fd, paddr, n - sizeof(int)) != n - sizeof(int)) {
365 			printf("read symbols: %s\n", strerror(errno));
366 			return (1);
367 		}
368 		printf("+%d]", n - sizeof(int));
369 		*esymp = paddr + (n - sizeof(int));
370 	}
371 
372 	*entryp = hdr->a_entry;
373 	return (0);
374 }
375 #endif /* SPARC_BOOT_AOUT */
376 
377 #ifdef SPARC_BOOT_ELF
378 #if 1
379 /* New style */
380 
381 #ifdef ELFSIZE
382 #undef ELFSIZE
383 #endif
384 
385 #define ELFSIZE	32
386 #include "elfXX_exec.c"
387 
388 #undef ELFSIZE
389 #define ELFSIZE	64
390 #include "elfXX_exec.c"
391 
392 #else
393 /* Old style */
394 int
395 elf32_exec(fd, elf, entryp, ssymp, esymp)
396 	int fd;
397 	Elf32_Ehdr *elf;
398 	u_int64_t *entryp;
399 	void **ssymp;
400 	void **esymp;
401 {
402 	Elf32_Shdr *shp;
403 	Elf32_Off off;
404 	void *addr;
405 	size_t size;
406 	int i, first = 1;
407 	long align;
408 	int n;
409 
410 	/*
411 	 * Don't display load address for ELF; it's encoded in
412 	 * each section.
413 	 */
414 #ifdef DEBUG
415 	printf("elf_exec: ");
416 #endif
417 	printf("Booting %s\n", opened_name);
418 
419 	for (i = 0; i < elf->e_phnum; i++) {
420 		Elf32_Phdr phdr;
421 		(void)lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET);
422 		if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) {
423 			printf("read phdr: %s\n", strerror(errno));
424 			return (1);
425 		}
426 		if (phdr.p_type != PT_LOAD ||
427 		    (phdr.p_flags & (PF_W|PF_X)) == 0)
428 			continue;
429 
430 		/* Read in segment. */
431 		printf("%s%lu@0x%lx", first ? "" : "+", phdr.p_filesz,
432 		    (u_long)phdr.p_vaddr);
433 		(void)lseek(fd, phdr.p_offset, SEEK_SET);
434 
435 		/*
436 		 * If the segment's VA is aligned on a 4MB boundary, align its
437 		 * request 4MB aligned physical memory.  Otherwise use default
438 		 * alignment.
439 		 */
440 		align = phdr.p_align;
441 		if ((phdr.p_vaddr & (4*MEG-1)) == 0)
442 			align = 4*MEG;
443 		if (OF_claim((void *)phdr.p_vaddr, phdr.p_memsz, phdr.p_align) ==
444 		    (void *)-1)
445 			panic("cannot claim memory");
446 		if (read(fd, (void *)phdr.p_vaddr, phdr.p_filesz) !=
447 		    phdr.p_filesz) {
448 			printf("read segment: %s\n", strerror(errno));
449 			return (1);
450 		}
451 		syncicache((void *)phdr.p_vaddr, phdr.p_filesz);
452 
453 		/* Zero BSS. */
454 		if (phdr.p_filesz < phdr.p_memsz) {
455 			printf("+%lu@0x%lx", phdr.p_memsz - phdr.p_filesz,
456 			    (u_long)(phdr.p_vaddr + phdr.p_filesz));
457 			bzero((void*)phdr.p_vaddr + phdr.p_filesz,
458 			    phdr.p_memsz - phdr.p_filesz);
459 		}
460 		first = 0;
461 	}
462 
463 	printf(" \n");
464 
465 #if 1 /* I want to rethink this... --thorpej@netbsd.org */
466 	/*
467 	 * Compute the size of the symbol table.
468 	 */
469 	size = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
470 	shp = addr = alloc(elf->e_shnum * sizeof(Elf32_Shdr));
471 	(void)lseek(fd, elf->e_shoff, SEEK_SET);
472 	if (read(fd, addr, elf->e_shnum * sizeof(Elf32_Shdr)) !=
473 	    elf->e_shnum * sizeof(Elf32_Shdr)) {
474 		printf("read section headers: %s\n", strerror(errno));
475 		return (1);
476 	}
477 	for (i = 0; i < elf->e_shnum; i++, shp++) {
478 		if (shp->sh_type == SHT_NULL)
479 			continue;
480 		if (shp->sh_type != SHT_SYMTAB
481 		    && shp->sh_type != SHT_STRTAB) {
482 			shp->sh_offset = 0;
483 			shp->sh_type = SHT_NOBITS;
484 			continue;
485 		}
486 		size += shp->sh_size;
487 	}
488 	shp = addr;
489 
490 	/*
491 	 * Reserve memory for the symbols.
492 	 */
493 	if ((addr = OF_claim(0, size, NBPG)) == (void *)-1)
494 		panic("no space for symbol table");
495 
496 	/*
497 	 * Copy the headers.
498 	 */
499 	elf->e_phoff = 0;
500 	elf->e_shoff = sizeof(Elf32_Ehdr);
501 	elf->e_phentsize = 0;
502 	elf->e_phnum = 0;
503 	bcopy(elf, addr, sizeof(Elf32_Ehdr));
504 	bcopy(shp, addr + sizeof(Elf32_Ehdr), elf->e_shnum * sizeof(Elf32_Shdr));
505 	free(shp, elf->e_shnum * sizeof(Elf32_Shdr));
506 	*ssymp = addr;
507 
508 	/*
509 	 * Now load the symbol sections themselves.
510 	 */
511 	shp = addr + sizeof(Elf32_Ehdr);
512 	addr += sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
513 	off = sizeof(Elf32_Ehdr) + (elf->e_shnum * sizeof(Elf32_Shdr));
514 	for (first = 1, i = 0; i < elf->e_shnum; i++, shp++) {
515 		if (shp->sh_type == SHT_SYMTAB
516 		    || shp->sh_type == SHT_STRTAB) {
517 			if (first)
518 				printf("symbols @ 0x%lx ", (u_long)addr);
519 			printf("%s%d", first ? "" : "+", shp->sh_size);
520 			(void)lseek(fd, shp->sh_offset, SEEK_SET);
521 			if (read(fd, addr, shp->sh_size) != shp->sh_size) {
522 				printf("read symbols: %s\n", strerror(errno));
523 				return (1);
524 			}
525 			addr += (shp->sh_size+3)&(~3);
526 			shp->sh_offset = off;
527 			off += (shp->sh_size+3)&(~3);
528 			first = 0;
529 		}
530 	}
531 	*esymp = addr;
532 #endif /* 0 */
533 
534 	*entryp = elf->e_entry;
535 	return (0);
536 }
537 #endif
538 #endif /* SPARC_BOOT_ELF */
539 
540 void
541 main()
542 {
543 	extern char bootprog_name[], bootprog_rev[],
544 	    bootprog_maker[], bootprog_date[];
545 	int chosen;
546 	char bootline[512];		/* Should check size? */
547 	char *cp;
548 	int i, fd;
549 
550 	/* Initialize kernelname */
551 	kernelname = kernels[0];
552 
553 	printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
554 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
555 
556 	/*
557 	 * Get the boot arguments from Openfirmware
558 	 */
559 	if ((chosen = OF_finddevice("/chosen")) == -1
560 	    || OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0
561 	    || OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) {
562 		printf("Invalid Openfirmware environment\n");
563 		exit(0);
564 	}
565 	/*prom2boot(bootdev);*/
566 	kernelname = kernels[0];
567 	parseargs(bootline, &boothowto);
568 	for (i=0;;) {
569 		kernelname = kernels[i];
570 		if (boothowto & RB_ASKNAME) {
571 			printf("Boot: ");
572 			gets(bootline);
573 			parseargs(bootline, &boothowto);
574 		}
575 		if ((fd = open(bootline, 0)) >= 0)
576 			break;
577 		if (errno)
578 			printf("open %s: %s\n", opened_name, strerror(errno));
579 		/*
580 		 * if we have are not in askname mode, and we aren't using the
581 		 * prom bootfile, try the next one (if it exits).  otherwise,
582 		 * go into askname mode.
583 		 */
584 		if ((boothowto & RB_ASKNAME) == 0 &&
585 		    i != -1 && kernels[++i]) {
586 			printf(": trying %s...\n", kernels[i]);
587 		} else {
588 			printf("\n");
589 			boothowto |= RB_ASKNAME;
590 		}
591 	}
592 #ifdef	__notyet__
593 	OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1);
594 	cp = bootline;
595 #else
596 	strcpy(bootline, opened_name);
597 	cp = bootline + strlen(bootline);
598 	*cp++ = ' ';
599 #endif
600 	*cp = '-';
601 	if (boothowto & RB_ASKNAME)
602 		*++cp = 'a';
603 	if (boothowto & RB_SINGLE)
604 		*++cp = 's';
605 	if (boothowto & RB_KDB)
606 		*++cp = 'd';
607 	if (*cp == '-')
608 #ifdef	__notyet__
609 		*cp = 0;
610 #else
611 		*--cp = 0;
612 #endif
613 	else
614 		*++cp = 0;
615 #ifdef	__notyet__
616 	OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1);
617 #endif
618 	/* XXX void, for now */
619 #ifdef DEBUG
620 	if (debug)
621 		printf("main: Calling loadfile(fd, %s)\n", bootline);
622 #endif
623 	(void)loadfile(fd, bootline);
624 
625 	_rtt();
626 }
627