Home | History | Annotate | Line # | Download | only in ofwboot
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