summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/armv7/stand/efiboot/Makefile67
-rw-r--r--sys/arch/armv7/stand/efiboot/conf.c56
-rw-r--r--sys/arch/armv7/stand/efiboot/efiboot.c396
-rw-r--r--sys/arch/armv7/stand/efiboot/efiboot.h27
-rw-r--r--sys/arch/armv7/stand/efiboot/eficall.h53
-rw-r--r--sys/arch/armv7/stand/efiboot/efidev.c240
-rw-r--r--sys/arch/armv7/stand/efiboot/efidev.h35
-rw-r--r--sys/arch/armv7/stand/efiboot/exec.c142
-rw-r--r--sys/arch/armv7/stand/efiboot/heap.h29
-rw-r--r--sys/arch/armv7/stand/efiboot/ldscript.arm63
-rw-r--r--sys/arch/armv7/stand/efiboot/libsa.h27
-rw-r--r--sys/arch/armv7/stand/efiboot/self_reloc.c123
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);
+ }
+}