diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2002-08-11 23:11:23 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2002-08-11 23:11:23 +0000 |
commit | fb6a32c2912aeedcccd7059407d495ad4a6e1421 (patch) | |
tree | 672650a8219bca690a2ac97afbb746a902db97b3 /sys/arch/sparc | |
parent | 1c9a674781a04c62693d9e96cee8c3d61d7270bb (diff) |
ELF support in sparc bootblocks.
Loadfile is from alpha, but heaviliy hacked here.
The build is done by building elf versions of boot and bootxx, then
merging the .rodata and .text sections into .text with a horrible hack
and then using objcopy to convert that into a.out.
Maybe someone will want to fix installboot to deal with ELF instead, but
I won't be that someone in the nearest future.
Diffstat (limited to 'sys/arch/sparc')
-rw-r--r-- | sys/arch/sparc/stand/boot/Makefile | 21 | ||||
-rw-r--r-- | sys/arch/sparc/stand/boot/boot.c | 175 | ||||
-rw-r--r-- | sys/arch/sparc/stand/boot/loadfile.c | 315 | ||||
-rw-r--r-- | sys/arch/sparc/stand/bootxx/Makefile | 13 | ||||
-rw-r--r-- | sys/arch/sparc/stand/bootxx/bootxx.c | 4 |
5 files changed, 349 insertions, 179 deletions
diff --git a/sys/arch/sparc/stand/boot/Makefile b/sys/arch/sparc/stand/boot/Makefile index 078cde65973..1c74591bab0 100644 --- a/sys/arch/sparc/stand/boot/Makefile +++ b/sys/arch/sparc/stand/boot/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.9 2000/02/19 15:38:24 deraadt Exp $ +# $OpenBSD: Makefile,v 1.10 2002/08/11 23:11:22 art Exp $ # $NetBSD: Makefile,v 1.2 1995/09/30 21:43:38 pk Exp $ .PATH: ${.CURDIR}/../common @@ -9,16 +9,25 @@ NOMAN= noman INSTALL_STRIP= SRCS= srt0.S boot.c conf.c dvma.c net.c netif_sun.c promdev.c version.c +SRCS+= loadfile.c CFLAGS= -O2 -I${.CURDIR}/../common -I${.CURDIR}/../../../../arch \ - -I${.CURDIR}/../../../.. -I${.CURDIR}/../../../../lib/libsa ${DEFS} + -I${.CURDIR}/../../../.. -I${.CURDIR}/../../../../lib/libsa ${DEFS} \ + -DSPARC_BOOT_AOUT -DSPARC_BOOT_ELF -${PROG}: ${OBJS} ${LIBS} - ${LD} -N -T ${RELOC2} -e start ${OBJS} ${LIBSA} ${LIBKERN} ${LIBZ} `cc -print-libgcc-file-name` - # convert to Sun magic +CLEANFILES+=${PROG}.aout ${PROG}.elf +LIBS=${LIBSA} ${LIBKERN} ${LIBZ} + +elfclean: clean-elf.c + ${HOSTCC} -o elfclean ${.ALLSRC} + +${PROG}: ${OBJS} ${LIBS} elfclean + ${LD} -N -Ttext ${RELOC2} --format a.out-sparc-netbsd -e start ${OBJS} ${LIBSA} ${LIBKERN} ${LIBZ} `cc -print-libgcc-file-name` -o elf + ./elfclean elf + objcopy -j .text -j .data -j .bss -O a.out-sparc-netbsd elf a.out @size a.out (echo -n 01 | tr 01 '\01\03'; tail +3c a.out) > ${.TARGET} - @rm a.out + @rm a.out elf srt0.o: srt0.S ${CC} ${CFLAGS} -D_LOCORE -c ${.IMPSRC} diff --git a/sys/arch/sparc/stand/boot/boot.c b/sys/arch/sparc/stand/boot/boot.c index 827e18955a1..cde1a0bda70 100644 --- a/sys/arch/sparc/stand/boot/boot.c +++ b/sys/arch/sparc/stand/boot/boot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: boot.c,v 1.3 2002/03/14 01:26:44 millert Exp $ */ +/* $OpenBSD: boot.c,v 1.4 2002/08/11 23:11:22 art Exp $ */ /* $NetBSD: boot.c,v 1.2 1997/09/14 19:27:21 pk Exp $ */ /*- @@ -53,20 +53,19 @@ int netif_debug; */ #define DEFAULT_KERNEL "bsd" -extern char *version; -unsigned long esym; -char *strtab; -int strtablen; -char fbuf[80], dbuf[128]; +extern char *version; +extern vaddr_t esym; +char fbuf[80], dbuf[128]; typedef void (*entry_t)(caddr_t, int, int, int, long, long); +int loadfile(int, vaddr_t *); -void loadfile(int, caddr_t); main() { int io; char *file; + entry_t entry; prom_init(); @@ -94,169 +93,11 @@ main() } printf("Booting %s @ 0x%x\n", file, LOADADDR); - loadfile(io, LOADADDR); - - _rtt(); -} - -void -loadfile(io, addr) - register int io; - register caddr_t addr; -{ - register entry_t entry = (entry_t)LOADADDR; - struct exec x; - int i; - - i = read(io, (char *)&x, sizeof(x)); - if (i != sizeof(x) || - N_BADMAG(x)) { - printf("Bad format\n"); - return; - } - printf("%d", x.a_text); - if (N_GETMAGIC(x) == ZMAGIC) { - entry = (entry_t)(addr+sizeof(struct exec)); - addr += sizeof(struct exec); - } - if (read(io, (char *)addr, x.a_text) != x.a_text) - goto shread; - addr += x.a_text; - if (N_GETMAGIC(x) == ZMAGIC || N_GETMAGIC(x) == NMAGIC) - while ((int)addr & __LDPGSZ) - *addr++ = 0; - printf("+%d", x.a_data); - if (read(io, addr, x.a_data) != x.a_data) - goto shread; - addr += x.a_data; - printf("+%d", x.a_bss); - for (i = x.a_bss; i ; --i) - *addr++ = 0; - if (x.a_syms != 0) { - bcopy(&x.a_syms, addr, sizeof(x.a_syms)); - addr += sizeof(x.a_syms); - printf("+[%d", x.a_syms); - if (read(io, addr, x.a_syms) != x.a_syms) - goto shread; - addr += x.a_syms; - - if (read(io, &strtablen, sizeof(int)) != sizeof(int)) - goto shread; - - bcopy(&strtablen, addr, sizeof(int)); - if (i = strtablen) { - i -= sizeof(int); - addr += sizeof(int); - if (read(io, addr, i) != i) - goto shread; - addr += i; - } - printf("+%d]", i); - esym = ((u_int)x.a_entry - (u_int)LOADADDR) + - (((int)addr + sizeof(int) - 1) & ~(sizeof(int) - 1)); -#if 0 - /* - * The FORTH word `loadsyms' is mentioned in the - * "Openboot command reference" book, but it seems it has - * not been implemented on at least one machine.. - */ - promsyms(io, &x); -#endif - } - printf("=0x%x\n", addr); - close(io); + loadfile(io, (vaddr_t *)&entry); /* Note: args 2-4 not used due to conflicts with SunOS loaders */ (*entry)(cputyp == CPU_SUN4 ? LOADADDR : (caddr_t)promvec, 0, 0, 0, esym, DDB_MAGIC1); - return; - -shread: - printf("boot: short read\n"); - return; -} -#if 0 -struct syms { - u_int32_t value; - u_int32_t index; -}; - -void -sort(syms, n) - struct syms *syms; - int n; -{ - register struct syms *sj; - register int i, j, k; - register u_int32_t value, index; - - /* Insertion sort. This is O(n^2), but so what? */ - for (i = 1; i < n; i++) { - /* save i'th entry */ - value = syms[i].value; - index = syms[i].index; - /* find j such that i'th entry goes before j'th */ - for (j = 0, sj = syms; j < i; j++, sj++) - if (value < sj->value) - break; - /* slide up any additional entries */ - for (k = 0; k < (i - j); k++) { - sj[k+1].value = sj[k].value; - sj[k+1].index = sj[k].index; - } - sj->value = value; - sj->index = index; - } -} - -void -promsyms(fd, hp) - int fd; - struct exec *hp; -{ - int i, n, strtablen; - char *str, *p, *cp, buf[128]; - struct syms *syms; - - lseek(fd, sizeof(*hp)+hp->a_text+hp->a_data, SEEK_SET); - n = hp->a_syms/sizeof(struct nlist); - if (n == 0) - return; - syms = (struct syms *)alloc(n * sizeof(struct syms)); - - printf("+[%x+", hp->a_syms); - for (i = 0; i < n; i++) { - struct nlist nlist; - - if (read(fd, &nlist, sizeof(nlist)) != sizeof(nlist)) { - printf("promsyms: read failed\n"); - return; - } - syms[i].value = nlist.n_value; - syms[i].index = nlist.n_un.n_strx - sizeof(strtablen); - } - - sort(syms, n); - - if (read(fd, &strtablen, sizeof(strtablen)) != sizeof(strtablen)) { - printf("promsym: read failed (strtablen)\n"); - return; - } - if (strtablen < sizeof(strtablen)) { - printf("promsym: string table corrupted\n"); - return; - } - strtablen -= sizeof(strtablen); - str = (char *)alloc(strtablen); - - printf("%x]", strtablen); - if (read(fd, str, strtablen) != strtablen) { - printf("promsym: read failed (strtab)\n"); - return; - } - - sprintf(buf, "%x %d %x loadsyms", syms, n, str); - (promvec->pv_fortheval.v2_eval)(buf); + _rtt(); } -#endif diff --git a/sys/arch/sparc/stand/boot/loadfile.c b/sys/arch/sparc/stand/boot/loadfile.c new file mode 100644 index 00000000000..2aa044cd673 --- /dev/null +++ b/sys/arch/sparc/stand/boot/loadfile.c @@ -0,0 +1,315 @@ +/* $OpenBSD: loadfile.c,v 1.1 2002/08/11 23:11:22 art Exp $ */ +/* $NetBSD: loadfile.c,v 1.3 1997/04/06 08:40:59 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)boot.c 8.1 (Berkeley) 6/10/93 + */ + +#define ELFSIZE 32 + +#include <lib/libkern/libkern.h> +#include <lib/libsa/stand.h> +#include <sparc/stand/common/promdev.h> + +#include <sys/param.h> +#include <sys/exec.h> +#include <sys/exec_elf.h> + +#include <ddb/db_aout.h> + +#ifdef SPARC_BOOT_AOUT +static int aout_exec(int, struct exec *, vaddr_t *); +#endif +#ifdef SPARC_BOOT_ELF +static int elf_exec(int, Elf_Ehdr *, vaddr_t *); +#endif +int loadfile(int, vaddr_t *); + +vaddr_t ssym, esym; + +/* + * Open 'filename', read in program and return the entry point or -1 if error. + */ +int +loadfile(int fd, vaddr_t *entryp) +{ + struct devices *dp; + union { +#ifdef SPARC_BOOT_AOUT + struct exec aout; +#endif +#ifdef SPARC_BOOT_ELF + Elf_Ehdr elf; +#endif + } hdr; + int rval; + + /* Read the exec header. */ + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + printf("read header: %s\n", strerror(errno)); + goto err; + } + +#ifdef SPARC_BOOT_ELF + if (memcmp(ELFMAG, hdr.elf.e_ident, SELFMAG) == 0) { + rval = elf_exec(fd, &hdr.elf, entryp); + } else +#endif +#ifdef SPARC_BOOT_AOUT + if (!N_BADMAG(hdr.aout)) { + rval = aout_exec(fd, &hdr.aout, entryp); + } else +#endif + { + printf("unknown executable format\n"); + } + +err: + if (fd >= 0) + close(fd); + return (rval); +} + +#ifdef SPARC_BOOT_AOUT +static int +aout_exec(int fd, struct exec *aout, vaddr_t *entryp) +{ + caddr_t addr = (caddr_t)LOADADDR; + int strtablen; + char *strtab; + vaddr_t entry = (vaddr_t)LOADADDR; + int i; + + printf("%d", aout->a_text); + lseek(fd, sizeof(struct exec), SEEK_SET); + if (N_GETMAGIC(*aout) == ZMAGIC) { + entry = (vaddr_t)(addr+sizeof(struct exec)); + addr += sizeof(struct exec); + } + if (read(fd, (char *)addr, aout->a_text) != aout->a_text) + goto shread; + addr += aout->a_text; + if (N_GETMAGIC(*aout) == ZMAGIC || N_GETMAGIC(*aout) == NMAGIC) + while ((int)addr & __LDPGSZ) + *addr++ = 0; + printf("+%d", aout->a_data); + if (read(fd, addr, aout->a_data) != aout->a_data) + goto shread; + addr += aout->a_data; + printf("+%d", aout->a_bss); + for (i = aout->a_bss; i ; --i) + *addr++ = 0; + if (aout->a_syms != 0) { + bcopy(&aout->a_syms, addr, sizeof(aout->a_syms)); + addr += sizeof(aout->a_syms); + printf("+[%d", aout->a_syms); + if (read(fd, addr, aout->a_syms) != aout->a_syms) + goto shread; + addr += aout->a_syms; + + if (read(fd, &strtablen, sizeof(int)) != sizeof(int)) + goto shread; + + bcopy(&strtablen, addr, sizeof(int)); + if (i = strtablen) { + i -= sizeof(int); + addr += sizeof(int); + if (read(fd, addr, i) != i) + goto shread; + addr += i; + } + printf("+%d]", i); + esym = ((u_int)aout->a_entry - (u_int)LOADADDR) + + (((int)addr + sizeof(int) - 1) & ~(sizeof(int) - 1)); + } + printf("=0x%x\n", addr); + close(fd); + + *entryp = entry; + return (0); + +shread: + printf("boot: short read\n"); + return (1); +} +#endif /* SPARC_BOOT_AOUT */ + +#ifdef SPARC_BOOT_ELF +static int +elf_exec(int fd, Elf_Ehdr *elf, vaddr_t *entryp) +{ + int i; + int first = 1, havesyms; + Elf_Shdr *shp; + Elf_Off off; + size_t sz; + vaddr_t addr = 0; + Elf_Ehdr *fake_elf; + + *entryp = 0; + +#define A(x) ((x) - *entryp + (vaddr_t)LOADADDR) + + /* loop through the pheaders and find the entry point. */ + for (i = 0; i < elf->e_phnum; i++) { + Elf_Phdr phdr; + lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET); + if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) { + (void)printf("read phdr: %s\n", strerror(errno)); + return (1); + } + if (phdr.p_type != PT_LOAD || + (phdr.p_flags & (PF_W|PF_X)) == 0 || + (phdr.p_vaddr != elf->e_entry)) + continue; + + *entryp = phdr.p_vaddr; + } + + if (*entryp == 0) { + printf("Can't find entry point.\n"); + return (-1); + } + + for (i = 0; i < elf->e_phnum; i++) { + Elf_Phdr phdr; + lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET); + if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) { + (void)printf("read phdr: %s\n", strerror(errno)); + return (1); + } + if (phdr.p_type != PT_LOAD || + (phdr.p_flags & (PF_W|PF_X)) == 0) + continue; + + /* Read in segment. */ + printf("%s%lu", first ? "" : "+", phdr.p_filesz); + lseek(fd, phdr.p_offset, SEEK_SET); + if (read(fd, (caddr_t)A(phdr.p_vaddr), phdr.p_filesz) != + phdr.p_filesz) { + (void)printf("read text: %s\n", strerror(errno)); + return (1); + } + + /* keep track of highest addr we loaded. */ + if (first || addr < (phdr.p_vaddr + phdr.p_memsz)) + addr = (phdr.p_vaddr + phdr.p_memsz); + + /* Zero out bss. */ + if (phdr.p_filesz < phdr.p_memsz) { + (void)printf("+%lu", phdr.p_memsz - phdr.p_filesz); + bzero((caddr_t)A(phdr.p_vaddr) + phdr.p_filesz, + phdr.p_memsz - phdr.p_filesz); + } + first = 0; + } + + addr = A(addr); + addr = roundup(addr, sizeof(long)); + + ssym = addr; + /* + * Retreive symbols. + */ + addr += sizeof(Elf_Ehdr); + + if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { + printf("seek to section headers: %s\n", strerror(errno)); + return (1); + } + + sz = elf->e_shnum * sizeof(Elf_Shdr); + shp = (Elf_Shdr *)addr; + addr += roundup(sz, sizeof(long)); + + if (read(fd, shp, sz) != sz) { + printf("read section headers: %d\n", strerror(errno)); + return (1); + } + + /* + * Now load the symbol sections themselves. Make sure the + * sections are aligned. Don't bother with string tables if + * there are no symbol sections. + */ + off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); + + for (havesyms = i = 0; i < elf->e_shnum; i++) + if (shp[i].sh_type == SHT_SYMTAB) + havesyms = 1; + + if (!havesyms) + goto no_syms; + + for (first = 1, i = 0; i < elf->e_shnum; i++) { + if (shp[i].sh_type == SHT_SYMTAB || + shp[i].sh_type == SHT_STRTAB) { + printf("%s%ld", first ? " [" : "+", + (u_long)shp[i].sh_size); + if (lseek(fd, shp[i].sh_offset, SEEK_SET) == -1) { + printf("lseek symbols: %s\n", strerror(errno)); + return (1); + } + if (read(fd, (void *)addr, shp[i].sh_size) != + shp[i].sh_size) { + printf("read symbols: %s\n", strerror(errno)); + return (1); + } + addr += roundup(shp[i].sh_size, sizeof(long)); + shp[i].sh_offset = off; + off += roundup(shp[i].sh_size, sizeof(long)); + first = 0; + } + } + if (havesyms && first == 0) + printf("]"); + + elf->e_phoff = 0; + elf->e_shoff = sizeof(Elf_Ehdr); + elf->e_phentsize = 0; + elf->e_phnum = 0; + bcopy(elf, (void *)ssym, sizeof(*elf)); + +no_syms: + esym = (addr - (vaddr_t)LOADADDR) + *entryp; + + *entryp = (vaddr_t)LOADADDR; + + printf("\n"); + return (0); +} +#endif /* ALPHA_BOOT_ELF */ diff --git a/sys/arch/sparc/stand/bootxx/Makefile b/sys/arch/sparc/stand/bootxx/Makefile index 3b07e62213c..a991b929284 100644 --- a/sys/arch/sparc/stand/bootxx/Makefile +++ b/sys/arch/sparc/stand/bootxx/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.5 1997/09/17 10:46:16 downsj Exp $ +# $OpenBSD: Makefile,v 1.6 2002/08/11 23:11:22 art Exp $ # $NetBSD: Makefile,v 1.2 1995/09/30 21:43:38 pk Exp $ .PATH: ${.CURDIR}/../common @@ -9,6 +9,7 @@ NOMAN= noman INSTALL_STRIP= SRCS= srt0.S bootxx.c closeall.c dvma.c promdev.c +CLEANFILES+=${PROG}.aout ${PROG}.elf # pre-built bits of libkern KOBJS= __main.o bzero.o urem.o udiv.o @@ -21,9 +22,13 @@ CFLAGS= -O2 -I${.CURDIR}/../common -I${.CURDIR}/../../../../arch \ -I${.CURDIR}/../../../.. -I${.CURDIR}/../../../../lib/libsa -DBOOTXX \ ${DEFS} -${PROG}: ${OBJS} - ${LD} -N -T ${RELOC} -e start ${OBJS} ${_SOBJS} ${_KOBJS} - # convert to Sun magic +elfclean: clean-elf.c + ${HOSTCC} -o elfclean ${.ALLSRC} + +${PROG}: ${OBJS} elfclean + ${LD} -N -Ttext ${RELOC} -e start ${OBJS} ${_SOBJS} ${_KOBJS} -o elf + ./elfclean elf + objcopy -j .text -j .data -j .bss -O a.out-sparc-netbsd elf a.out @size a.out (echo -n 01 | tr 01 '\01\03'; tail +3c a.out) > ${.TARGET} @rm a.out diff --git a/sys/arch/sparc/stand/bootxx/bootxx.c b/sys/arch/sparc/stand/bootxx/bootxx.c index 2b9325548fe..d7bf507c753 100644 --- a/sys/arch/sparc/stand/bootxx/bootxx.c +++ b/sys/arch/sparc/stand/bootxx/bootxx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bootxx.c,v 1.2 2002/03/14 01:26:44 millert Exp $ */ +/* $OpenBSD: bootxx.c,v 1.3 2002/08/11 23:11:22 art Exp $ */ /* $NetBSD: bootxx.c,v 1.2 1997/09/14 19:28:17 pk Exp $ */ /* @@ -45,7 +45,7 @@ int netif_debug; /* * Boot device is derived from ROM provided information. */ -const char progname[] = "bootxx"; +char progname[] = "bootxx"; struct open_file io; /* |