Ported from arm64 with changes for riscv64.
Initial effort by Mickael Torres, with additional updates
ACPI api removed per request
ok kettenis@
--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2021/04/28 19:01:00 drahn Exp $
+
+SUBDIR= efiboot
+
+.include <bsd.subdir.mk>
--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2021/04/28 19:01:00 drahn Exp $
+
+NOMAN= #
+
+.if ${MACHINE} == "riscv64"
+
+PROG= BOOTRISCV64.EFI
+OBJFMT= binary
+INSTALL_STRIP=
+BINDIR= /usr/mdec
+SRCS= start.S self_reloc.c efiboot.c conf.c exec.c
+SRCS+= efidev.c efipxe.c efirng.c fdt.c
+SRCS+= softraid_riscv64.c
+
+S= ${.CURDIR}/../../../..
+EFIDIR= ${S}/stand/efi
+
+OBJCOPY?= objcopy
+OBJDUMP?= objdump
+
+LDFLAGS+=-nostdlib -T ${.CURDIR}/ldscript.riscv64 -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 hexdump.c \
+ memcmp.c memcpy.c memmove.c memset.c \
+ printf.c putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c \
+ strncpy.c strtol.c strtoll.c
+SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fchmod.c \
+ fstat.c lseek.c open.c read.c readdir.c stat.c
+SRCS+= loadfile.c arc4.c
+SRCS+= ufs.c ufs2.c
+SRCS+= arp.c ether.c globals.c in_cksum.c net.c netif.c netudp.c tftp.c
+SRCS+= aes_xts.c bcrypt_pbkdf.c blowfish.c explicit_bzero.c hmac_sha1.c \
+ pkcs5_pbkdf2.c rijndael.c sha1.c sha2.c softraid.c
+
+.PATH: ${S}/lib/libkern/arch/riscv64 ${S}/lib/libkern
+SRCS+= divdi3.c moddi3.c qdivrem.c strlcat.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/riscv64
+CPPFLAGS+= -D_STANDALONE
+CPPFLAGS+= -DSMALL -DSLOW -DNOBYFOUR -D__INTERNAL_LIBSA_CREAD
+CPPFLAGS+= -DNEEDS_HEAP_H -DFWRANDOM
+CPPFLAGS+= -march=rv64gc --target=riscv64 -mno-relax
+COPTS+= -Wno-attributes -Wno-format
+COPTS+= -ffreestanding -fno-stack-protector
+COPTS+= -fshort-wchar -fPIC -fno-builtin
+COPTS+= -Wall -Werror
+
+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(clean) && !make(cleandir) && !make(includes) && !make(obj)
+.BEGIN:
+ @([ -h machine ] || ln -s ${.CURDIR}/../../../${MACHINE}/include machine)
+.NOPATH: machine
+CLEANFILES+= machine
+.endif
+
+.else
+NOPROG=yes
+.include <bsd.prog.mk>
+.endif
--- /dev/null
+/* $OpenBSD: conf.c,v 1.1 2021/04/28 19:01:00 drahn 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/queue.h>
+#include <sys/disklabel.h>
+#include <lib/libsa/stand.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/ufs.h>
+#include <lib/libsa/ufs2.h>
+#include <dev/cons.h>
+
+#include <dev/biovar.h>
+#include <dev/softraidvar.h>
+
+#include <efi.h>
+
+#include "disk.h"
+#include "efiboot.h"
+#include "efidev.h"
+#include "efipxe.h"
+#include "softraid_riscv64.h"
+
+const char version[] = "1.4";
+int debug = 0;
+
+struct fs_ops file_system[] = {
+ { mtftp_open, mtftp_close, mtftp_read, mtftp_write, mtftp_seek,
+ mtftp_stat, mtftp_readdir },
+ { efitftp_open,tftp_close, tftp_read, tftp_write, tftp_seek,
+ tftp_stat, tftp_readdir },
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
+ ufs_stat, ufs_readdir, ufs_fchmod },
+ { ufs2_open, ufs2_close, ufs2_read, ufs2_write, ufs2_seek,
+ ufs2_stat, ufs2_readdir, ufs2_fchmod },
+};
+int nfsys = nitems(file_system);
+
+struct devsw devsw[] = {
+ { "tftp", tftpstrategy, tftpopen, tftpclose, tftpioctl },
+ { "sd", efistrategy, efiopen, eficlose, efiioctl },
+ { "sr", srstrategy, sropen, srclose, srioctl },
+};
+int ndevs = nitems(devsw);
+
+struct consdev constab[] = {
+ { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc },
+ { efi_fb_probe, efi_fb_init, efi_cons_getc, efi_cons_putc },
+ { NULL }
+};
+struct consdev *cn_tab;
+
+struct netif_driver *netif_drivers[] = {
+ &efinet_driver,
+};
+int n_netif_drivers = nitems(netif_drivers);
--- /dev/null
+/* $OpenBSD: disk.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+#ifndef _DISK_H
+#define _DISK_H
+
+#include <sys/queue.h>
+
+typedef struct efi_diskinfo {
+ EFI_BLOCK_IO *blkio;
+ UINT32 mediaid;
+} *efi_diskinfo_t;
+
+struct diskinfo {
+ struct efi_diskinfo ed;
+ struct disklabel disklabel;
+ struct sr_boot_volume *sr_vol;
+
+ u_int part;
+ u_int flags;
+#define DISKINFO_FLAG_GOODLABEL (1 << 0)
+
+ int (*diskio)(int, struct diskinfo *, u_int, int, void *);
+ int (*strategy)(void *, int, daddr_t, size_t, void *, size_t *);
+
+ TAILQ_ENTRY(diskinfo) list;
+};
+TAILQ_HEAD(disklist_lh, diskinfo);
+
+extern struct diskinfo *bootdev_dip;
+
+extern struct disklist_lh disklist;
+
+#endif /* _DISK_H */
--- /dev/null
+/* $OpenBSD: efiboot.c,v 1.1 2021/04/28 19:01:00 drahn 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 <sys/stat.h>
+#include <dev/cons.h>
+#include <sys/disklabel.h>
+
+#include <efi.h>
+#include <efiapi.h>
+#include <efiprot.h>
+#include <eficonsctl.h>
+
+#include <dev/biovar.h>
+#include <dev/softraidvar.h>
+
+#include <lib/libkern/libkern.h>
+#include <lib/libsa/softraid.h>
+#include <stand/boot/cmd.h>
+
+#include "libsa.h"
+#include "disk.h"
+#include "softraid_riscv64.h"
+
+#include "efidev.h"
+#include "efiboot.h"
+#include "eficall.h"
+#include "fdt.h"
+
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RS;
+EFI_HANDLE IH, efi_bootdp;
+
+EFI_PHYSICAL_ADDRESS heap;
+UINTN heapsiz = 1 * 1024 * 1024;
+EFI_MEMORY_DESCRIPTOR *mmap;
+UINTN mmap_key;
+UINTN mmap_ndesc;
+UINTN mmap_descsiz;
+UINT32 mmap_version;
+
+static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+
+int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+static void efi_heap_init(void);
+static void efi_memprobe_internal(void);
+static void efi_timer_init(void);
+static void efi_timer_cleanup(void);
+static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
+
+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;
+ RS = ST->RuntimeServices;
+ IH = image;
+
+ /* disable reset by watchdog after 5 minutes */
+ EFI_CALL(BS->SetWatchdogTimer, 0, 0, 0, NULL);
+
+ 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 = "BOOTRISCV64";
+
+ boot(0);
+
+ return (EFI_SUCCESS);
+}
+
+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+static SIMPLE_INPUT_INTERFACE *conin;
+
+/*
+ * The device majors for these don't match the ones used by the
+ * kernel. That's fine. They're just used as an index into the cdevs
+ * array and never passed on to the kernel.
+ */
+static dev_t serial = makedev(0, 0);
+static dev_t framebuffer = makedev(1, 0);
+
+static char framebuffer_path[128];
+
+void
+efi_cons_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_MIDPRI;
+ cn->cn_dev = serial;
+}
+
+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 || key.UnicodeChar == 0) {
+ 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);
+}
+
+void
+efi_fb_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_LOWPRI;
+ cn->cn_dev = framebuffer;
+}
+
+void
+efi_fb_init(struct consdev *cn)
+{
+ conin = ST->ConIn;
+ conout = ST->ConOut;
+}
+
+int
+efi_fb_getc(dev_t dev)
+{
+ return efi_cons_getc(dev);
+}
+
+void
+efi_fb_putc(dev_t dev, int c)
+{
+ efi_cons_putc(dev, c);
+}
+
+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()");
+}
+
+struct disklist_lh disklist;
+struct diskinfo *bootdev_dip;
+
+void
+efi_diskprobe(void)
+{
+ int i, bootdev = 0, depth = -1;
+ UINTN sz;
+ EFI_STATUS status;
+ EFI_HANDLE *handles = NULL;
+ EFI_BLOCK_IO *blkio;
+ EFI_BLOCK_IO_MEDIA *media;
+ struct diskinfo *di;
+ EFI_DEVICE_PATH *dp;
+
+ TAILQ_INIT(&disklist);
+
+ 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))
+ return;
+
+ if (efi_bootdp != NULL)
+ depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+
+ /*
+ * U-Boot incorrectly represents devices with a single
+ * MEDIA_DEVICE_PATH component. In that case include that
+ * component into the matching, otherwise we'll blindly select
+ * the first device.
+ */
+ if (depth == 0)
+ depth = 1;
+
+ for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+ 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;
+ di = alloc(sizeof(struct diskinfo));
+ efid_init(di, blkio);
+
+ if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
+ goto next;
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
+ (void **)&dp);
+ if (EFI_ERROR(status))
+ goto next;
+ if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
+ TAILQ_INSERT_HEAD(&disklist, di, list);
+ bootdev_dip = di;
+ bootdev = 1;
+ continue;
+ }
+next:
+ TAILQ_INSERT_TAIL(&disklist, di, list);
+ }
+
+ free(handles, sz);
+
+ /* Print available disks and probe for softraid. */
+ i = 0;
+ printf("disks:");
+ TAILQ_FOREACH(di, &disklist, list) {
+ printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
+ i++;
+ }
+ srprobe();
+ printf("\n");
+}
+
+/*
+ * Determine the number of nodes up to, but not including, the first
+ * node of the specified type.
+ */
+int
+efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
+{
+ int i;
+
+ for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
+ if (DevicePathType(dp) == dptype)
+ return (i);
+ }
+
+ return (i);
+}
+
+int
+efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
+{
+ int i, cmp;
+
+ for (i = 0; i < deptn; i++) {
+ if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
+ return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
+ ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
+ cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
+ if (cmp)
+ return (cmp);
+ cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
+ if (cmp)
+ return (cmp);
+ dpa = NextDevicePathNode(dpa);
+ dpb = NextDevicePathNode(dpb);
+ }
+
+ return (0);
+}
+
+void
+efi_framebuffer(void)
+{
+ EFI_GRAPHICS_OUTPUT *gop;
+ EFI_STATUS status;
+ void *node, *child;
+ uint32_t acells, scells;
+ uint64_t base, size;
+ uint32_t reg[4];
+ uint32_t width, height, stride;
+ char *format;
+ char *prop;
+
+ /*
+ * Don't create a "simple-framebuffer" node if we already have
+ * one. Besides "/chosen", we also check under "/" since that
+ * is where the Raspberry Pi firmware puts it.
+ */
+ node = fdt_find_node("/chosen");
+ for (child = fdt_child_node(node); child;
+ child = fdt_next_node(child)) {
+ if (!fdt_node_is_compatible(child, "simple-framebuffer"))
+ continue;
+ if (!fdt_node_property(child, "status", &prop) ||
+ strcmp(prop, "okay") == 0) {
+ strlcpy(framebuffer_path, "/chosen/",
+ sizeof(framebuffer_path));
+ strlcat(framebuffer_path, fdt_node_name(child),
+ sizeof(framebuffer_path));
+ return;
+ }
+ }
+ node = fdt_find_node("/");
+ for (child = fdt_child_node(node); child;
+ child = fdt_next_node(child)) {
+ if (!fdt_node_is_compatible(child, "simple-framebuffer"))
+ continue;
+ if (!fdt_node_property(child, "status", &prop) ||
+ strcmp(prop, "okay") == 0) {
+ strlcpy(framebuffer_path, "/",
+ sizeof(framebuffer_path));
+ strlcat(framebuffer_path, fdt_node_name(child),
+ sizeof(framebuffer_path));
+ return;
+ }
+ }
+
+ status = EFI_CALL(BS->LocateProtocol, &gop_guid, NULL, (void **)&gop);
+ if (status != EFI_SUCCESS)
+ return;
+
+ /* Paranoia! */
+ if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
+ return;
+
+ /* We only support 32-bit pixel modes for now. */
+ switch (gop->Mode->Info->PixelFormat) {
+ case PixelRedGreenBlueReserved8BitPerColor:
+ format = "x8b8g8r8";
+ break;
+ case PixelBlueGreenRedReserved8BitPerColor:
+ format = "x8r8g8b8";
+ break;
+ default:
+ return;
+ }
+
+ base = gop->Mode->FrameBufferBase;
+ size = gop->Mode->FrameBufferSize;
+ width = htobe32(gop->Mode->Info->HorizontalResolution);
+ height = htobe32(gop->Mode->Info->VerticalResolution);
+ stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
+
+ node = fdt_find_node("/");
+ if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
+ acells = 1;
+ if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
+ scells = 1;
+ if (acells > 2 || scells > 2)
+ return;
+ if (acells >= 1)
+ reg[0] = htobe32(base);
+ if (acells == 2) {
+ reg[1] = reg[0];
+ reg[0] = htobe32(base >> 32);
+ }
+ if (scells >= 1)
+ reg[acells] = htobe32(size);
+ if (scells == 2) {
+ reg[acells + 1] = reg[acells];
+ reg[acells] = htobe32(size >> 32);
+ }
+
+ node = fdt_find_node("/chosen");
+ fdt_node_add_node(node, "framebuffer", &child);
+ fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
+ fdt_node_add_property(child, "format", format, strlen(format) + 1);
+ fdt_node_add_property(child, "stride", &stride, 4);
+ fdt_node_add_property(child, "height", &height, 4);
+ fdt_node_add_property(child, "width", &width, 4);
+ fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
+ fdt_node_add_property(child, "compatible",
+ "simple-framebuffer", strlen("simple-framebuffer") + 1);
+
+ strlcpy(framebuffer_path, "/chosen/framebuffer",
+ sizeof(framebuffer_path));
+}
+
+void
+efi_console(void)
+{
+ void *node;
+
+ if (cn_tab->cn_dev != framebuffer)
+ return;
+
+ if (strlen(framebuffer_path) == 0)
+ return;
+
+ /* Point stdout-path at the framebuffer node. */
+ node = fdt_find_node("/chosen");
+ fdt_node_add_property(node, "stdout-path",
+ framebuffer_path, strlen(framebuffer_path) + 1);
+}
+
+uint64_t dma_constraint[2] = { 0, -1 };
+
+void
+efi_dma_constraint(void)
+{
+ void *node;
+
+ /* Raspberry Pi 4 is "special". */
+ node = fdt_find_node("/");
+ if (fdt_node_is_compatible(node, "brcm,bcm2711"))
+ dma_constraint[1] = htobe64(0x3bffffff);
+
+ /* Pass DMA constraint. */
+ node = fdt_find_node("/chosen");
+ fdt_node_add_property(node, "openbsd,dma-constraint",
+ dma_constraint, sizeof(dma_constraint));
+}
+
+void *fdt = NULL;
+char *bootmac = NULL;
+static EFI_GUID fdt_guid = FDT_TABLE_GUID;
+
+#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
+
+void *
+efi_makebootargs(char *bootargs, int howto)
+{
+ struct sr_boot_volume *bv;
+ u_char bootduid[8];
+ u_char zero[8] = { 0 };
+ uint64_t uefi_system_table = htobe64((uintptr_t)ST);
+ uint32_t boothowto = htobe32(howto);
+ void *node;
+ size_t len;
+ int i;
+
+ if (fdt == NULL) {
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ if (efi_guidcmp(&fdt_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ fdt = ST->ConfigurationTable[i].VendorTable;
+ }
+ }
+
+ if (!fdt_init(fdt))
+ return NULL;
+
+ node = fdt_find_node("/chosen");
+ if (!node)
+ return NULL;
+
+ len = strlen(bootargs) + 1;
+ fdt_node_add_property(node, "bootargs", bootargs, len);
+ fdt_node_add_property(node, "openbsd,boothowto",
+ &boothowto, sizeof(boothowto));
+
+ /* Pass DUID of the boot disk. */
+ if (bootdev_dip) {
+ memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
+ sizeof(bootduid));
+ if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
+ fdt_node_add_property(node, "openbsd,bootduid",
+ bootduid, sizeof(bootduid));
+ }
+
+ if (bootdev_dip->sr_vol != NULL) {
+ bv = bootdev_dip->sr_vol;
+ fdt_node_add_property(node, "openbsd,sr-bootuuid",
+ &bv->sbv_uuid, sizeof(bv->sbv_uuid));
+ if (bv->sbv_maskkey != NULL)
+ fdt_node_add_property(node,
+ "openbsd,sr-bootkey", bv->sbv_maskkey,
+ SR_CRYPTO_MAXKEYBYTES);
+ }
+ }
+
+ sr_clear_keys();
+
+ /* Pass netboot interface address. */
+ if (bootmac)
+ fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
+
+ /* Pass EFI system table. */
+ fdt_node_add_property(node, "openbsd,uefi-system-table",
+ &uefi_system_table, sizeof(uefi_system_table));
+
+ /* Placeholders for EFI memory map. */
+ fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
+ fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
+ fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
+ fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
+
+ efi_framebuffer();
+ efi_console();
+ efi_dma_constraint();
+
+ fdt_finalize();
+
+ return fdt;
+}
+
+void
+efi_updatefdt(void)
+{
+ uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
+ uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
+ uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
+ uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
+ void *node;
+
+ node = fdt_find_node("/chosen");
+ if (!node)
+ return;
+
+ /* Pass EFI memory map. */
+ fdt_node_set_property(node, "openbsd,uefi-mmap-start",
+ &uefi_mmap_start, sizeof(uefi_mmap_start));
+ fdt_node_set_property(node, "openbsd,uefi-mmap-size",
+ &uefi_mmap_size, sizeof(uefi_mmap_size));
+ fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
+ &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
+ fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
+ &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
+
+ fdt_finalize();
+}
+
+u_long efi_loadaddr;
+
+void
+machdep(void)
+{
+ EFI_PHYSICAL_ADDRESS addr;
+
+ cninit();
+ efi_heap_init();
+
+ /*
+ * The kernel expects to be loaded into a block of memory aligned
+ * on a 2MB boundary. We allocate a block of 64MB of memory, which
+ * gives us plenty of room for growth.
+ */
+ if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
+ 0x200000, &addr) != EFI_SUCCESS)
+ printf("Can't allocate memory\n");
+ efi_loadaddr = addr;
+
+ efi_timer_init();
+ efi_diskprobe();
+ efi_pxeprobe();
+}
+
+void
+efi_cleanup(void)
+{
+ int retry;
+ EFI_STATUS status;
+
+ efi_timer_cleanup();
+
+ /* retry once in case of failure */
+ for (retry = 1; retry >= 0; retry--) {
+ efi_memprobe_internal(); /* sync the current map */
+ efi_updatefdt();
+ status = EFI_CALL(BS->ExitBootServices, IH, mmap_key);
+ if (status == EFI_SUCCESS)
+ break;
+ if (retry == 0)
+ panic("ExitBootServices failed (%d)", status);
+ }
+}
+
+void
+_rtt(void)
+{
+#ifdef EFI_DEBUG
+ printf("Hit any key to reboot\n");
+ efi_cons_getc(0);
+#endif
+ RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+ for (;;)
+ continue;
+}
+
+/*
+ * U-Boot only implements the GetTime() Runtime Service if it has been
+ * configured with CONFIG_DM_RTC. Most board configurations don't
+ * include that option, so we can't use it to implement our boot
+ * prompt timeout. Instead we use timer events to simulate a clock
+ * that ticks ever second.
+ */
+
+EFI_EVENT timer;
+int ticks;
+
+static VOID
+efi_timer(EFI_EVENT event, VOID *context)
+{
+ ticks++;
+}
+
+static void
+efi_timer_init(void)
+{
+ EFI_STATUS status;
+
+ status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ efi_timer, NULL, &timer);
+ if (status == EFI_SUCCESS)
+ status = BS->SetTimer(timer, TimerPeriodic, 10000000);
+ if (EFI_ERROR(status))
+ printf("Can't create timer\n");
+}
+
+static void
+efi_timer_cleanup(void)
+{
+ BS->CloseEvent(timer);
+}
+
+time_t
+getsecs(void)
+{
+ return ticks;
+}
+
+/*
+ * Various device-related bits.
+ */
+
+void
+devboot(dev_t dev, char *p)
+{
+ struct sr_boot_volume *bv;
+ struct sr_boot_chunk *bc;
+ struct diskinfo *dip;
+ int sd_boot_vol = 0;
+ int sr_boot_vol = -1;
+ int part_type = FS_UNUSED;
+
+ if (bootdev_dip == NULL) {
+ strlcpy(p, "tftp0a", 7);
+ return;
+ }
+
+ TAILQ_FOREACH(dip, &disklist, list) {
+ if (bootdev_dip == dip)
+ break;
+ sd_boot_vol++;
+ }
+
+ /*
+ * Determine the partition type for the 'a' partition of the
+ * boot device.
+ */
+ if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0)
+ part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
+
+ /*
+ * See if we booted from a disk that is a member of a bootable
+ * softraid volume.
+ */
+ SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
+ if (bc->sbc_diskinfo == bootdev_dip)
+ sr_boot_vol = bv->sbv_unit;
+ if (sr_boot_vol != -1)
+ break;
+ }
+
+ if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
+ strlcpy(p, "sr0a", 5);
+ p[2] = '0' + sr_boot_vol;
+ return;
+ }
+
+ strlcpy(p, "sd0a", 5);
+ p[2] = '0' + sd_boot_vol;
+}
+
+const char cdevs[][4] = { "com", "fb" };
+const int ncdevs = nitems(cdevs);
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ return 115200;
+}
+
+char ttyname_buf[8];
+
+char *
+ttyname(int fd)
+{
+ snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
+ cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
+
+ return ttyname_buf;
+}
+
+dev_t
+ttydev(char *name)
+{
+ int i, unit = -1;
+ char *no = name + strlen(name) - 1;
+
+ while (no >= name && *no >= '0' && *no <= '9')
+ unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
+ if (no < name || unit < 0)
+ return NODEV;
+ for (i = 0; i < ncdevs; i++)
+ if (strncmp(name, cdevs[i], no - name + 1) == 0)
+ return makedev(i, unit);
+ 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 = 0;
+ 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[dev];
+ f->f_dev = dp;
+
+ if (strcmp("tftp", dp->dv_name) != 0) {
+ /*
+ * Clear bootmac, to signal that we loaded this file from a
+ * non-network device.
+ */
+ bootmac = NULL;
+ }
+
+ return (*dp->dv_open)(f, unit, part);
+}
+
+static void
+efi_memprobe_internal(void)
+{
+ EFI_STATUS status;
+ UINTN mapkey, mmsiz, siz;
+ UINT32 mmver;
+ EFI_MEMORY_DESCRIPTOR *mm;
+ int n;
+
+ free(mmap, mmap_ndesc * mmap_descsiz);
+
+ siz = 0;
+ status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz,
+ &mmver);
+ if (status != EFI_BUFFER_TOO_SMALL)
+ panic("cannot get the size of memory map");
+ mm = alloc(siz);
+ status = EFI_CALL(BS->GetMemoryMap, &siz, mm, &mapkey, &mmsiz, &mmver);
+ if (status != EFI_SUCCESS)
+ panic("cannot get the memory map");
+ n = siz / mmsiz;
+ mmap = mm;
+ mmap_key = mapkey;
+ mmap_ndesc = n;
+ mmap_descsiz = mmsiz;
+ mmap_version = mmver;
+}
+
+/*
+ * 64-bit ARMs can have a much wider memory mapping, as in somewhere
+ * after the 32-bit region. To cope with our alignment requirement,
+ * use the memory table to find a place where we can fit.
+ */
+static EFI_STATUS
+efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
+{
+ EFI_MEMORY_DESCRIPTOR *mm;
+ int i, j;
+
+ if (align < EFI_PAGE_SIZE)
+ return EFI_INVALID_PARAMETER;
+
+ efi_memprobe_internal(); /* sync the current map */
+
+ for (i = 0, mm = mmap; i < mmap_ndesc;
+ i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
+ if (mm->Type != EfiConventionalMemory)
+ continue;
+
+ if (mm->NumberOfPages < pages)
+ continue;
+
+ for (j = 0; j < mm->NumberOfPages; j++) {
+ EFI_PHYSICAL_ADDRESS paddr;
+
+ if (mm->NumberOfPages - j < pages)
+ break;
+
+ paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
+ if (paddr & (align - 1))
+ continue;
+
+ if (EFI_CALL(BS->AllocatePages, AllocateAddress,
+ EfiLoaderData, pages, &paddr) == EFI_SUCCESS) {
+ *addr = paddr;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/*
+ * Commands
+ */
+
+int Xdtb_efi(void);
+int Xexit_efi(void);
+int Xpoweroff_efi(void);
+
+const struct cmd_table cmd_machine[] = {
+ { "dtb", CMDT_CMD, Xdtb_efi },
+ { "exit", CMDT_CMD, Xexit_efi },
+ { "poweroff", CMDT_CMD, Xpoweroff_efi },
+ { NULL, 0 }
+};
+
+int
+Xdtb_efi(void)
+{
+ EFI_PHYSICAL_ADDRESS addr;
+ char path[MAXPATHLEN];
+ struct stat sb;
+ int fd;
+
+#define O_RDONLY 0
+
+ if (cmd.argc != 2) {
+ printf("dtb file\n");
+ return (0);
+ }
+
+ snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0 || fstat(fd, &sb) == -1) {
+ printf("cannot open %s\n", path);
+ return (0);
+ }
+ if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
+ 0x1000, &addr) != EFI_SUCCESS) {
+ printf("cannot allocate memory for %s\n", path);
+ return (0);
+ }
+ if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
+ printf("cannot read from %s\n", path);
+ return (0);
+ }
+
+ fdt = (void *)addr;
+ return (0);
+}
+
+int
+Xexit_efi(void)
+{
+ EFI_CALL(BS->Exit, IH, 0, 0, NULL);
+ for (;;)
+ continue;
+ return (0);
+}
+
+int
+Xpoweroff_efi(void)
+{
+ EFI_CALL(RS->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ return (0);
+}
--- /dev/null
+/* $OpenBSD: efiboot.h,v 1.1 2021/04/28 19:01:00 drahn 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_diskprobe(void);
+void efi_pxeprobe(void);
+void *efi_makebootargs(char *, int);
+void efi_cons_probe(struct consdev *);
+void efi_cons_init(struct consdev *);
+int efi_cons_getc(dev_t);
+void efi_cons_putc(dev_t, int);
+void efi_fb_probe(struct consdev *);
+void efi_fb_init(struct consdev *);
+int efi_fb_getc(dev_t);
+void efi_fb_putc(dev_t, int);
--- /dev/null
+/* $OpenBSD: eficall.h,v 1.1 2021/04/28 19:01:00 drahn 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 _call_10(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
+ efi_call(10, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8), (_9), (_10))
+
+#define _efi_call_fn(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _fn, ...) _fn
+
+#define EFI_CALL(...) \
+ _efi_call_fn(__VA_ARGS__, _call_10, _call_9, _call_8, _call_7, _call_6, \
+ _call_5, _call_4, _call_3, _call_2, _call_1, _call_0)(__VA_ARGS__)
+#endif
--- /dev/null
+/* $OpenBSD: efidev.c,v 1.1 2021/04/28 19:01:00 drahn 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 <isofs/cd9660/iso.h>
+
+#include "libsa.h"
+
+#include <efi.h>
+#include "eficall.h"
+
+extern EFI_BOOT_SERVICES *BS;
+
+extern int debug;
+
+#include "disk.h"
+#include "efidev.h"
+
+#define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
+#define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed))
+
+static EFI_STATUS
+ efid_io(int, efi_diskinfo_t, u_int, int, void *);
+static int efid_diskio(int, struct diskinfo *, u_int, int, void *);
+const char * efi_getdisklabel(efi_diskinfo_t, struct disklabel *);
+static int efi_getdisklabel_cd9660(efi_diskinfo_t, struct disklabel *);
+static u_int findopenbsd(efi_diskinfo_t, const char **);
+static u_int findopenbsd_gpt(efi_diskinfo_t, const char **);
+static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
+
+void
+efid_init(struct diskinfo *dip, void *handle)
+{
+ EFI_BLOCK_IO *blkio = handle;
+
+ memset(dip, 0, sizeof(struct diskinfo));
+ dip->ed.blkio = blkio;
+ dip->ed.mediaid = blkio->Media->MediaId;
+ dip->diskio = efid_diskio;
+ dip->strategy = efistrategy;
+
+ if (efi_getdisklabel(&dip->ed, &dip->disklabel) == NULL)
+ dip->flags |= DISKINFO_FLAG_GOODLABEL;
+}
+
+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;
+ memcpy(data, buf, nsect * DEV_BSIZE);
+ status = EFI_CALL(ed->blkio->WriteBlocks,
+ ed->blkio, ed->mediaid, off,
+ nsect * DEV_BSIZE, data);
+ if (EFI_ERROR(status))
+ 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);
+}
+
+/*
+ * Returns 0 if the MBR with the provided partition array is a GPT protective
+ * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
+ * one MBR partition, an EFI partition that either covers the whole disk or as
+ * much of it as is possible with a 32bit size field.
+ *
+ * Taken from kern/subr_disk.c.
+ *
+ * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
+ */
+static int
+gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
+{
+ struct dos_partition *dp2;
+ int efi, found, i;
+ u_int32_t psize;
+
+ found = efi = 0;
+ for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
+ if (dp2->dp_typ == DOSPTYP_UNUSED)
+ continue;
+ found++;
+ if (dp2->dp_typ != DOSPTYP_EFI)
+ continue;
+ psize = letoh32(dp2->dp_size);
+ if (psize == (dsize - 1) ||
+ psize == UINT32_MAX) {
+ if (letoh32(dp2->dp_start) == 1)
+ efi++;
+ }
+ }
+ if (found == 1 && efi == 1)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Try to find the disk address of the first MBR OpenBSD partition.
+ *
+ * N.B.: must boot from a partition within first 2^32-1 sectors!
+ *
+ * Called only if the MBR on sector 0 is *not* a protective MBR
+ * and *does* have a valid signature.
+ *
+ * We don't check the signatures of EBR's, and they cannot be
+ * protective MBR's so there is no need to check for that.
+ */
+static u_int
+findopenbsd(efi_diskinfo_t ed, const char **err)
+{
+ EFI_STATUS status;
+ struct dos_mbr mbr;
+ struct dos_partition *dp;
+ u_int mbroff = DOSBBSECTOR;
+ u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */
+ int i, maxebr = DOS_MAXEBR, nextebr;
+
+again:
+ if (!maxebr--) {
+ *err = "too many extended partitions";
+ return (-1);
+ }
+
+ /* Read MBR */
+ bzero(&mbr, sizeof(mbr));
+ status = efid_io(F_READ, ed, mbroff, 1, &mbr);
+ if (EFI_ERROR(status)) {
+ *err = "Disk I/O Error";
+ return (-1);
+ }
+
+ /* Search for OpenBSD partition */
+ nextebr = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ dp = &mbr.dmbr_parts[i];
+ if (!dp->dp_size)
+ continue;
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("found partition %u: "
+ "type %u (0x%x) offset %u (0x%x)\n",
+ (int)(dp - mbr.dmbr_parts),
+ dp->dp_typ, dp->dp_typ,
+ dp->dp_start, dp->dp_start);
+#endif
+ if (dp->dp_typ == DOSPTYP_OPENBSD) {
+ if (dp->dp_start > (dp->dp_start + mbroff))
+ continue;
+ return (dp->dp_start + mbroff);
+ }
+
+ /*
+ * Record location of next ebr if and only if this is the first
+ * extended partition in this boot record!
+ */
+ if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND ||
+ dp->dp_typ == DOSPTYP_EXTENDL)) {
+ nextebr = dp->dp_start + mbr_eoff;
+ if (nextebr < dp->dp_start)
+ nextebr = (u_int)-1;
+ if (mbr_eoff == DOSBBSECTOR)
+ mbr_eoff = dp->dp_start;
+ }
+ }
+
+ if (nextebr && nextebr != (u_int)-1) {
+ mbroff = nextebr;
+ goto again;
+ }
+
+ return (-1);
+}
+
+/*
+ * Try to find the disk address of the first GPT OpenBSD partition.
+ *
+ * N.B.: must boot from a partition within first 2^32-1 sectors!
+ *
+ * Called only if the MBR on sector 0 *is* a protective MBR
+ * with a valid signature and sector 1 is a valid GPT header.
+ */
+static u_int
+findopenbsd_gpt(efi_diskinfo_t ed, const char **err)
+{
+ EFI_STATUS status;
+ struct gpt_header gh;
+ int i, part, found;
+ uint64_t lba;
+ uint32_t orig_csum, new_csum;
+ uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec;
+ uint32_t gpsectors;
+ const char openbsd_uuid_code[] = GPT_UUID_OPENBSD;
+ struct gpt_partition gp;
+ static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space;
+ static u_char buf[4096];
+
+ /* Prepare OpenBSD UUID */
+ if (openbsd_uuid == NULL) {
+ /* XXX: should be replaced by uuid_dec_be() */
+ memcpy(&openbsd_uuid_space, openbsd_uuid_code,
+ sizeof(openbsd_uuid_space));
+ openbsd_uuid_space.time_low =
+ betoh32(openbsd_uuid_space.time_low);
+ openbsd_uuid_space.time_mid =
+ betoh16(openbsd_uuid_space.time_mid);
+ openbsd_uuid_space.time_hi_and_version =
+ betoh16(openbsd_uuid_space.time_hi_and_version);
+
+ openbsd_uuid = &openbsd_uuid_space;
+ }
+
+ if (EFI_BLKSPERSEC(ed) > 8) {
+ *err = "disk sector > 4096 bytes\n";
+ return (-1);
+ }
+
+ /* LBA1: GPT Header */
+ lba = 1;
+ status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), EFI_BLKSPERSEC(ed),
+ buf);
+ if (EFI_ERROR(status)) {
+ *err = "Disk I/O Error";
+ return (-1);
+ }
+ memcpy(&gh, buf, sizeof(gh));
+
+ /* Check signature */
+ if (letoh64(gh.gh_sig) != GPTSIGNATURE) {
+ *err = "bad GPT signature\n";
+ return (-1);
+ }
+
+ if (letoh32(gh.gh_rev) != GPTREVISION) {
+ *err = "bad GPT revision\n";
+ return (-1);
+ }
+
+ ghsize = letoh32(gh.gh_size);
+ if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) {
+ *err = "bad GPT header size\n";
+ return (-1);
+ }
+
+ /* Check checksum */
+ orig_csum = gh.gh_csum;
+ gh.gh_csum = 0;
+ new_csum = crc32(0, (unsigned char *)&gh, ghsize);
+ gh.gh_csum = orig_csum;
+ if (letoh32(orig_csum) != new_csum) {
+ *err = "bad GPT header checksum\n";
+ return (-1);
+ }
+
+ lba = letoh64(gh.gh_part_lba);
+ ghpartsize = letoh32(gh.gh_part_size);
+ ghpartspersec = ed->blkio->Media->BlockSize / ghpartsize;
+ ghpartnum = letoh32(gh.gh_part_num);
+ gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec;
+ new_csum = crc32(0L, Z_NULL, 0);
+ found = 0;
+ for (i = 0; i < gpsectors; i++, lba++) {
+ status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba),
+ EFI_BLKSPERSEC(ed), buf);
+ if (EFI_ERROR(status)) {
+ *err = "Disk I/O Error";
+ return (-1);
+ }
+ for (part = 0; part < ghpartspersec; part++) {
+ if (ghpartnum == 0)
+ break;
+ new_csum = crc32(new_csum, buf + part * sizeof(gp),
+ sizeof(gp));
+ ghpartnum--;
+ if (found)
+ continue;
+ memcpy(&gp, buf + part * sizeof(gp), sizeof(gp));
+ if (memcmp(&gp.gp_type, openbsd_uuid,
+ sizeof(struct uuid)) == 0)
+ found = 1;
+ }
+ }
+ if (new_csum != letoh32(gh.gh_part_csum)) {
+ *err = "bad GPT entries checksum\n";
+ return (-1);
+ }
+ if (found) {
+ lba = letoh64(gp.gp_lba_start);
+ /* Bootloaders do not current handle addresses > UINT_MAX! */
+ if (lba > UINT_MAX || EFI_SECTOBLK(ed, lba) > UINT_MAX) {
+ *err = "OpenBSD Partition LBA > 2**32 - 1";
+ return (-1);
+ }
+ return (u_int)lba;
+ }
+
+ return (-1);
+}
+
+const char *
+efi_getdisklabel(efi_diskinfo_t ed, struct disklabel *label)
+{
+ u_int start = 0;
+ uint8_t buf[DEV_BSIZE];
+ struct dos_partition dosparts[NDOSPART];
+ EFI_STATUS status;
+ const char *err = NULL;
+ int error;
+
+ /*
+ * Read sector 0. Ensure it has a valid MBR signature.
+ *
+ * If it's a protective MBR then try to find the disklabel via
+ * GPT. If it's not a protective MBR, try to find the disklabel
+ * via MBR.
+ */
+ memset(buf, 0, sizeof(buf));
+ status = efid_io(F_READ, ed, DOSBBSECTOR, 1, buf);
+ if (EFI_ERROR(status))
+ return ("Disk I/O Error");
+
+ /* Check MBR signature. */
+ if (buf[510] != 0x55 || buf[511] != 0xaa) {
+ if (efi_getdisklabel_cd9660(ed, label) == 0)
+ return (NULL);
+ return ("invalid MBR signature");
+ }
+
+ memcpy(dosparts, buf+DOSPARTOFF, sizeof(dosparts));
+
+ /* check for GPT protective MBR. */
+ if (gpt_chk_mbr(dosparts, ed->blkio->Media->LastBlock + 1) == 0) {
+ start = findopenbsd_gpt(ed, &err);
+ if (start == (u_int)-1) {
+ if (err != NULL)
+ return (err);
+ return ("no OpenBSD GPT partition");
+ }
+ } else {
+ start = findopenbsd(ed, &err);
+ if (start == (u_int)-1) {
+ if (err != NULL)
+ return (err);
+ return "no OpenBSD MBR partition\n";
+ }
+ }
+
+ /* Load BSD disklabel */
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR);
+#endif
+ /* read disklabel */
+ error = efid_io(F_READ, ed, EFI_SECTOBLK(ed, start) + DOS_LABELSECTOR,
+ 1, buf);
+
+ if (error)
+ return "failed to read disklabel";
+
+ /* Fill in disklabel */
+ return (getdisklabel(buf, label));
+}
+
+static int
+efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct disklabel *label)
+{
+ int off;
+ uint8_t buf[DEV_BSIZE];
+ EFI_STATUS status;
+
+ for (off = 0; off < 100; off++) {
+ status = efid_io(F_READ, ed,
+ EFI_BLKSPERSEC(ed) * (16 + off), 1, buf);
+ if (EFI_ERROR(status))
+ return (-1);
+ if (bcmp(buf + 1, ISO_STANDARD_ID, 5) != 0 ||
+ buf[0] == ISO_VD_END)
+ return (-1);
+ if (buf[0] == ISO_VD_PRIMARY)
+ break;
+ }
+ if (off >= 100)
+ return (-1);
+
+ /* Create an imaginary disk label */
+ label->d_secsize = 2048;
+ label->d_ntracks = 1;
+ label->d_nsectors = 100;
+ label->d_ncylinders = 1;
+ label->d_secpercyl = label->d_ntracks * label->d_nsectors;
+
+ strncpy(label->d_typename, "ATAPI CD-ROM", sizeof(label->d_typename));
+ label->d_type = DTYPE_ATAPI;
+
+ strncpy(label->d_packname, "fictitious", sizeof(label->d_packname));
+ DL_SETDSIZE(label, 100);
+
+ label->d_bbsize = 2048;
+ label->d_sbsize = 2048;
+
+ /* 'a' partition covering the "whole" disk */
+ DL_SETPOFFSET(&label->d_partitions[0], 0);
+ DL_SETPSIZE(&label->d_partitions[0], 100);
+ label->d_partitions[0].p_fstype = FS_UNUSED;
+
+ /* The raw partition is special */
+ DL_SETPOFFSET(&label->d_partitions[RAW_PART], 0);
+ DL_SETPSIZE(&label->d_partitions[RAW_PART], 100);
+ label->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
+
+ label->d_npartitions = MAXPARTITIONS;
+
+ label->d_magic = DISKMAGIC;
+ label->d_magic2 = DISKMAGIC;
+ label->d_checksum = dkcksum(label);
+
+ return (0);
+}
+
+int
+efiopen(struct open_file *f, ...)
+{
+ struct diskinfo *dip = NULL;
+ va_list ap;
+ u_int unit, part;
+ int i = 0;
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ if (part >= MAXPARTITIONS)
+ return (ENXIO);
+
+ TAILQ_FOREACH(dip, &disklist, list) {
+ if (i == unit)
+ break;
+ i++;
+ }
+
+ if (dip == NULL)
+ return (ENXIO);
+
+ if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0)
+ return (ENXIO);
+
+ dip->part = part;
+ bootdev_dip = dip;
+ f->f_devdata = dip;
+
+ return 0;
+}
+
+int
+efistrategy(void *devdata, int rw, daddr_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 += DL_SECTOBLK(&dip->disklabel,
+ dip->disklabel.d_partitions[dip->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;
+}
--- /dev/null
+/* $OpenBSD: efidev.h,v 1.1 2021/04/28 19:01:00 drahn 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 */
+void efid_init(struct diskinfo *, void *handle);
+int efiopen(struct open_file *, ...);
+int efistrategy(void *, int, daddr_t, size_t, void *, size_t *);
+int eficlose(struct open_file *);
+int efiioctl(struct open_file *, u_long, void *);
--- /dev/null
+/* $OpenBSD: efipxe.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+/*
+ * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
+ *
+ * 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/disklabel.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <libsa.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/net.h>
+#include <lib/libsa/netif.h>
+
+#include <efi.h>
+#include <efiapi.h>
+#include "eficall.h"
+#include "efiboot.h"
+#include "disk.h"
+
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_DEVICE_PATH *efi_bootdp;
+
+extern char *bootmac;
+static UINT8 boothw[16];
+struct in_addr bootip, servip;
+extern struct in_addr gateip;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+static EFI_GUID net_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
+static EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL;
+static EFI_SIMPLE_NETWORK *NET = NULL;
+static EFI_PXE_BASE_CODE *PXE = NULL;
+static EFI_PHYSICAL_ADDRESS txbuf;
+static int use_mtftp = 0;
+
+extern int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+extern int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+
+int efinet_probe(struct netif *, void *);
+int efinet_match(struct netif *, void *);
+void efinet_init(struct iodesc *, void *);
+int efinet_get(struct iodesc *, void *, size_t, time_t);
+int efinet_put(struct iodesc *, void *, size_t);
+void efinet_end(struct netif *);
+
+/*
+ * TFTP initial probe. This function discovers PXE handles and tries
+ * to figure out if there has already been a successful PXE handshake.
+ * If so, set the PXE variable.
+ */
+void
+efi_pxeprobe(void)
+{
+ EFI_SIMPLE_NETWORK *net;
+ EFI_PXE_BASE_CODE *pxe;
+ EFI_DEVICE_PATH *dp0;
+ EFI_HANDLE *handles;
+ EFI_STATUS status;
+ UINTN nhandles;
+ int i, depth;
+
+ if (efi_bootdp == NULL)
+ return;
+
+ status = EFI_CALL(BS->LocateHandleBuffer, ByProtocol, &pxe_guid, NULL,
+ &nhandles, &handles);
+ if (status != EFI_SUCCESS)
+ return;
+
+ for (i = 0; i < nhandles; i++) {
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i],
+ &devp_guid, (void **)&dp0);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ depth = efi_device_path_depth(efi_bootdp, MESSAGING_DEVICE_PATH);
+ if (depth == -1 || efi_device_path_ncmp(efi_bootdp, dp0, depth))
+ continue;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &net_guid,
+ (void **)&net);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &pxe_guid,
+ (void **)&pxe);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ if (pxe->Mode == NULL)
+ continue;
+
+ if (pxe->Mtftp != NULL) {
+ status = EFI_CALL(pxe->Mtftp, NULL, 0, NULL,
+ FALSE, NULL, NULL, NULL, NULL, NULL, FALSE);
+ if (status != EFI_UNSUPPORTED)
+ use_mtftp = 1;
+ }
+
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)&pxe->Mode->DhcpAck;
+ memcpy(&bootip, dhcp->BootpYiAddr, sizeof(bootip));
+ memcpy(&servip, dhcp->BootpSiAddr, sizeof(servip));
+ memcpy(&gateip, dhcp->BootpSiAddr, sizeof(gateip));
+ memcpy(boothw, dhcp->BootpHwAddr, sizeof(boothw));
+ bootmac = boothw;
+ NET = net;
+ PXE = pxe;
+ break;
+ }
+}
+
+/*
+ * TFTP filesystem layer implementation.
+ */
+struct mtftp_handle {
+ unsigned char *inbuf; /* input buffer */
+ size_t inbufsize;
+ off_t inbufoff;
+};
+
+int
+mtftp_open(char *path, struct open_file *f)
+{
+ struct mtftp_handle *tftpfile;
+ EFI_PHYSICAL_ADDRESS addr;
+ EFI_IP_ADDRESS dstip;
+ EFI_STATUS status;
+ UINT64 size;
+
+ if (strcmp("tftp", f->f_dev->dv_name) != 0)
+ return ENXIO;
+
+ if (PXE == NULL)
+ return ENXIO;
+
+ if (!use_mtftp)
+ return ENXIO;
+
+ tftpfile = alloc(sizeof(*tftpfile));
+ if (tftpfile == NULL)
+ return ENOMEM;
+ memset(tftpfile, 0, sizeof(*tftpfile));
+
+ memcpy(&dstip, &servip, sizeof(servip));
+ status = EFI_CALL(PXE->Mtftp, PXE, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ NULL, FALSE, &size, NULL, &dstip, path, NULL, FALSE);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENOENT;
+ }
+ tftpfile->inbufsize = size;
+
+ if (tftpfile->inbufsize == 0)
+ goto out;
+
+ status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(tftpfile->inbufsize), &addr);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENOMEM;
+ }
+ tftpfile->inbuf = (unsigned char *)((paddr_t)addr);
+
+ status = EFI_CALL(PXE->Mtftp, PXE, EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ tftpfile->inbuf, FALSE, &size, NULL, &dstip, path, NULL, FALSE);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENXIO;
+ }
+out:
+ f->f_fsdata = tftpfile;
+ return 0;
+}
+
+int
+mtftp_close(struct open_file *f)
+{
+ struct mtftp_handle *tftpfile = f->f_fsdata;
+
+ if (tftpfile->inbuf != NULL)
+ EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
+ EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
+ free(tftpfile, sizeof(*tftpfile));
+ return 0;
+}
+
+int
+mtftp_read(struct open_file *f, void *addr, size_t size, size_t *resid)
+{
+ struct mtftp_handle *tftpfile = f->f_fsdata;
+ size_t toread;
+
+ if (size > tftpfile->inbufsize - tftpfile->inbufoff)
+ toread = tftpfile->inbufsize - tftpfile->inbufoff;
+ else
+ toread = size;
+
+ if (toread != 0) {
+ memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
+ tftpfile->inbufoff += toread;
+ }
+
+ if (resid != NULL)
+ *resid = size - toread;
+ return 0;
+}
+
+int
+mtftp_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+ return EROFS;
+}
+
+off_t
+mtftp_seek(struct open_file *f, off_t offset, int where)
+{
+ struct mtftp_handle *tftpfile = f->f_fsdata;
+
+ switch(where) {
+ case SEEK_CUR:
+ if (tftpfile->inbufoff + offset < 0 ||
+ tftpfile->inbufoff + offset > tftpfile->inbufsize) {
+ errno = EOFFSET;
+ break;
+ }
+ tftpfile->inbufoff += offset;
+ return (tftpfile->inbufoff);
+ case SEEK_SET:
+ if (offset < 0 || offset > tftpfile->inbufsize) {
+ errno = EOFFSET;
+ break;
+ }
+ tftpfile->inbufoff = offset;
+ return (tftpfile->inbufoff);
+ case SEEK_END:
+ tftpfile->inbufoff = tftpfile->inbufsize;
+ return (tftpfile->inbufoff);
+ default:
+ errno = EINVAL;
+ }
+ return((off_t)-1);
+}
+
+int
+mtftp_stat(struct open_file *f, struct stat *sb)
+{
+ struct mtftp_handle *tftpfile = f->f_fsdata;
+
+ sb->st_mode = 0444;
+ sb->st_nlink = 1;
+ sb->st_uid = 0;
+ sb->st_gid = 0;
+ sb->st_size = tftpfile->inbufsize;
+
+ return 0;
+}
+
+int
+mtftp_readdir(struct open_file *f, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * Overload generic TFTP implementation to check that
+ * we actually have a driver.
+ */
+int
+efitftp_open(char *path, struct open_file *f)
+{
+ if (strcmp("tftp", f->f_dev->dv_name) != 0)
+ return ENXIO;
+
+ if (NET == NULL || PXE == NULL)
+ return ENXIO;
+
+ if (use_mtftp)
+ return ENXIO;
+
+ return tftp_open(path, f);
+}
+
+/*
+ * Dummy network device.
+ */
+int tftpdev_sock = -1;
+
+int
+tftpopen(struct open_file *f, ...)
+{
+ EFI_STATUS status;
+ u_int unit, part;
+ va_list ap;
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ /* No PXE set -> no PXE available */
+ if (PXE == NULL)
+ return 1;
+
+ if (unit != 0)
+ return 1;
+
+ if (!use_mtftp) {
+ status = EFI_CALL(BS->AllocatePages, AllocateAnyPages,
+ EfiLoaderData, EFI_SIZE_TO_PAGES(RECV_SIZE), &txbuf);
+ if (status != EFI_SUCCESS)
+ return ENOMEM;
+
+ if ((tftpdev_sock = netif_open("efinet")) < 0) {
+ EFI_CALL(BS->FreePages, txbuf,
+ EFI_SIZE_TO_PAGES(RECV_SIZE));
+ return ENXIO;
+ }
+
+ f->f_devdata = &tftpdev_sock;
+ }
+
+ return 0;
+}
+
+int
+tftpclose(struct open_file *f)
+{
+ int ret = 0;
+
+ if (!use_mtftp) {
+ ret = netif_close(*(int *)f->f_devdata);
+ EFI_CALL(BS->FreePages, txbuf, EFI_SIZE_TO_PAGES(RECV_SIZE));
+ txbuf = 0;
+ }
+
+ return ret;
+}
+
+int
+tftpioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return EOPNOTSUPP;
+}
+
+int
+tftpstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * Simple Network Protocol driver.
+ */
+struct netif_stats efinet_stats;
+struct netif_dif efinet_ifs[] = {
+ { 0, 1, &efinet_stats, 0, 0, },
+};
+
+struct netif_driver efinet_driver = {
+ "efinet",
+ efinet_match,
+ efinet_probe,
+ efinet_init,
+ efinet_get,
+ efinet_put,
+ efinet_end,
+ efinet_ifs,
+ nitems(efinet_ifs)
+};
+
+int
+efinet_match(struct netif *nif, void *v)
+{
+ return 1;
+}
+
+int
+efinet_probe(struct netif *nif, void *v)
+{
+ if (strncmp(v, efinet_driver.netif_bname, 3))
+ return -1;
+
+ return 0;
+}
+
+void
+efinet_init(struct iodesc *desc, void *v)
+{
+ EFI_SIMPLE_NETWORK *net = NET;
+ EFI_STATUS status;
+
+ if (net == NULL)
+ return;
+
+ if (net->Mode->State == EfiSimpleNetworkStopped) {
+ status = EFI_CALL(net->Start, net);
+ if (status != EFI_SUCCESS)
+ return;
+ }
+
+ if (net->Mode->State != EfiSimpleNetworkInitialized) {
+ status = EFI_CALL(net->Initialize, net, 0, 0);
+ if (status != EFI_SUCCESS)
+ return;
+ }
+
+ EFI_CALL(net->ReceiveFilters, net,
+ EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST,
+ 0, FALSE, 0, NULL);
+
+ memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6);
+ memcpy(&desc->myip, &bootip, sizeof(bootip));
+ desc->xid = 1;
+}
+
+int
+efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t tmo)
+{
+ EFI_SIMPLE_NETWORK *net = NET;
+ EFI_STATUS status;
+ UINTN bufsz, pktsz;
+ time_t t;
+ char *buf, *ptr;
+ ssize_t ret = -1;
+
+ if (net == NULL)
+ return ret;
+
+ bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ buf = alloc(bufsz + ETHER_ALIGN);
+ if (buf == NULL)
+ return ret;
+ ptr = buf + ETHER_ALIGN;
+
+ t = getsecs();
+ status = EFI_NOT_READY;
+ while ((getsecs() - t) < tmo) {
+ pktsz = bufsz;
+ status = EFI_CALL(net->Receive, net, NULL, &pktsz, ptr,
+ NULL, NULL, NULL);
+ if (status == EFI_SUCCESS)
+ break;
+ if (status != EFI_NOT_READY)
+ break;
+ }
+
+ if (status == EFI_SUCCESS) {
+ memcpy(pkt, ptr, min((ssize_t)pktsz, len));
+ ret = min((ssize_t)pktsz, len);
+ }
+
+ free(buf, bufsz + ETHER_ALIGN);
+ return ret;
+}
+
+int
+efinet_put(struct iodesc *desc, void *pkt, size_t len)
+{
+ EFI_SIMPLE_NETWORK *net = NET;
+ EFI_STATUS status;
+ void *buf = NULL;
+ int ret = -1;
+
+ if (net == NULL)
+ goto out;
+
+ if (len > RECV_SIZE)
+ goto out;
+
+ memcpy((void *)txbuf, pkt, len);
+ status = EFI_CALL(net->Transmit, net, 0, len, (void *)txbuf,
+ NULL, NULL, NULL);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ buf = NULL;
+ while (status == EFI_SUCCESS) {
+ status = EFI_CALL(net->GetStatus, net, NULL, &buf);
+ if (buf)
+ break;
+ }
+
+ if (status == EFI_SUCCESS)
+ ret = len;
+
+out:
+ return ret;
+}
+
+void
+efinet_end(struct netif *nif)
+{
+ EFI_SIMPLE_NETWORK *net = NET;
+
+ if (net == NULL)
+ return;
+
+ EFI_CALL(net->Shutdown, net);
+}
--- /dev/null
+/* $OpenBSD: efipxe.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+/*
+ * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
+ *
+ * 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.
+ */
+
+extern struct netif_driver efinet_driver;
+
+int efitftp_open(char *path, struct open_file *f);
+
+int mtftp_open(char *, struct open_file *);
+int mtftp_close(struct open_file *);
+int mtftp_read(struct open_file *, void *, size_t, size_t *);
+int mtftp_write(struct open_file *, void *, size_t, size_t *);
+off_t mtftp_seek(struct open_file *, off_t, int);
+int mtftp_stat(struct open_file *, struct stat *);
+int mtftp_readdir(struct open_file *, char *);
+
+int tftpopen(struct open_file *, ...);
+int tftpclose(struct open_file *);
+int tftpioctl(struct open_file *, u_long, void *);
+int tftpstrategy(void *, int, daddr_t, size_t, void *, size_t *);
--- /dev/null
+/* $OpenBSD: efirng.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+/*
+ * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * 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 <efi.h>
+#include <efiapi.h>
+
+#include "eficall.h"
+#include "libsa.h"
+
+extern EFI_BOOT_SERVICES *BS;
+
+/* Random Number Generator Protocol */
+
+#define EFI_RNG_PROTOCOL_GUID \
+ { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} }
+
+INTERFACE_DECL(_EFI_RNG_PROTOCOL);
+
+typedef EFI_GUID EFI_RNG_ALGORITHM;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RNG_GET_INFO) (
+ IN struct _EFI_RNG_PROTOCOL *This,
+ IN OUT UINTN *RNGAlgorithmListSize,
+ OUT EFI_RNG_ALGORITHM *RNGAlgorithmList
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RNG_GET_RNG) (
+ IN struct _EFI_RNG_PROTOCOL *This,
+ IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL
+ IN UINTN RNGValueLength,
+ OUT UINT8 *RNGValue
+ );
+
+typedef struct _EFI_RNG_PROTOCOL {
+ EFI_RNG_GET_INFO GetInfo;
+ EFI_RNG_GET_RNG GetRNG;
+} EFI_RNG_PROTOCOL;
+
+static EFI_GUID rng_guid = EFI_RNG_PROTOCOL_GUID;
+
+int
+fwrandom(char *buf, size_t buflen)
+{
+ EFI_STATUS status;
+ EFI_RNG_PROTOCOL *rng = NULL;
+ UINT8 *random;
+ size_t i;
+ int ret = 0;
+
+ status = EFI_CALL(BS->LocateProtocol, &rng_guid, NULL, (void **)&rng);
+ if (rng == NULL || EFI_ERROR(status))
+ return -1;
+
+ random = alloc(buflen);
+
+ status = EFI_CALL(rng->GetRNG, rng, NULL, buflen, random);
+ if (EFI_ERROR(status)) {
+ printf("RNG GetRNG() failed (%d)\n", status);
+ ret = -1;
+ goto out;
+ }
+
+ for (i = 0; i < buflen; i++)
+ buf[i] ^= random[i];
+
+out:
+ free(random, buflen);
+ return ret;
+}
--- /dev/null
+/* $OpenBSD: exec.c,v 1.1 2021/04/28 19:01:00 drahn 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 <sys/reboot.h>
+#include <dev/cons.h>
+
+#include <lib/libkern/libkern.h>
+#include <lib/libsa/loadfile.h>
+#include <sys/exec_elf.h>
+
+#include <efi.h>
+#include <stand/boot/cmd.h>
+
+#include "efiboot.h"
+#include "libsa.h"
+#include "fdt.h"
+
+typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn));
+
+unsigned int cpu_get_dcache_line_size(void);
+void cpu_flush_dcache(vaddr_t, vsize_t);
+void cpu_inval_icache(void);
+
+void
+cpu_flush_dcache(vaddr_t addr, vsize_t len)
+{
+ __asm volatile("fence" ::: "memory");
+}
+
+void
+cpu_inval_icache(void)
+{
+ __asm volatile("fence.i" ::: "memory");
+}
+
+void
+run_loadfile(uint64_t *marks, int howto)
+{
+ char args[256];
+ char *cp;
+ void *fdt;
+
+ strlcpy(args, cmd.path, sizeof(args));
+ cp = args + strlen(args);
+
+ *cp++ = ' ';
+ *cp = '-';
+ if (howto & RB_ASKNAME)
+ *++cp = 'a';
+ if (howto & RB_CONFIG)
+ *++cp = 'c';
+ if (howto & RB_SINGLE)
+ *++cp = 's';
+ if (howto & RB_KDB)
+ *++cp = 'd';
+ if (*cp == '-')
+ *--cp = 0;
+ else
+ *++cp = 0;
+
+ fdt = efi_makebootargs(args, howto);
+
+ efi_cleanup();
+
+ cpu_flush_dcache(marks[MARK_ENTRY], marks[MARK_END] - marks[MARK_ENTRY]);
+ cpu_inval_icache();
+
+ cpu_flush_dcache((vaddr_t)fdt, fdt_get_size(fdt));
+
+ (*(startfuncp)(marks[MARK_ENTRY]))((void *)marks[MARK_END], 0, fdt);
+
+ /* NOTREACHED */
+}
--- /dev/null
+/* $OpenBSD: fdt.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
+ * Copyright (c) 2009, 2016 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * 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/systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include "fdt.h"
+
+unsigned int fdt_check_head(void *);
+char *fdt_get_str(uint32_t);
+void *skip_property(uint32_t *);
+void *skip_props(uint32_t *);
+void *skip_node_name(uint32_t *);
+void *skip_node(void *);
+void *fdt_parent_node_recurse(void *, void *);
+
+static int tree_inited = 0;
+static struct fdt tree;
+
+unsigned int
+fdt_check_head(void *fdt)
+{
+ struct fdt_head *fh;
+ uint32_t *ptr;
+
+ fh = fdt;
+ ptr = (uint32_t *)fdt;
+
+ if (betoh32(fh->fh_magic) != FDT_MAGIC)
+ return 0;
+
+ if (betoh32(fh->fh_version) > FDT_CODE_VERSION)
+ return 0;
+
+ if (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4))) !=
+ FDT_NODE_BEGIN)
+ return 0;
+
+ /* check for end signature on version 17 blob */
+ if ((betoh32(fh->fh_version) >= 17) &&
+ (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) +
+ (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END))
+ return 0;
+
+ return betoh32(fh->fh_version);
+}
+
+/*
+ * Initializes internal structures of module.
+ * Has to be called once.
+ */
+int
+fdt_init(void *fdt)
+{
+ int version;
+
+ memset(&tree, 0, sizeof(struct fdt));
+ tree_inited = 0;
+
+ if (!fdt)
+ return 0;
+
+ if (!(version = fdt_check_head(fdt)))
+ return 0;
+
+ tree.header = (struct fdt_head *)fdt;
+ tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off);
+ tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off);
+ tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off);
+ tree.end = (char *)fdt + betoh32(tree.header->fh_size);
+ tree.version = version;
+ tree.strings_size = betoh32(tree.header->fh_strings_size);
+ if (tree.version >= 17)
+ tree.struct_size = betoh32(tree.header->fh_struct_size);
+ tree_inited = 1;
+
+ return version;
+}
+
+void
+fdt_finalize(void)
+{
+ char *start = (char *)tree.header;
+
+ tree.header->fh_size = htobe32(tree.end - start);
+ tree.header->fh_struct_off = htobe32(tree.tree - start);
+ tree.header->fh_strings_off = htobe32(tree.strings - start);
+ tree.header->fh_reserve_off = htobe32(tree.memory - start);
+ tree.header->fh_strings_size = htobe32(tree.strings_size);
+ if (tree.version >= 17)
+ tree.header->fh_struct_size = htobe32(tree.struct_size);
+}
+
+/*
+ * Return the size of the FDT.
+ */
+size_t
+fdt_get_size(void *fdt)
+{
+ if (!fdt)
+ return 0;
+
+ if (!fdt_check_head(fdt))
+ return 0;
+
+ return betoh32(((struct fdt_head *)fdt)->fh_size);
+}
+
+/*
+ * Retrieve string pointer from strings table.
+ */
+char *
+fdt_get_str(uint32_t num)
+{
+ if (num > tree.strings_size)
+ return NULL;
+ return (tree.strings) ? (tree.strings + num) : NULL;
+}
+
+int
+fdt_add_str(char *name)
+{
+ size_t len = roundup(strlen(name) + 1, sizeof(uint32_t));
+ char *end = tree.strings + tree.strings_size;
+
+ memmove(end + len, end, tree.end - end);
+ tree.strings_size += len;
+ if (tree.tree > tree.strings)
+ tree.tree += len;
+ if (tree.memory > tree.strings)
+ tree.memory += len;
+ tree.end += len;
+ memset(end, 0, len);
+ memcpy(end, name, strlen(name));
+
+ return (end - tree.strings);
+}
+
+/*
+ * Utility functions for skipping parts of tree.
+ */
+void *
+skip_property(uint32_t *ptr)
+{
+ uint32_t size;
+
+ size = betoh32(*(ptr + 1));
+ /* move forward by magic + size + nameid + rounded up property size */
+ ptr += 3 + roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+
+ return ptr;
+}
+
+void *
+skip_props(uint32_t *ptr)
+{
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ ptr = skip_property(ptr);
+ }
+ return ptr;
+}
+
+void *
+skip_node_name(uint32_t *ptr)
+{
+ /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */
+ return ptr + roundup(strlen((char *)ptr) + 1,
+ sizeof(uint32_t)) / sizeof(uint32_t);
+}
+
+/*
+ * Retrieves node property, the returned pointer is inside the fdt tree,
+ * so we should not modify content pointed by it directly.
+ */
+int
+fdt_node_property(void *node, char *name, char **out)
+{
+ uint32_t *ptr;
+ uint32_t nameid;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ if (!strcmp(name, tmp)) {
+ *out = (char *)(ptr + 3); /* beginning of the value */
+ return betoh32(*(ptr + 1)); /* size of value */
+ }
+ ptr = skip_property(ptr);
+ }
+ return 0;
+}
+
+int
+fdt_node_set_property(void *node, char *name, void *data, int len)
+{
+ uint32_t *ptr, *next;
+ uint32_t nameid;
+ uint32_t curlen;
+ size_t delta;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ next = skip_property(ptr);
+ if (!strcmp(name, tmp)) {
+ curlen = betoh32(*(ptr + 1));
+ delta = roundup(len, sizeof(uint32_t)) -
+ roundup(curlen, sizeof(uint32_t));
+ memmove((char *)next + delta, next,
+ tree.end - (char *)next);
+ tree.struct_size += delta;
+ if (tree.strings > tree.tree)
+ tree.strings += delta;
+ if (tree.memory > tree.tree)
+ tree.memory += delta;
+ tree.end += delta;
+ *(ptr + 1) = htobe32(len);
+ memcpy(ptr + 3, data, len);
+ return 1;
+ }
+ ptr = next;
+ }
+ return 0;
+}
+
+int
+fdt_node_add_property(void *node, char *name, void *data, int len)
+{
+ char *dummy;
+
+ if (!tree_inited)
+ return 0;
+
+ if (!fdt_node_property(node, name, &dummy)) {
+ uint32_t *ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ memmove(ptr + 3, ptr, tree.end - (char *)ptr);
+ tree.struct_size += 3 * sizeof(uint32_t);
+ if (tree.strings > tree.tree)
+ tree.strings += 3 * sizeof(uint32_t);
+ if (tree.memory > tree.tree)
+ tree.memory += 3 * sizeof(uint32_t);
+ tree.end += 3 * sizeof(uint32_t);
+ *ptr++ = htobe32(FDT_PROPERTY);
+ *ptr++ = htobe32(0);
+ *ptr++ = htobe32(fdt_add_str(name));
+ }
+
+ return fdt_node_set_property(node, name, data, len);
+}
+
+int
+fdt_node_add_node(void *node, char *name, void **child)
+{
+ size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)) + 8;
+ uint32_t *ptr = (uint32_t *)node;
+
+ if (!tree_inited)
+ return 0;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ memmove((char *)ptr + len, ptr, tree.end - (char *)ptr);
+ tree.struct_size += len;
+ if (tree.strings > tree.tree)
+ tree.strings += len;
+ if (tree.memory > tree.tree)
+ tree.memory += len;
+ tree.end += len;
+
+ *child = ptr;
+ *ptr++ = htobe32(FDT_NODE_BEGIN);
+ memset(ptr, 0, len - 8);
+ memcpy(ptr, name, strlen(name));
+ ptr += (len - 8) / sizeof(uint32_t);
+ *ptr++ = htobe32(FDT_NODE_END);
+
+ return 1;
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node, no matter if it exists or not.
+ */
+void *
+skip_node(void *node)
+{
+ uint32_t *ptr = node;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node if exists, otherwise returns NULL.
+ * If passed 0 will return first node of the tree (root).
+ */
+void *
+fdt_next_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (node == NULL) {
+ ptr = (uint32_t *)tree.tree;
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL;
+ }
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ if (betoh32(*ptr) != FDT_NODE_END)
+ return NULL;
+
+ if (betoh32(*(ptr + 1)) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves node property as integers and puts them in the given
+ * integer array.
+ */
+int
+fdt_node_property_ints(void *node, char *name, int *out, int outlen)
+{
+ int *data;
+ int i, inlen;
+
+ inlen = fdt_node_property(node, name, (char **)&data) / sizeof(int);
+ if (inlen <= 0)
+ return -1;
+
+ for (i = 0; i < inlen && i < outlen; i++)
+ out[i] = betoh32(data[i]);
+
+ return i;
+}
+
+/*
+ * Retrieves node property as an integer.
+ */
+int
+fdt_node_property_int(void *node, char *name, int *out)
+{
+ return fdt_node_property_ints(node, name, out, 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node
+ */
+void *
+fdt_child_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+ /* check if there is a child node */
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL;
+}
+
+/*
+ * Retrieves node name.
+ */
+char *
+fdt_node_name(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (char *)(ptr + 1);
+}
+
+void *
+fdt_find_node(char *name)
+{
+ void *node = fdt_next_node(0);
+ const char *p = name;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (*p != '/')
+ return NULL;
+
+ while (*p) {
+ void *child;
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (*p == 0)
+ return node;
+ q = strchr(p, '/');
+ if (q == NULL)
+ q = p + strlen(p);
+
+ for (child = fdt_child_node(node); child;
+ child = fdt_next_node(child)) {
+ if (strncmp(p, fdt_node_name(child), q - p) == 0) {
+ node = child;
+ break;
+ }
+ }
+
+ p = q;
+ }
+
+ return node;
+}
+
+void *
+fdt_parent_node_recurse(void *pnode, void *child)
+{
+ void *node = fdt_child_node(pnode);
+ void *tmp;
+
+ while (node && (node != child)) {
+ if ((tmp = fdt_parent_node_recurse(node, child)))
+ return tmp;
+ node = fdt_next_node(node);
+ }
+ return (node) ? pnode : NULL;
+}
+
+void *
+fdt_parent_node(void *node)
+{
+ void *pnode = fdt_next_node(0);
+
+ if (!tree_inited)
+ return NULL;
+
+ if (node == pnode)
+ return NULL;
+
+ return fdt_parent_node_recurse(pnode, node);
+}
+
+int
+fdt_node_is_compatible(void *node, const char *name)
+{
+ char *data;
+ int len;
+
+ len = fdt_node_property(node, "compatible", &data);
+ while (len > 0) {
+ if (strcmp(data, name) == 0)
+ return 1;
+ len -= strlen(data) + 1;
+ data += strlen(data) + 1;
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+/*
+ * Debug methods for printing whole tree, particular nodes and properties
+ */
+void *
+fdt_print_property(void *node, int level)
+{
+ uint32_t *ptr;
+ char *tmp, *value;
+ int cnt;
+ uint32_t nameid, size;
+
+ ptr = (uint32_t *)node;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (betoh32(*ptr) != FDT_PROPERTY)
+ return ptr; /* should never happen */
+
+ /* extract property name_id and size */
+ size = betoh32(*++ptr);
+ nameid = betoh32(*++ptr);
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+
+ tmp = fdt_get_str(nameid);
+ printf("\t%s : ", tmp ? tmp : "NO_NAME");
+
+ ptr++;
+ value = (char *)ptr;
+
+ if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") ||
+ !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") ||
+ !strcmp(tmp, "linux,stdout-path")) {
+ printf("%s", value);
+ } else if (!strcmp(tmp, "clock-frequency") ||
+ !strcmp(tmp, "timebase-frequency")) {
+ printf("%d", betoh32(*((unsigned int *)value)));
+ } else {
+ for (cnt = 0; cnt < size; cnt++) {
+ if ((cnt % sizeof(uint32_t)) == 0)
+ printf(" ");
+ printf("%x%x", value[cnt] >> 4, value[cnt] & 0xf);
+ }
+ }
+ ptr += roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+ printf("\n");
+
+ return ptr;
+}
+
+void
+fdt_print_node(void *node, int level)
+{
+ uint32_t *ptr;
+ int cnt;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return;
+
+ ptr++;
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+ printf("%s :\n", fdt_node_name(node));
+ ptr = skip_node_name(ptr);
+
+ while (betoh32(*ptr) == FDT_PROPERTY)
+ ptr = fdt_print_property(ptr, level);
+}
+
+void
+fdt_print_node_recurse(void *node, int level)
+{
+ void *child;
+
+ fdt_print_node(node, level);
+ for (child = fdt_child_node(node); child; child = fdt_next_node(child))
+ fdt_print_node_recurse(child, level + 1);
+}
+
+void
+fdt_print_tree(void)
+{
+ fdt_print_node_recurse(fdt_next_node(0), 0);
+}
+#endif
--- /dev/null
+/* $OpenBSD: fdt.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.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.
+ */
+
+struct fdt_head {
+ uint32_t fh_magic;
+ uint32_t fh_size;
+ uint32_t fh_struct_off;
+ uint32_t fh_strings_off;
+ uint32_t fh_reserve_off;
+ uint32_t fh_version;
+ uint32_t fh_comp_ver; /* last compatible version */
+ uint32_t fh_boot_cpu_id; /* fh_version >=2 */
+ uint32_t fh_strings_size; /* fh_version >=3 */
+ uint32_t fh_struct_size; /* fh_version >=17 */
+};
+
+struct fdt {
+ struct fdt_head *header;
+ char *tree;
+ char *strings;
+ char *memory;
+ char *end;
+ int version;
+ int strings_size;
+ int struct_size;
+};
+
+#define FDT_MAGIC 0xd00dfeed
+#define FDT_NODE_BEGIN 0x01
+#define FDT_NODE_END 0x02
+#define FDT_PROPERTY 0x03
+#define FDT_NOP 0x04
+#define FDT_END 0x09
+
+#define FDT_CODE_VERSION 0x11
+
+int fdt_init(void *);
+void fdt_finalize(void);
+size_t fdt_get_size(void *);
+void *fdt_next_node(void *);
+void *fdt_child_node(void *);
+char *fdt_node_name(void *);
+void *fdt_find_node(char *);
+int fdt_node_property(void *, char *, char **);
+int fdt_node_property_int(void *, char *, int *);
+int fdt_node_property_ints(void *, char *, int *, int);
+int fdt_node_set_property(void *, char *, void *, int);
+int fdt_node_add_property(void *, char *, void *, int);
+int fdt_node_add_node(void *, char *, void **);
+void *fdt_parent_node(void *);
+int fdt_node_is_compatible(void *, const char *);
+#ifdef DEBUG
+void *fdt_print_property(void *, int);
+void fdt_print_node(void *, int);
+void fdt_print_tree(void);
+#endif
--- /dev/null
+/* $OpenBSD: heap.h,v 1.1 2021/04/28 19:01:00 drahn 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;
+}
--- /dev/null
+/* $OpenBSD: ldscript.riscv64,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+/*
+OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd")
+*/
+OUTPUT_ARCH(elf64-littleriscv)
+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)
+ *(.plt)
+ } =0xD4200000
+ . = ALIGN(16);
+ .data : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
+ *(.opd)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.data1)
+ *(.plabel)
+
+ . = ALIGN(16);
+ __bss_start = .;
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss *.bss.*)
+ *(COMMON)
+ . = ALIGN(16);
+ __bss_end = .;
+ }
+ . = ALIGN(16);
+ set_Xcommand_set : {
+ __start_set_Xcommand_set = .;
+ *(set_Xcommand_set)
+ __stop_set_Xcommand_set = .;
+ }
+ set_Xficl_compile_set : {
+ __start_set_Xficl_compile_set = .;
+ *(set_Xficl_compile_set)
+ __stop_set_Xficl_compile_set = .;
+ }
+ . = ALIGN(16);
+ __gp = .;
+ .sdata : {
+ *(.got.plt .got)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ *(dynsbss)
+ *(.scommon)
+ }
+ . = ALIGN(16);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(16);
+ .rela.dyn : {
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ *(.rela.plt)
+ *(.relset_*)
+ *(.rela.dyn .rela.dyn.*)
+ }
+ . = ALIGN(16);
+ .reloc : { *(.reloc) }
+ . = ALIGN(16);
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ _edata = .;
+
+ /* Unused sections */
+ .hash : { *(.hash) }
+}
--- /dev/null
+/* $OpenBSD: libsa.h,v 1.1 2021/04/28 19:01:00 drahn 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
+
+void machdep(void);
+void devboot(dev_t, char *);
+
+#define MACHINE_CMD cmd_machine
--- /dev/null
+/* $OpenBSD: self_reloc.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+/*-
+ * 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/param.h>
+#include <machine/reloc.h>
+
+#if defined(__aarch64__) || defined(__amd64__) || defined(__riscv)
+#define ELFSIZE 64
+#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 ELFSIZE 32
+#define ElfW_Rel Elf32_Rel
+#define ElfW_Dyn Elf32_Dyn
+#define ELFW_R_TYPE ELF32_R_TYPE
+#else
+#error architecture not supported
+#endif
+
+#include <sys/exec_elf.h>
+
+#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
+#elif defined(__riscv)
+#define RELOC_TYPE_NONE R_RISCV_NONE
+#define RELOC_TYPE_RELATIVE R_RISCV_RELATIVE
+#endif
+
+/*
+ * A simple elf relocator.
+ */
+void
+self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic)
+{
+ Elf_Word relsz, relent;
+ Elf_Addr *newaddr;
+ ElfW_Rel *rel = NULL;
+ 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. We rely on the object having been
+ * linked at 0, so that the difference between the load and link
+ * address is the same as the load address.
+ */
+ 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:
+ newaddr = (Elf_Addr *)(rel->r_offset + baseaddr);
+#ifdef ELF_RELA
+ /* Addend relative to the base address. */
+ *newaddr = baseaddr + rel->r_addend;
+#else
+ /* Address relative to the base address. */
+ *newaddr += baseaddr;
+#endif
+ break;
+ default:
+ /* XXX: do we need other relocations ? */
+ break;
+ }
+ rel = (ElfW_Rel *) ((caddr_t) rel + relent);
+ }
+}
--- /dev/null
+/* $OpenBSD: softraid_riscv64.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+/*
+ * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
+ *
+ * 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 <sys/disklabel.h>
+#include <sys/reboot.h>
+
+#include <dev/biovar.h>
+#include <dev/softraidvar.h>
+
+#include <lib/libsa/aes_xts.h>
+#include <lib/libsa/softraid.h>
+#include <lib/libz/zlib.h>
+
+#include <efi.h>
+
+#include "libsa.h"
+#include "disk.h"
+#include "efidev.h"
+#include "softraid_riscv64.h"
+
+static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
+static uint64_t findopenbsd_gpt(struct sr_boot_volume *, const char **);
+
+void
+srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
+{
+ struct sr_meta_opt_hdr *omh;
+ struct sr_meta_opt_item *omi;
+#if 0
+ u_int8_t checksum[MD5_DIGEST_LENGTH];
+#endif
+ int i;
+
+ /* Process optional metadata. */
+ omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
+ sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
+ for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
+
+#ifdef BIOS_DEBUG
+ printf("Found optional metadata of type %u, length %u\n",
+ omh->som_type, omh->som_length);
+#endif
+
+ /* Unsupported old fixed length optional metadata. */
+ if (omh->som_length == 0) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ SR_OLD_META_OPT_SIZE);
+ continue;
+ }
+
+ /* Load variable length optional metadata. */
+ omi = alloc(sizeof(struct sr_meta_opt_item));
+ bzero(omi, sizeof(struct sr_meta_opt_item));
+ SLIST_INSERT_HEAD(som, omi, omi_link);
+ omi->omi_som = alloc(omh->som_length);
+ bzero(omi->omi_som, omh->som_length);
+ bcopy(omh, omi->omi_som, omh->som_length);
+
+#if 0
+ /* XXX - Validate checksum. */
+ bcopy(&omi->omi_som->som_checksum, &checksum,
+ MD5_DIGEST_LENGTH);
+ bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH);
+ sr_checksum(sc, omi->omi_som,
+ &omi->omi_som->som_checksum, omh->som_length);
+ if (bcmp(&checksum, &omi->omi_som->som_checksum,
+ sizeof(checksum)))
+ panic("%s: invalid optional metadata checksum",
+ DEVNAME(sc));
+#endif
+
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ omh->som_length);
+ }
+}
+
+void
+srprobe_keydisk_load(struct sr_metadata *sm)
+{
+ struct sr_meta_opt_hdr *omh;
+ struct sr_meta_keydisk *skm;
+ struct sr_boot_keydisk *kd;
+ int i;
+
+ /* Process optional metadata. */
+ omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
+ sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
+ for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
+
+ /* Unsupported old fixed length optional metadata. */
+ if (omh->som_length == 0) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ SR_OLD_META_OPT_SIZE);
+ continue;
+ }
+
+ if (omh->som_type != SR_OPT_KEYDISK) {
+ omh = (struct sr_meta_opt_hdr *)((void *)omh +
+ omh->som_length);
+ continue;
+ }
+
+ kd = alloc(sizeof(struct sr_boot_keydisk));
+ bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
+ skm = (struct sr_meta_keydisk*)omh;
+ bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
+ SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
+ }
+}
+
+void
+srprobe(void)
+{
+ struct sr_boot_volume *bv, *bv1, *bv2;
+ struct sr_boot_chunk *bc, *bc1, *bc2;
+ struct sr_meta_chunk *mc;
+ struct sr_metadata *md;
+ struct diskinfo *dip;
+ struct partition *pp;
+ int i, error, volno;
+ daddr_t off;
+
+ /* Probe for softraid volumes. */
+ SLIST_INIT(&sr_volumes);
+ SLIST_INIT(&sr_keydisks);
+
+ md = alloc(SR_META_SIZE * DEV_BSIZE);
+
+ TAILQ_FOREACH(dip, &disklist, list) {
+
+ /* Make sure disklabel has been read. */
+ if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0)
+ continue;
+
+ for (i = 0; i < MAXPARTITIONS; i++) {
+
+ pp = &dip->disklabel.d_partitions[i];
+ if (pp->p_fstype != FS_RAID || pp->p_size == 0)
+ continue;
+
+ /* Read softraid metadata. */
+ bzero(md, SR_META_SIZE * DEV_BSIZE);
+ off = DL_SECTOBLK(&dip->disklabel, DL_GETPOFFSET(pp));
+ off += SR_META_OFFSET;
+ error = dip->diskio(F_READ, dip, off, SR_META_SIZE, md);
+ if (error)
+ continue;
+
+ /* Is this valid softraid metadata? */
+ if (md->ssdi.ssd_magic != SR_MAGIC)
+ continue;
+
+ /* XXX - validate checksum. */
+
+ /* Handle key disks separately... */
+ if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
+ srprobe_keydisk_load(md);
+ continue;
+ }
+
+ /* Locate chunk-specific metadata for this chunk. */
+ mc = (struct sr_meta_chunk *)(md + 1);
+ mc += md->ssdi.ssd_chunk_id;
+
+ bc = alloc(sizeof(struct sr_boot_chunk));
+ bc->sbc_diskinfo = dip;
+ bc->sbc_disk = 0;
+ bc->sbc_part = 'a' + i;
+
+ bc->sbc_mm = 0;
+
+ bc->sbc_chunk_id = md->ssdi.ssd_chunk_id;
+ bc->sbc_ondisk = md->ssd_ondisk;
+ bc->sbc_state = mc->scm_status;
+
+ SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
+ if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
+ sizeof(md->ssdi.ssd_uuid)) == 0)
+ break;
+ }
+
+ if (bv == NULL) {
+ bv = alloc(sizeof(struct sr_boot_volume));
+ bzero(bv, sizeof(struct sr_boot_volume));
+ bv->sbv_level = md->ssdi.ssd_level;
+ bv->sbv_volid = md->ssdi.ssd_volid;
+ bv->sbv_chunk_no = md->ssdi.ssd_chunk_no;
+ bv->sbv_flags = md->ssdi.ssd_vol_flags;
+ bv->sbv_size = md->ssdi.ssd_size;
+ bv->sbv_secsize = md->ssdi.ssd_secsize;
+ bv->sbv_data_blkno = md->ssd_data_blkno;
+ bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
+ sizeof(md->ssdi.ssd_uuid));
+ SLIST_INIT(&bv->sbv_chunks);
+ SLIST_INIT(&bv->sbv_meta_opt);
+
+ /* Load optional metadata for this volume. */
+ srprobe_meta_opt_load(md, &bv->sbv_meta_opt);
+
+ /* Maintain volume order. */
+ bv2 = NULL;
+ SLIST_FOREACH(bv1, &sr_volumes, sbv_link) {
+ if (bv1->sbv_volid > bv->sbv_volid)
+ break;
+ bv2 = bv1;
+ }
+ if (bv2 == NULL)
+ SLIST_INSERT_HEAD(&sr_volumes, bv,
+ sbv_link);
+ else
+ SLIST_INSERT_AFTER(bv2, bv, sbv_link);
+ }
+
+ /* Maintain chunk order. */
+ bc2 = NULL;
+ SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) {
+ if (bc1->sbc_chunk_id > bc->sbc_chunk_id)
+ break;
+ bc2 = bc1;
+ }
+ if (bc2 == NULL)
+ SLIST_INSERT_HEAD(&bv->sbv_chunks,
+ bc, sbc_link);
+ else
+ SLIST_INSERT_AFTER(bc2, bc, sbc_link);
+
+ bv->sbv_chunks_found++;
+ }
+ }
+
+ /*
+ * Assemble RAID volumes.
+ */
+ volno = 0;
+ SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
+
+ /* Skip if this is a hotspare "volume". */
+ if (bv->sbv_level == SR_HOTSPARE_LEVEL &&
+ bv->sbv_chunk_no == 1)
+ continue;
+
+ /* Determine current ondisk version. */
+ bv->sbv_ondisk = 0;
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
+ if (bc->sbc_ondisk > bv->sbv_ondisk)
+ bv->sbv_ondisk = bc->sbc_ondisk;
+ }
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
+ if (bc->sbc_ondisk != bv->sbv_ondisk)
+ bc->sbc_state = BIOC_SDOFFLINE;
+ }
+
+ /* XXX - Check for duplicate chunks. */
+
+ /*
+ * Validate that volume has sufficient chunks for
+ * read-only access.
+ *
+ * XXX - check chunk states.
+ */
+ bv->sbv_state = BIOC_SVOFFLINE;
+ switch (bv->sbv_level) {
+ case 0:
+ case 'C':
+ case 'c':
+ if (bv->sbv_chunk_no == bv->sbv_chunks_found)
+ bv->sbv_state = BIOC_SVONLINE;
+ break;
+
+ case 1:
+ if (bv->sbv_chunk_no == bv->sbv_chunks_found)
+ bv->sbv_state = BIOC_SVONLINE;
+ else if (bv->sbv_chunks_found > 0)
+ bv->sbv_state = BIOC_SVDEGRADED;
+ break;
+ }
+
+ bv->sbv_unit = volno++;
+ if (bv->sbv_state != BIOC_SVOFFLINE)
+ printf(" sr%d%s", bv->sbv_unit,
+ bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
+ }
+
+ explicit_bzero(md, SR_META_SIZE * DEV_BSIZE);
+ free(md, SR_META_SIZE * DEV_BSIZE);
+}
+
+int
+sr_strategy(struct sr_boot_volume *bv, int rw, daddr_t blk, size_t size,
+ void *buf, size_t *rsize)
+{
+ struct diskinfo *sr_dip, *dip;
+ struct sr_boot_chunk *bc;
+ struct aes_xts_ctx ctx;
+ size_t i, j, nsect;
+ daddr_t blkno;
+ u_char iv[8];
+ u_char *bp;
+ int err;
+
+ /* We only support read-only softraid. */
+ if (rw != F_READ)
+ return ENOTSUP;
+
+ /* Partition offset within softraid volume. */
+ sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
+ blk += DL_SECTOBLK(&sr_dip->disklabel,
+ sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset);
+
+ if (bv->sbv_level == 0) {
+ return ENOTSUP;
+ } else if (bv->sbv_level == 1) {
+
+ /* Select first online chunk. */
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
+ if (bc->sbc_state == BIOC_SDONLINE)
+ break;
+ if (bc == NULL)
+ return EIO;
+
+ dip = (struct diskinfo *)bc->sbc_diskinfo;
+ blk += bv->sbv_data_blkno;
+
+ /* XXX - If I/O failed we should try another chunk... */
+ return dip->strategy(dip, rw, blk, size, buf, rsize);
+
+ } else if (bv->sbv_level == 'C') {
+
+ /* Select first online chunk. */
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
+ if (bc->sbc_state == BIOC_SDONLINE)
+ break;
+ if (bc == NULL)
+ return EIO;
+
+ dip = (struct diskinfo *)bc->sbc_diskinfo;
+
+ /* XXX - select correct key. */
+ aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64);
+
+ nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
+ for (i = 0; i < nsect; i++) {
+ blkno = blk + i;
+ bp = ((u_char *)buf) + i * DEV_BSIZE;
+ err = dip->strategy(dip, rw, bv->sbv_data_blkno + blkno,
+ DEV_BSIZE, bp, NULL);
+ if (err != 0)
+ return err;
+
+ bcopy(&blkno, iv, sizeof(blkno));
+ aes_xts_reinit(&ctx, iv);
+ for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
+ aes_xts_decrypt(&ctx, bp + j);
+ }
+ if (rsize != NULL)
+ *rsize = nsect * DEV_BSIZE;
+
+ return err;
+
+ } else
+ return ENOTSUP;
+}
+
+/*
+ * Returns 0 if the MBR with the provided partition array is a GPT protective
+ * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
+ * one MBR partition, an EFI partition that either covers the whole disk or as
+ * much of it as is possible with a 32bit size field.
+ *
+ * Taken from kern/subr_disk.c.
+ *
+ * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
+ */
+static int
+gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
+{
+ struct dos_partition *dp2;
+ int efi, found, i;
+ u_int32_t psize;
+
+ found = efi = 0;
+ for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
+ if (dp2->dp_typ == DOSPTYP_UNUSED)
+ continue;
+ found++;
+ if (dp2->dp_typ != DOSPTYP_EFI)
+ continue;
+ psize = letoh32(dp2->dp_size);
+ if (psize == (dsize - 1) ||
+ psize == UINT32_MAX) {
+ if (letoh32(dp2->dp_start) == 1)
+ efi++;
+ }
+ }
+ if (found == 1 && efi == 1)
+ return (0);
+
+ return (1);
+}
+
+static uint64_t
+findopenbsd_gpt(struct sr_boot_volume *bv, const char **err)
+{
+ struct gpt_header gh;
+ int i, part, found;
+ uint64_t lba;
+ uint32_t orig_csum, new_csum;
+ uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec;
+ uint32_t gpsectors;
+ const char openbsd_uuid_code[] = GPT_UUID_OPENBSD;
+ struct gpt_partition gp;
+ static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space;
+ u_char *buf;
+
+ /* Prepare OpenBSD UUID */
+ if (openbsd_uuid == NULL) {
+ /* XXX: should be replaced by uuid_dec_be() */
+ memcpy(&openbsd_uuid_space, openbsd_uuid_code,
+ sizeof(openbsd_uuid_space));
+ openbsd_uuid_space.time_low =
+ betoh32(openbsd_uuid_space.time_low);
+ openbsd_uuid_space.time_mid =
+ betoh16(openbsd_uuid_space.time_mid);
+ openbsd_uuid_space.time_hi_and_version =
+ betoh16(openbsd_uuid_space.time_hi_and_version);
+
+ openbsd_uuid = &openbsd_uuid_space;
+ }
+
+ if (bv->sbv_secsize > 4096) {
+ *err = "disk sector > 4096 bytes\n";
+ return (-1);
+ }
+ buf = alloc(bv->sbv_secsize);
+ if (buf == NULL) {
+ *err = "out of memory\n";
+ return (-1);
+ }
+ bzero(buf, bv->sbv_secsize);
+
+ /* LBA1: GPT Header */
+ lba = 1;
+ sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), DEV_BSIZE,
+ buf, NULL);
+ memcpy(&gh, buf, sizeof(gh));
+
+ /* Check signature */
+ if (letoh64(gh.gh_sig) != GPTSIGNATURE) {
+ *err = "bad GPT signature\n";
+ free(buf, bv->sbv_secsize);
+ return (-1);
+ }
+
+ if (letoh32(gh.gh_rev) != GPTREVISION) {
+ *err = "bad GPT revision\n";
+ free(buf, bv->sbv_secsize);
+ return (-1);
+ }
+
+ ghsize = letoh32(gh.gh_size);
+ if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) {
+ *err = "bad GPT header size\n";
+ free(buf, bv->sbv_secsize);
+ return (-1);
+ }
+
+ /* Check checksum */
+ orig_csum = gh.gh_csum;
+ gh.gh_csum = 0;
+ new_csum = crc32(0, (unsigned char *)&gh, ghsize);
+ gh.gh_csum = orig_csum;
+ if (letoh32(orig_csum) != new_csum) {
+ *err = "bad GPT header checksum\n";
+ free(buf, bv->sbv_secsize);
+ return (-1);
+ }
+
+ lba = letoh64(gh.gh_part_lba);
+ ghpartsize = letoh32(gh.gh_part_size);
+ ghpartspersec = bv->sbv_secsize / ghpartsize;
+ ghpartnum = letoh32(gh.gh_part_num);
+ gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec;
+ new_csum = crc32(0L, Z_NULL, 0);
+ found = 0;
+ for (i = 0; i < gpsectors; i++, lba++) {
+ sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE),
+ bv->sbv_secsize, buf, NULL);
+ for (part = 0; part < ghpartspersec; part++) {
+ if (ghpartnum == 0)
+ break;
+ new_csum = crc32(new_csum, buf + part * sizeof(gp),
+ sizeof(gp));
+ ghpartnum--;
+ if (found)
+ continue;
+ memcpy(&gp, buf + part * sizeof(gp), sizeof(gp));
+ if (memcmp(&gp.gp_type, openbsd_uuid,
+ sizeof(struct uuid)) == 0)
+ found = 1;
+ }
+ }
+
+ free(buf, bv->sbv_secsize);
+
+ if (new_csum != letoh32(gh.gh_part_csum)) {
+ *err = "bad GPT entries checksum\n";
+ return (-1);
+ }
+ if (found)
+ return (letoh64(gp.gp_lba_start));
+
+ return (-1);
+}
+
+const char *
+sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
+{
+ struct dos_partition *dp;
+ struct dos_mbr mbr;
+ const char *err = NULL;
+ u_int start = 0;
+ char buf[DEV_BSIZE];
+ int i;
+
+ /* Check for MBR to determine partition offset. */
+ bzero(&mbr, sizeof(mbr));
+ sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL);
+ if (gpt_chk_mbr(mbr.dmbr_parts, bv->sbv_size /
+ (bv->sbv_secsize / DEV_BSIZE)) == 0) {
+ start = findopenbsd_gpt(bv, &err);
+ if (start == (u_int)-1) {
+ if (err != NULL)
+ return (err);
+ return "no OpenBSD partition\n";
+ }
+ } else if (mbr.dmbr_sign == DOSMBR_SIGNATURE) {
+
+ /* Search for OpenBSD partition */
+ for (i = 0; i < NDOSPART; i++) {
+ dp = &mbr.dmbr_parts[i];
+ if (!dp->dp_size)
+ continue;
+ if (dp->dp_typ == DOSPTYP_OPENBSD) {
+ start = dp->dp_start;
+ break;
+ }
+ }
+ }
+
+ /* Read the disklabel. */
+ sr_strategy(bv, F_READ,
+ start * (bv->sbv_secsize / DEV_BSIZE) + DOS_LABELSECTOR,
+ sizeof(struct disklabel), buf, NULL);
+
+#ifdef BIOS_DEBUG
+ printf("sr_getdisklabel: magic %lx\n",
+ ((struct disklabel *)buf)->d_magic);
+ for (i = 0; i < MAXPARTITIONS; i++)
+ printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
+ (int)((struct disklabel *)buf)->d_partitions[i].p_fstype,
+ (int)((struct disklabel *)buf)->d_partitions[i].p_size,
+ (int)((struct disklabel *)buf)->d_partitions[i].p_offset);
+#endif
+
+ /* Fill in disklabel */
+ return (getdisklabel(buf, label));
+}
+
+int
+sropen(struct open_file *f, ...)
+{
+ struct diskinfo *dip = NULL;
+ struct sr_boot_volume *bv;
+ va_list ap;
+ u_int unit, part;
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ /* Create a fake diskinfo for this softraid volume. */
+ SLIST_FOREACH(bv, &sr_volumes, sbv_link)
+ if (bv->sbv_unit == unit)
+ break;
+ if (bv == NULL) {
+ printf("Unknown device: sr%d\n", unit);
+ return EADAPT;
+ }
+
+ if (bv->sbv_level == 'C' && bv->sbv_keys == NULL)
+ if (sr_crypto_unlock_volume(bv) != 0)
+ return EPERM;
+
+ if (bv->sbv_diskinfo == NULL) {
+ dip = alloc(sizeof(struct diskinfo));
+ bzero(dip, sizeof(*dip));
+ dip->diskio = srdiskio;
+ dip->strategy = srstrategy;
+ bv->sbv_diskinfo = dip;
+ dip->sr_vol = bv;
+ }
+
+ dip = bv->sbv_diskinfo;
+
+ if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) {
+ /* Attempt to read disklabel. */
+ bv->sbv_part = 'c';
+ if (sr_getdisklabel(bv, &dip->disklabel))
+ return ERDLAB;
+ dip->flags |= DISKINFO_FLAG_GOODLABEL;
+ }
+
+ bv->sbv_part = part + 'a';
+
+ bootdev_dip = dip;
+ f->f_devdata = dip;
+
+ return 0;
+}
+
+int
+srstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ struct diskinfo *dip = (struct diskinfo *)devdata;
+ return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
+}
+
+int
+srdiskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
+{
+ return dip->diskio(rw, dip, off, nsect, buf);
+}
+
+int
+srclose(struct open_file *f)
+{
+ f->f_devdata = NULL;
+
+ return 0;
+}
+
+int
+srioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return 0;
+}
--- /dev/null
+/* $OpenBSD: softraid_riscv64.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+
+/*
+ * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
+ *
+ * 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.
+ */
+
+#ifndef _SOFTRAID_ARM64_H_
+#define _SOFTRAID_ARM64_H_
+
+void srprobe(void);
+
+const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *);
+int sr_strategy(struct sr_boot_volume *, int, daddr_t, size_t,
+ void *, size_t *);
+int sropen(struct open_file *, ...);
+int srstrategy(void *, int, daddr_t, size_t, void *, size_t *);
+int srdiskio(int, struct diskinfo *, u_int, int, void *);
+int srclose(struct open_file *);
+int srioctl(struct open_file *, u_long, void *);
+
+#endif /* _SOFTRAID_ARM64_H */
--- /dev/null
+/* $OpenBSD: start.S,v 1.1 2021/04/28 19:01:00 drahn Exp $ */
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * 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.
+ *
+ * $FreeBSD: head/sys/boot/efi/loader/arch/arm64/start.S 282727 2015-05-10 13:24:26Z ian $
+ */
+
+/*
+ * We need to be a PE32+ file for EFI. On some architectures we can use
+ * objcopy to create the correct file, however on arm64 we need to do
+ * it ourselves.
+ */
+
+#define IMAGE_FILE_MACHINE_RISCV64 0x5064
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+
+ .section .peheader, "a"
+efi_start:
+ /* The MS-DOS Stub, only used to get the offset of the COFF header */
+ .ascii "MZ"
+ .short 0
+ .space 0x38
+ .long pe_sig - efi_start
+
+ /* The PE32 Signature. Needs to be 8-byte aligned */
+ .align 3
+pe_sig:
+ .ascii "PE"
+ .short 0
+coff_head:
+ .short IMAGE_FILE_MACHINE_RISCV64 /* RISCV64 file */
+ .short 2 /* 2 Sections */
+ .long 0 /* Timestamp */
+ .long 0 /* No symbol table */
+ .long 0 /* No symbols */
+ .short section_table - optional_header /* Optional header size */
+ .short 0 /* Characteristics TODO: Fill in */
+
+optional_header:
+ .short 0x020b /* PE32+ (64-bit addressing) */
+ .byte 0 /* Major linker version */
+ .byte 0 /* Minor linker version */
+ .long _edata - _end_header /* Code size */
+ .long 0 /* No initialized data */
+ .long 0 /* No uninitialized data */
+ .long _start - efi_start /* Entry point */
+ .long _end_header - efi_start /* Start of code */
+
+optional_windows_header:
+ .quad 0 /* Image base */
+ .long 32 /* Section Alignment */
+ .long 8 /* File alignment */
+ .short 0 /* Major OS version */
+ .short 0 /* Minor OS version */
+ .short 0 /* Major image version */
+ .short 0 /* Minor image version */
+ .short 0 /* Major subsystem version */
+ .short 0 /* Minor subsystem version */
+ .long 0 /* Win32 version */
+ .long _edata - efi_start /* Image size */
+ .long _end_header - efi_start /* Header size */
+ .long 0 /* Checksum */
+ .short 0xa /* Subsystem (EFI app) */
+ .short 0 /* DLL Characteristics */
+ .quad 0 /* Stack reserve */
+ .quad 0 /* Stack commit */
+ .quad 0 /* Heap reserve */
+ .quad 0 /* Heap commit */
+ .long 0 /* Loader flags */
+ .long 6 /* Number of RVAs */
+
+ /* RVAs: */
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+section_table:
+ /* We need a .reloc section for EFI */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long 0 /* Virtual size */
+ .long 0 /* Virtual address */
+ .long 0 /* Size of raw data */
+ .long 0 /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */
+
+ /* The contents of the loader */
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long _edata - _end_header /* Virtual size */
+ .long _end_header - efi_start /* Virtual address */
+ .long _edata - _end_header /* Size of raw data */
+ .long _end_header - efi_start /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_MEM_READ) /* Characteristics */
+_end_header:
+
+ .text
+ .globl _start
+_start:
+ /* Save the boot params to the stack */
+ addi sp, sp, -16
+ sd a0, 0(sp)
+ sd a1, 8(sp)
+
+ la a0, __bss_start
+ la a1, __bss_end
+
+ j 2f
+
+1:
+ sd zero, 0(a0)
+ addi a0, a0, 8
+2:
+ bltu a0, a1, 1b
+
+ la a0, ImageBase
+ la a1, _DYNAMIC
+
+ call self_reloc
+
+ ld a0, 0(sp)
+ ld a1, 8(sp)
+ addi sp, sp, 16
+
+ call efi_main
+
+1: j 1b