diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-14 17:55:16 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-14 17:55:16 +0000 |
commit | 22efdef3f23847dc5e4183184bb75c7e16626634 (patch) | |
tree | be1aa6485b7c4d6f12f35c2f5d2e27fc7af2e166 /sys | |
parent | 5b3645912fac0d0b7a8eab07f7671dbffd312a3a (diff) |
Initial stab at an EFI bootloader for armv7. Bits and pieces from FreeBSD
and our amd64 EFI bootloader. The current code works on a 2GB CuBox-i,
but probably not on anything else. It needs a u-boot with EFI loader
support.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/armv7/stand/efiboot/Makefile | 67 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/conf.c | 56 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efiboot.c | 396 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efiboot.h | 27 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/eficall.h | 53 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efidev.c | 240 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efidev.h | 35 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/exec.c | 142 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/heap.h | 29 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/ldscript.arm | 63 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/libsa.h | 27 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/self_reloc.c | 123 |
12 files changed, 1258 insertions, 0 deletions
diff --git a/sys/arch/armv7/stand/efiboot/Makefile b/sys/arch/armv7/stand/efiboot/Makefile new file mode 100644 index 00000000000..eb537e7bff5 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/Makefile @@ -0,0 +1,67 @@ +# $OpenBSD: Makefile,v 1.1 2016/05/14 17:55:15 kettenis Exp $ + +PROG= BOOTARM.EFI +NOMAN= # +OBJFMT= binary +SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c + +S= ${.CURDIR}/../../../.. +EFIDIR= ${S}/stand/efi + +OBJCOPY?= objcopy +OBJDUMP?= objdump + +LDFLAGS+=-nostdlib -T ${.CURDIR}/ldscript.arm -Bsymbolic -shared + +.PATH: ${S}/stand/boot +SRCS+= boot.c cmd.c vars.c + +.PATH: ${S}/lib/libsa +SRCS+= alloc.c ctime.c exit.c getchar.c memcmp.o memcpy.o memset.c printf.c \ + putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c strncpy.c \ + strtol.c +SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fstat.c \ + lseek.c open.c read.c readdir.c stat.c +SRCS+= loadfile.c +SRCS+= ufs.c + +.PATH: ${S}/lib/libkern/arch/arm ${S}/lib/libkern +SRCS+= divsi3.S divdi3.c moddi3.c qdivrem.c strlcpy.c strlen.c + +.PATH: ${S}/lib/libz +SRCS+= adler32.c crc32.c inflate.c inftrees.c + +CPPFLAGS+= -nostdinc +CPPFLAGS+= -I${S} -I. -I${.CURDIR} +CPPFLAGS+= -I${EFIDIR}/include -I${EFIDIR}/include/arm +CPPFLAGS+= -D_STANDALONE +CPPFLAGS+= -DSMALL -DSLOW -DNOBYFOUR -D__INTERNAL_LIBSA_CREAD +CPPFLAGS+= -DNEEDS_HEAP_H +COPTS+= -ffreestanding -fno-stack-protector +COPTS+= -fshort-wchar -fPIC -fno-builtin + +PROG.elf= ${PROG:S/.EFI/.elf/} +CLEANFILES+= ${PROG.elf} ${PROG.elf}.tmp + +${PROG}: ${PROG.elf} + ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ + -j .dynamic -j .dynsym -j .dynstr -j .rel -j .rel.dyn \ + -j .rela -j .rela.dyn -j .reloc \ + --output-target=${OBJFMT} ${PROG.elf} ${.TARGET} + +.include <bsd.prog.mk> + +${PROG.elf}: ${OBJS} + ${LD} ${LDFLAGS} -o ${.TARGET}.tmp ${OBJS} ${LDADD} + @if ${OBJDUMP} -t ${.TARGET}.tmp | grep 'UND'; then \ + (echo Undefined symbols; false); \ + fi + mv ${.TARGET}.tmp ${.TARGET} + +.if !make(obj) +.BEGIN: + @([ -h machine ] || ln -s ${.CURDIR}/../../../${MACHINE}/include machine) + @([ -h arm ] || ln -s ${.CURDIR}/../../../arm/include arm) +.NOPATH: machine arm +CLEANFILES+= machine arm +.endif diff --git a/sys/arch/armv7/stand/efiboot/conf.c b/sys/arch/armv7/stand/efiboot/conf.c new file mode 100644 index 00000000000..5207c711052 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/conf.c @@ -0,0 +1,56 @@ +/* $OpenBSD: conf.c,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 1996 Michael Shalayeff + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <lib/libsa/stand.h> +#include <lib/libsa/ufs.h> +#include <dev/cons.h> + +#include "efiboot.h" +#include "efidev.h" + +const char version[] = "0.1"; +int debug = 0; + +struct fs_ops file_system[] = { + { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, + ufs_stat, ufs_readdir }, +}; +int nfsys = nitems(file_system); + +struct devsw devsw[] = { + { "efi", efistrategy, efiopen, eficlose, efiioctl }, +}; +int ndevs = nitems(devsw); + +struct consdev constab[] = { + { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc }, + { NULL } +}; +struct consdev *cn_tab; diff --git a/sys/arch/armv7/stand/efiboot/efiboot.c b/sys/arch/armv7/stand/efiboot/efiboot.c new file mode 100644 index 00000000000..f3fe8a05362 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/efiboot.c @@ -0,0 +1,396 @@ +/* $OpenBSD: efiboot.c,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * Copyright (c) 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <dev/cons.h> +#include <sys/disklabel.h> + +#include <efi.h> +#include <efiapi.h> +#include <efiprot.h> +#include <eficonsctl.h> + +#include "eficall.h" +#include "libsa.h" + +EFI_SYSTEM_TABLE *ST; +EFI_BOOT_SERVICES *BS; +EFI_RUNTIME_SERVICES *RS; +EFI_HANDLE IH; + +EFI_HANDLE efi_bootdp; + +static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; +static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; +static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; + +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) +{ + extern char *progname; + EFI_LOADED_IMAGE *imgp; + EFI_DEVICE_PATH *dp = NULL; + EFI_STATUS status; + + ST = systab; + BS = ST->BootServices; + IH = image; + + status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid, + (void **)&imgp); + if (status == EFI_SUCCESS) + status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle, + &devp_guid, (void **)&dp); + if (status == EFI_SUCCESS) + efi_bootdp = dp; + + progname = "BOOTARM"; + + boot(0); + + return (EFI_SUCCESS); +} + +static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; +static SIMPLE_INPUT_INTERFACE *conin; + +void +efi_cons_probe(struct consdev *cn) +{ + cn->cn_pri = CN_MIDPRI; + cn->cn_dev = makedev(12, 0); +} + +void +efi_cons_init(struct consdev *cp) +{ + conin = ST->ConIn; + conout = ST->ConOut; +} + +int +efi_cons_getc(dev_t dev) +{ + EFI_INPUT_KEY key; + EFI_STATUS status; +#if 0 + UINTN dummy; +#endif + static int lastchar = 0; + + if (lastchar) { + int r = lastchar; + if ((dev & 0x80) == 0) + lastchar = 0; + return (r); + } + + status = conin->ReadKeyStroke(conin, &key); + while (status == EFI_NOT_READY) { + if (dev & 0x80) + return (0); + /* + * XXX The implementation of WaitForEvent() in U-boot + * is broken and neverreturns. + */ +#if 0 + BS->WaitForEvent(1, &conin->WaitForKey, &dummy); +#endif + status = conin->ReadKeyStroke(conin, &key); + } + + if (dev & 0x80) + lastchar = key.UnicodeChar; + + return (key.UnicodeChar); +} + +void +efi_cons_putc(dev_t dev, int c) +{ + CHAR16 buf[2]; + + if (c == '\n') + efi_cons_putc(dev, '\r'); + + buf[0] = c; + buf[1] = 0; + + conout->OutputString(conout, buf); +} + +EFI_PHYSICAL_ADDRESS heap; +UINTN heapsiz = 1 * 1024 * 1024; + +static void +efi_heap_init(void) +{ + EFI_STATUS status; + + status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(heapsiz), &heap); + if (status != EFI_SUCCESS) + panic("BS->AllocatePages()"); +} + +EFI_BLOCK_IO *disk; + +void +efi_diskprobe(void) +{ + int i, bootdev; + UINTN sz; + EFI_STATUS status; + EFI_HANDLE *handles = NULL; + EFI_BLOCK_IO *blkio; + EFI_BLOCK_IO_MEDIA *media; + EFI_DEVICE_PATH *dp, *bp; + + sz = 0; + status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + handles = alloc(sz); + status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, + 0, &sz, handles); + } + if (handles == NULL || EFI_ERROR(status)) + panic("BS->LocateHandle() returns %d", status); + + for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { + bootdev = 0; + status = EFI_CALL(BS->HandleProtocol, handles[i], &blkio_guid, + (void **)&blkio); + if (EFI_ERROR(status)) + panic("BS->HandleProtocol() returns %d", status); + + media = blkio->Media; + if (media->LogicalPartition || !media->MediaPresent) + continue; + + if (efi_bootdp == NULL) + goto next; + status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid, + (void **)&dp); + if (EFI_ERROR(status)) + goto next; + bp = efi_bootdp; + while (1) { + if (IsDevicePathEnd(dp)) { + bootdev = 1; + break; + } + if (memcmp(dp, bp, sizeof(EFI_DEVICE_PATH)) != 0 || + memcmp(dp, bp, DevicePathNodeLength(dp)) != 0) + break; + dp = NextDevicePathNode(dp); + bp = NextDevicePathNode(bp); + } +next: + if (bootdev) { + disk = blkio; + break; + } + } + + free(handles, sz); +} + +u_long efi_loadaddr; + +void +machdep(void) +{ + EFI_STATUS status; + EFI_PHYSICAL_ADDRESS addr = 0x10000000; + + cninit(); + + printf("pos %p\n", machdep); + + status = BS->AllocatePages(AllocateAddress, EfiLoaderData, + EFI_SIZE_TO_PAGES(32 * 1024 * 1024), &addr); + if (status != EFI_SUCCESS) + printf("Can't allocate memory\n"); + efi_loadaddr = addr; + + efi_heap_init(); + efi_diskprobe(); +} + +void +_rtt(void) +{ +#ifdef EFI_DEBUG + printf("Hit any key to reboot\n"); + efi_cons_getc(0); +#endif + /* + * XXX ResetSystem doesn't seem to work on U-Boot 2016.05 on + * the CuBox-i. So trigger an unimplemented instruction trap + * instead. + */ +#if 1 + asm volatile(".word 0xa000f7f0\n"); +#else + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); +#endif + while (1) { } +} + +time_t +getsecs(void) +{ + EFI_TIME t; + time_t r = 0; + int y = 0; + const int daytab[][14] = { + { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, + { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + }; +#define isleap(_y) (((_y) % 4) == 0 && (((_y) % 100) != 0 || ((_y) % 400) == 0)) + + EFI_CALL(ST->RuntimeServices->GetTime, &t, NULL); + + /* Calc days from UNIX epoch */ + r = (t.Year - 1970) * 365; + for (y = 1970; y < t.Year; y++) { + if (isleap(y)) + r++; + } + r += daytab[isleap(t.Year)? 1 : 0][t.Month] + t.Day; + + /* Calc secs */ + r *= 60 * 60 * 24; + r += ((t.Hour * 60) + t.Minute) * 60 + t.Second; + if (-24 * 60 < t.TimeZone && t.TimeZone < 24 * 60) + r += t.TimeZone * 60; + + return (r); +} + +void +devboot(dev_t dev, char *p) +{ + strlcpy(p, "efi0a", 6); +} + +int +cnspeed(dev_t dev, int sp) +{ + return 115200; +} + +char * +ttyname(int fd) +{ + return "com0"; +} + +dev_t +ttydev(char *name) +{ + return NODEV; +} + +#define MAXDEVNAME 16 + +/* + * Parse a device spec. + * + * [A-Za-z]*[0-9]*[A-Za-z]:file + * dev uint part + */ +int +devparse(const char *fname, int *dev, int *unit, int *part, const char **file) +{ + const char *s; + + *unit = 0; /* default to wd0a */ + *part = 0; + *dev = 0; + + s = strchr(fname, ':'); + if (s != NULL) { + int devlen; + int i, u, p; + struct devsw *dp; + char devname[MAXDEVNAME]; + + devlen = s - fname; + if (devlen > MAXDEVNAME) + return (EINVAL); + + /* extract device name */ + for (i = 0; isalpha(fname[i]) && (i < devlen); i++) + devname[i] = fname[i]; + devname[i] = 0; + + if (!isdigit(fname[i])) + return (EUNIT); + + /* device number */ + for (u = 0; isdigit(fname[i]) && (i < devlen); i++) + u = u * 10 + (fname[i] - '0'); + + if (!isalpha(fname[i])) + return (EPART); + + /* partition number */ + if (i < devlen) + p = fname[i++] - 'a'; + + if (i != devlen) + return (ENXIO); + + /* check device name */ + for (dp = devsw, i = 0; i < ndevs; dp++, i++) { + if (dp->dv_name && !strcmp(devname, dp->dv_name)) + break; + } + + if (i >= ndevs) + return (ENXIO); + + *unit = u; + *part = p; + *dev = i; + fname = ++s; + } + + *file = fname; + + return (0); +} + +int +devopen(struct open_file *f, const char *fname, char **file) +{ + struct devsw *dp; + int dev, unit, part, error; + + error = devparse(fname, &dev, &unit, &part, (const char **)file); + if (error) + return (error); + + dp = &devsw[0]; + f->f_dev = dp; + + return (*dp->dv_open)(f, unit, part); +} diff --git a/sys/arch/armv7/stand/efiboot/efiboot.h b/sys/arch/armv7/stand/efiboot/efiboot.h new file mode 100644 index 00000000000..3683af505ee --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/efiboot.h @@ -0,0 +1,27 @@ +/* $OpenBSD: efiboot.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void efi_cleanup(void); +void efi_cons_probe (struct consdev *); +void efi_memprobe (void); +void efi_hardprobe (void); +void efi_diskprobe (void); +void efi_cons_init (struct consdev *); +int efi_cons_getc (dev_t); +void efi_cons_putc (dev_t, int); +int efi_cons_getshifts(dev_t dev); diff --git a/sys/arch/armv7/stand/efiboot/eficall.h b/sys/arch/armv7/stand/efiboot/eficall.h new file mode 100644 index 00000000000..ac9d028d350 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/eficall.h @@ -0,0 +1,53 @@ +/* $OpenBSD: eficall.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__amd64__) + +#define EFI_CALL(_func_, ...) (_func_)(__VA_ARGS__) + +#else + +extern uint64_t efi_call(int, void *, ...); + +#define _call_0(_func) \ + efi_call(0, (_func)) +#define _call_1(_func, _1) \ + efi_call(1, (_func), (_1)) +#define _call_2(_func, _1, _2) \ + efi_call(2, (_func), (_1), (_2)) +#define _call_3(_func, _1, _2, _3) \ + efi_call(3, (_func), (_1), (_2), (_3)) +#define _call_4(_func, _1, _2, _3, _4) \ + efi_call(4, (_func), (_1), (_2), (_3), (_4)) +#define _call_5(_func, _1, _2, _3, _4, _5) \ + efi_call(5, (_func), (_1), (_2), (_3), (_4), (_5)) +#define _call_6(_func, _1, _2, _3, _4, _5, _6) \ + efi_call(6, (_func), (_1), (_2), (_3), (_4), (_5), (_6)) +#define _call_7(_func, _1, _2, _3, _4, _5, _6, _7) \ + efi_call(7, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7)) +#define _call_8(_func, _1, _2, _3, _4, _5, _6, _7, _8) \ + efi_call(8, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8)) +#define _call_9(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + efi_call(9, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8), (_9)) + +#define _efi_call_fn(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _fn, ...) _fn + +#define EFI_CALL(...) \ + _efi_call_fn(__VA_ARGS__, _call_9, _call_8, _call_7, _call_6, _call_5, \ + _call_4, _call_3, _call_2, _call_1, _call_1)(__VA_ARGS__) +#endif diff --git a/sys/arch/armv7/stand/efiboot/efidev.c b/sys/arch/armv7/stand/efiboot/efidev.c new file mode 100644 index 00000000000..6d0a25f7258 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/efidev.c @@ -0,0 +1,240 @@ +/* $OpenBSD: efidev.c,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * Copyright (c) 2016 Mark Kettenis + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + * + */ +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/disklabel.h> +#include <lib/libz/zlib.h> + +#include "libsa.h" + +#include <efi.h> +#include "eficall.h" + +extern EFI_BOOT_SERVICES *BS; + +extern int debug; + +#include "efidev.h" + +#define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE) +#define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed)) + +typedef struct efi_diskinfo { + EFI_BLOCK_IO *blkio; + UINT32 mediaid; +} *efi_diskinfo_t; + +struct diskinfo { + struct efi_diskinfo ed; + struct disklabel disklabel; + + u_int sc_part; +}; + +extern EFI_BLOCK_IO *disk; +struct diskinfo diskinfo; + +static EFI_STATUS + efid_io(int, efi_diskinfo_t, u_int, int, void *); +static int efid_diskio(int, struct diskinfo *, u_int, int, void *); + +static EFI_STATUS +efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf) +{ + EFI_STATUS status = EFI_SUCCESS; + EFI_PHYSICAL_ADDRESS addr; + caddr_t data; + + if (ed->blkio->Media->BlockSize != DEV_BSIZE) + return (EFI_UNSUPPORTED); + + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE), &addr); + if (EFI_ERROR(status)) + goto on_eio; + data = (caddr_t)(uintptr_t)addr; + + switch (rw) { + case F_READ: + status = EFI_CALL(ed->blkio->ReadBlocks, + ed->blkio, ed->mediaid, off, + nsect * DEV_BSIZE, data); + if (EFI_ERROR(status)) + goto on_eio; + memcpy(buf, data, nsect * DEV_BSIZE); + break; + case F_WRITE: + if (ed->blkio->Media->ReadOnly) + goto on_eio; + /* XXX not yet */ + goto on_eio; + break; + } + return (EFI_SUCCESS); + +on_eio: + BS->FreePages(addr, EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE)); + + return (status); +} + +static int +efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) +{ + EFI_STATUS status; + + status = efid_io(rw, &dip->ed, off, nsect, buf); + + return ((EFI_ERROR(status))? -1 : 0); +} + +/* + * Read disk label from the device. + */ +int +efi_getdisklabel(struct diskinfo *dip) +{ + char *msg; + int sector; + size_t rsize; + struct disklabel *lp; + unsigned char buf[DEV_BSIZE]; + + /* + * Find OpenBSD Partition in DOS partition table. + */ + sector = 0; + if (efistrategy(dip, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize)) + return EOFFSET; + + if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) { + int i; + struct dos_partition *dp = (struct dos_partition *)buf; + + /* + * Lookup OpenBSD slice. If there is none, go ahead + * and try to read the disklabel off sector #0. + */ + + memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp)); + for (i = 0; i < NDOSPART; i++) { + if (dp[i].dp_typ == DOSPTYP_OPENBSD) { + sector = letoh32(dp[i].dp_start); + break; + } + } + } + + if (efistrategy(dip, F_READ, sector + DOS_LABELSECTOR, DEV_BSIZE, + buf, &rsize)) + return EOFFSET; + + if ((msg = getdisklabel(buf + LABELOFFSET, &dip->disklabel))) + printf("sd%d: getdisklabel: %s\n", 0, msg); + + lp = &dip->disklabel; + + /* check partition */ + if ((dip->sc_part >= lp->d_npartitions) || + (lp->d_partitions[dip->sc_part].p_fstype == FS_UNUSED)) { + DPRINTF(("illegal partition\n")); + return (EPART); + } + + return (0); +} + +int +efiopen(struct open_file *f, ...) +{ + struct diskinfo *dip = &diskinfo; + va_list ap; + u_int unit, part; + int error; + + if (disk == NULL) + return (ENXIO); + + va_start(ap, f); + unit = va_arg(ap, u_int); + part = va_arg(ap, u_int); + va_end(ap); + + if (unit != 0) + return (ENXIO); + + diskinfo.ed.blkio = disk; + diskinfo.ed.mediaid = disk->Media->MediaId; + diskinfo.sc_part = part; + + error = efi_getdisklabel(&diskinfo); + if (error) + return (error); + + f->f_devdata = dip; + + return 0; +} + +int +efistrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, + size_t *rsize) +{ + struct diskinfo *dip = (struct diskinfo *)devdata; + int error = 0; + size_t nsect; + + nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; + blk += dip->disklabel.d_partitions[B_PARTITION(dip->sc_part)].p_offset; + + if (blk < 0) + error = EINVAL; + else + error = efid_diskio(rw, dip, blk, nsect, buf); + + if (rsize != NULL) + *rsize = nsect * DEV_BSIZE; + + return (error); +} + +int +eficlose(struct open_file *f) +{ + f->f_devdata = NULL; + + return 0; +} + +int +efiioctl(struct open_file *f, u_long cmd, void *data) +{ + return 0; +} diff --git a/sys/arch/armv7/stand/efiboot/efidev.h b/sys/arch/armv7/stand/efiboot/efidev.h new file mode 100644 index 00000000000..6ef83bcf045 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/efidev.h @@ -0,0 +1,35 @@ +/* $OpenBSD: efidev.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 1996 Michael Shalayeff + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + * + */ + +/* efidev.c */ +int efiopen(struct open_file *, ...); +int efistrategy(void *, int, daddr32_t, size_t, void *, size_t *); +int eficlose(struct open_file *); +int efiioctl(struct open_file *, u_long, void *); diff --git a/sys/arch/armv7/stand/efiboot/exec.c b/sys/arch/armv7/stand/efiboot/exec.c new file mode 100644 index 00000000000..189eb4e4b8c --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/exec.c @@ -0,0 +1,142 @@ +/* $OpenBSD: exec.c,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2006, 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> + +#include <lib/libsa/loadfile.h> + +#ifdef BOOT_ELF +#include <sys/exec_elf.h> +#endif + +#include <sys/reboot.h> +#include <stand/boot/cmd.h> +#include <machine/bootconfig.h> + +#include <efi.h> + +extern EFI_BOOT_SERVICES *BS; + +typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn)); + +struct uboot_tag_header { + uint32_t size; + uint32_t tag; +}; +struct uboot_tag_core { + uint32_t flags; + uint32_t pagesize; + uint32_t rootdev; +}; +struct uboot_tag_serialnr { + uint32_t low; + uint32_t high; +}; +struct uboot_tag_revision { + uint32_t rev; +}; +struct uboot_tag_mem32 { + uint32_t size; + uint32_t start; +}; +struct uboot_tag_cmdline { + char cmdline[1]; +}; + +#define ATAG_CORE 0x54410001 +#define ATAG_MEM 0x54410002 +#define ATAG_CMDLINE 0x54410009 +#define ATAG_SERIAL 0x54410006 +#define ATAG_REVISION 0x54410007 +#define ATAG_NONE 0x00000000 +struct uboot_tag { + struct uboot_tag_header hdr; + union { + struct uboot_tag_core core; + struct uboot_tag_mem32 mem; + struct uboot_tag_revision rev; + struct uboot_tag_serialnr serialnr; + struct uboot_tag_cmdline cmdline; + } u; +}; + +struct uboot_tag tags[2]; + +void +run_loadfile(u_long *marks, int howto) +{ +#if 0 +#ifdef BOOT_ELF + Elf_Ehdr *elf = (Elf_Ehdr *)marks[MARK_SYM]; + Elf_Shdr *shp = (Elf_Shdr *)(marks[MARK_SYM] + elf->e_shoff); + u_long esym = marks[MARK_END]; + char *cp; + int i; + + /* + * Tell locore.S where the symbol table ends by setting + * 'esym', which should be the first word in the .data + * section. + */ + for (i = 0; i < elf->e_shnum; i++) { + /* XXX Assume .data is the first writable segment. */ + if (shp[i].sh_flags & SHF_WRITE) { + /* XXX We have to store the virtual address. */ + esym |= shp[i].sh_addr & 0xff000000; + *(u_long *)(shp[i].sh_addr & 0x00ffffff) = esym; + break; + } + } +#endif + cp = (char *)0x00200000 - MAX_BOOT_STRING - 1; + +#define BOOT_STRING_MAGIC 0x4f425344 + + *(int *)cp = BOOT_STRING_MAGIC; + + cp += sizeof(int); + snprintf(cp, MAX_BOOT_STRING, "%s:%s -", cmd.bootdev, cmd.image); + + while (*cp != '\0') + cp++; + if (howto & RB_ASKNAME) + *cp++ = 'a'; + if (howto & RB_CONFIG) + *cp++ = 'c'; + if (howto & RB_KDB) + *cp++ = 'd'; + if (howto & RB_SINGLE) + *cp++ = 's'; + + *cp = '\0'; + +#endif + + tags[0].hdr.tag = ATAG_MEM; + tags[0].hdr.size = sizeof(struct uboot_tag); + tags[0].u.mem.start = 0x10000000; + tags[0].u.mem.size = 0x80000000; + + memcpy((void *)0x10000000, tags, sizeof(tags)); + + BS->ExitBootServices(NULL, 0); + + (*(startfuncp)(marks[MARK_ENTRY]))(NULL, (void *)4821, (void *)0x10000000); + + /* NOTREACHED */ +} diff --git a/sys/arch/armv7/stand/efiboot/heap.h b/sys/arch/armv7/stand/efiboot/heap.h new file mode 100644 index 00000000000..046a4db5433 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/heap.h @@ -0,0 +1,29 @@ +/* $OpenBSD: heap.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <efi.h> + +static char *top = NULL; +#define NEEDS_HEAP_INIT 1 + +static void +heap_init(void) +{ + extern EFI_PHYSICAL_ADDRESS heap; + if (top == NULL) + top = (char *)(uintptr_t)heap; +} diff --git a/sys/arch/armv7/stand/efiboot/ldscript.arm b/sys/arch/armv7/stand/efiboot/ldscript.arm new file mode 100644 index 00000000000..a9b53bc3dee --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/ldscript.arm @@ -0,0 +1,63 @@ +/* $FreeBSD: head/sys/boot/efi/loader/arch/arm/ldscript.arm 295420 2016-02-09 00:01:43Z andrew $ */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + . = ALIGN(16); + .data : + { + *(.data .data.*) + *(.gnu.linkonce.d*) + *(.rodata) + *(.rodata.*) + CONSTRUCTORS + + . = ALIGN(4); + PROVIDE (__bss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + PROVIDE (__bss_end = .); + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { + *(.got.plt .got) + *(.sdata*.sdata.* .gnu.linkonce.s.*) + } + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + __gp = .; + .plt : { *(.plt) } + .dynamic : { *(.dynamic) } + .reloc : { *(.reloc) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.dyn : { + *(.rel.*) + *(.relset_*) + } + _edata = .; + PROVIDE (end = .); + .hash : { *(.hash) } +} diff --git a/sys/arch/armv7/stand/efiboot/libsa.h b/sys/arch/armv7/stand/efiboot/libsa.h new file mode 100644 index 00000000000..8f1d8fc6cf9 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/libsa.h @@ -0,0 +1,27 @@ +/* $OpenBSD: libsa.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */ + +/* + * Copyright (c) 2008 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <lib/libsa/stand.h> + +#define DEFAULT_KERNEL_ADDRESS 0 + +#ifdef DEBUG +#define DPRINTF(x) printf x; +#else +#define DPRINTF(x) +#endif diff --git a/sys/arch/armv7/stand/efiboot/self_reloc.c b/sys/arch/armv7/stand/efiboot/self_reloc.c new file mode 100644 index 00000000000..44603fb353c --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/self_reloc.c @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/exec_elf.h> +#include <machine/reloc.h> + +#if defined(__aarch64__) +#define ElfW_Rel Elf64_Rela +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#define ELF_RELA +#elif defined(__arm__) || defined(__i386__) +#define ElfW_Rel Elf32_Rel +#define ElfW_Dyn Elf32_Dyn +#define ELFW_R_TYPE ELF32_R_TYPE +#elif defined(__amd64__) +#define ElfW_Rel Elf64_Rel +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#else +#error architecture not supported +#endif +#if defined(__aarch64__) +#define RELOC_TYPE_NONE R_AARCH64_NONE +#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE +#elif defined(__amd64__) +#define RELOC_TYPE_NONE R_X86_64_NONE +#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE +#elif defined(__arm__) +#define RELOC_TYPE_NONE R_ARM_NONE +#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE +#elif defined(__i386__) +#define RELOC_TYPE_NONE R_386_NONE +#define RELOC_TYPE_RELATIVE R_386_RELATIVE +#endif + +void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic); + +/* + * A simple elf relocator. + */ +void +self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic) +{ + Elf_Word relsz, relent; + Elf_Addr *newaddr; + ElfW_Rel *rel; + ElfW_Dyn *dynp; + + /* + * Find the relocation address, its size and the relocation entry. + */ + relsz = 0; + relent = 0; + for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + case DT_RELA: + rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr); + break; + case DT_RELSZ: + case DT_RELASZ: + relsz = dynp->d_un.d_val; + break; + case DT_RELENT: + case DT_RELAENT: + relent = dynp->d_un.d_val; + break; + default: + break; + } + } + + /* + * Perform the actual relocation. + */ + for (; relsz > 0; relsz -= relent) { + switch (ELFW_R_TYPE(rel->r_info)) { + case RELOC_TYPE_NONE: + /* No relocation needs be performed. */ + break; + + case RELOC_TYPE_RELATIVE: + /* Address relative to the base address. */ + newaddr = (Elf_Addr *)(rel->r_offset + baseaddr); + *newaddr += baseaddr; + /* Add the addend when the ABI uses them */ +#ifdef ELF_RELA + *newaddr += rel->r_addend; +#endif + break; + default: + /* XXX: do we need other relocations ? */ + break; + } + rel = (ElfW_Rel *)(void *)((caddr_t) rel + relent); + } +} |