summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2019-05-11 02:33:35 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2019-05-11 02:33:35 +0000
commit65b504b73b92f2381ae03528d65eb0d0aa5a2c30 (patch)
tree89202c27f5062e44b78bab9a14dd1d816de0891b /sys/arch
parent6070324fbf2dcaf994ee99e84a5f6bfbd4860086 (diff)
Refactor efiboot into 32 and 64 bit copies.
Make 2 separate efiboots, one for 32 bit and one for 64 bit to allow us to remove lots of #ifdef code. Needed to ease the development effort for random-VA linked kernels ok tedu, deraadt
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/amd64/stand/efi32/Makefile9
-rw-r--r--sys/arch/amd64/stand/efi32/Makefile.common78
-rw-r--r--sys/arch/amd64/stand/efi32/Makefile.inc3
-rw-r--r--sys/arch/amd64/stand/efi32/bootia32/Makefile18
-rw-r--r--sys/arch/amd64/stand/efi32/cmd_i386.c162
-rw-r--r--sys/arch/amd64/stand/efi32/conf.c92
-rw-r--r--sys/arch/amd64/stand/efi32/dev_i386.c207
-rw-r--r--sys/arch/amd64/stand/efi32/diskprobe.c301
-rw-r--r--sys/arch/amd64/stand/efi32/efiboot.c1045
-rw-r--r--sys/arch/amd64/stand/efi32/efiboot.h41
-rw-r--r--sys/arch/amd64/stand/efi32/eficall.S64
-rw-r--r--sys/arch/amd64/stand/efi32/eficall.h55
-rw-r--r--sys/arch/amd64/stand/efi32/efidev.c794
-rw-r--r--sys/arch/amd64/stand/efi32/efidev.h38
-rw-r--r--sys/arch/amd64/stand/efi32/efipxe.c306
-rw-r--r--sys/arch/amd64/stand/efi32/efipxe.h21
-rw-r--r--sys/arch/amd64/stand/efi32/efirng.c87
-rw-r--r--sys/arch/amd64/stand/efi32/exec_i386.c220
-rw-r--r--sys/arch/amd64/stand/efi32/heap.h29
-rw-r--r--sys/arch/amd64/stand/efi32/ldscript.amd6465
-rw-r--r--sys/arch/amd64/stand/efi32/ldscript.i38675
-rw-r--r--sys/arch/amd64/stand/efi32/machdep.c95
-rw-r--r--sys/arch/amd64/stand/efi32/memprobe.c173
-rw-r--r--sys/arch/amd64/stand/efi32/run_i386.S115
-rw-r--r--sys/arch/amd64/stand/efi32/run_i386.h21
-rw-r--r--sys/arch/amd64/stand/efi32/self_reloc.c124
-rw-r--r--sys/arch/amd64/stand/efi32/start_amd64.S76
-rw-r--r--sys/arch/amd64/stand/efi32/start_i386.S68
28 files changed, 4382 insertions, 0 deletions
diff --git a/sys/arch/amd64/stand/efi32/Makefile b/sys/arch/amd64/stand/efi32/Makefile
new file mode 100644
index 00000000000..d1e9f399611
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/Makefile
@@ -0,0 +1,9 @@
+# $OpenBSD: Makefile,v 1.1 2019/05/11 02:33:34 mlarkin Exp $
+
+.if ${MACHINE} == "amd64"
+
+SUBDIR= bootx64 bootia32
+
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/sys/arch/amd64/stand/efi32/Makefile.common b/sys/arch/amd64/stand/efi32/Makefile.common
new file mode 100644
index 00000000000..010b5252e49
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/Makefile.common
@@ -0,0 +1,78 @@
+# $OpenBSD: Makefile.common,v 1.1 2019/05/11 02:33:34 mlarkin Exp $
+
+S= ${.CURDIR}/../../../../..
+SADIR= ${.CURDIR}/../..
+EFIDIR= ${S}/stand/efi
+
+OBJCOPY?= objcopy
+OBJDUMP?= objdump
+
+EFI_HEAP_LIMIT= 0xc00000
+
+LDFLAGS+= -nostdlib -T${.CURDIR}/../${LDSCRIPT} -Bsymbolic -shared
+
+COPTS+= -DEFIBOOT -DFWRANDOM -DNEEDS_HEAP_H -I${.CURDIR}/..
+COPTS+= -I${EFIDIR}/include -I${S}/stand/boot
+COPTS+= -ffreestanding -std=gnu99
+COPTS+= -fshort-wchar -fPIC -mno-red-zone
+.if ${SOFTRAID:L} == "yes"
+COPTS+= -DSOFTRAID
+.endif
+COPTS+= -D_STANDALONE -nostdinc -fno-builtin
+
+AFLAGS+= -pipe -fPIC
+
+.PATH: ${.CURDIR}/..
+SRCS+= self_reloc.c
+SRCS+= efiboot.c efidev.c efipxe.c efirng.c
+SRCS+= conf.c dev_i386.c cmd_i386.c diskprobe.c exec_i386.c machdep.c
+SRCS+= memprobe.c
+
+.PATH: ${S}/stand/boot
+SRCS+= boot.c bootarg.c cmd.c vars.c
+
+.PATH: ${S}/lib/libsa
+SRCS+= alloc.c ctime.c exit.c getchar.c memcmp.c memcpy.c memmove.c memset.c printf.c \
+ putchar.c snprintf.c strcmp.c strerror.c strlen.c strncmp.c strncpy.c \
+ strtol.c strtoll.c
+SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fstat.c \
+ lseek.c open.c read.c readdir.c stat.c
+SRCS+= ufs.c cd9660.c
+.if ${SOFTRAID:L} == "yes"
+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
+.endif
+
+.PATH: ${S}/lib/libz
+SRCS+= adler32.c crc32.c inflate.c inftrees.c
+
+.PATH: ${S}/lib/libkern
+SRCS+= divdi3.c moddi3.c qdivrem.c
+SRCS+= strlcpy.c
+
+.PATH: ${SADIR}/libsa
+SRCS+= loadfile.c elf64.c elf32.c
+
+.if ${SOFTRAID:L} == "yes"
+SRCS+= softraid_amd64.c
+.endif
+
+PROG.so= ${PROG:S/.EFI/.so/}
+CLEANFILES+= ${PROG.so} ${PROG.so}.tmp
+
+${PROG}: ${PROG.so}
+ ${OBJCOPY} -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+ -j .rel.dyn -j .rela -j .rela.dyn -j .reloc \
+ --target=${OBJFMT} ${PROG.so} ${.TARGET}
+
+.include <bsd.prog.mk>
+CFLAGS+= -Wno-pointer-sign
+CPPFLAGS+= -DSMALL -DSLOW -DNOBYFOUR -D__INTERNAL_LIBSA_CREAD
+CPPFLAGS+= -DHEAP_LIMIT=${EFI_HEAP_LIMIT} -DHIBERNATE
+
+${PROG.so}: ${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}
diff --git a/sys/arch/amd64/stand/efi32/Makefile.inc b/sys/arch/amd64/stand/efi32/Makefile.inc
new file mode 100644
index 00000000000..8b33a7be00c
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/Makefile.inc
@@ -0,0 +1,3 @@
+# $OpenBSD: Makefile.inc,v 1.1 2019/05/11 02:33:34 mlarkin Exp $
+
+.include "${.CURDIR}/../../Makefile.inc"
diff --git a/sys/arch/amd64/stand/efi32/bootia32/Makefile b/sys/arch/amd64/stand/efi32/bootia32/Makefile
new file mode 100644
index 00000000000..4186e53b1fc
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/bootia32/Makefile
@@ -0,0 +1,18 @@
+# $OpenBSD: Makefile,v 1.1 2019/05/11 02:33:34 mlarkin Exp $
+
+.include <bsd.own.mk>
+
+PROG= BOOTIA32.EFI
+NOMAN= #
+OBJFMT= efi-app-ia32
+SOFTRAID= yes
+SRCS+= start_i386.S random_i386.S
+LDSCRIPT= ldscript.i386
+
+COPTS= -I${EFIDIR}/include/i386
+
+.include "${.CURDIR}/../Makefile.common"
+
+CFLAGS+= -m32
+AFLAGS+= -m32
+LDFLAGS+= -N
diff --git a/sys/arch/amd64/stand/efi32/cmd_i386.c b/sys/arch/amd64/stand/efi32/cmd_i386.c
new file mode 100644
index 00000000000..460c618273c
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/cmd_i386.c
@@ -0,0 +1,162 @@
+/* $OpenBSD: cmd_i386.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 <machine/biosvar.h>
+#include <sys/disklabel.h>
+#include "disk.h"
+#include "biosdev.h"
+#include "libsa.h"
+#include <cmd.h>
+
+#include "efiboot.h"
+#include "efidev.h"
+
+extern const char version[];
+
+int Xboot(void);
+int Xcomaddr(void);
+int Xdiskinfo(void);
+int Xmemory(void);
+int Xregs(void);
+
+/* From gidt.S */
+int bootbuf(void *, int);
+
+const struct cmd_table cmd_machine[] = {
+ { "comaddr", CMDT_CMD, Xcomaddr },
+ { "diskinfo", CMDT_CMD, Xdiskinfo },
+ { "memory", CMDT_CMD, Xmemory },
+ { "video", CMDT_CMD, Xvideo_efi },
+ { "gop", CMDT_CMD, Xgop_efi },
+ { "exit", CMDT_CMD, Xexit_efi },
+ { "poweroff", CMDT_CMD, Xpoweroff_efi },
+#ifdef DEBUG
+ { "regs", CMDT_CMD, Xregs },
+#endif
+ { NULL, 0 }
+};
+
+int
+Xdiskinfo(void)
+{
+ efi_dump_diskinfo();
+ return 0;
+}
+
+#ifdef DEBUG
+int
+Xregs(void)
+{
+ DUMP_REGS;
+ return 0;
+}
+#endif
+
+int
+Xmemory(void)
+{
+ if (cmd.argc >= 2) {
+ int i;
+ /* parse the memory specs */
+
+ for (i = 1; i < cmd.argc; i++) {
+ char *p;
+ long long addr, size;
+
+ p = cmd.argv[i];
+
+ size = strtoll(p + 1, &p, 0);
+ /* Size the size */
+ switch (*p) {
+ case 'G':
+ case 'g':
+ size *= 1024;
+ case 'M':
+ case 'm':
+ size *= 1024;
+ case 'K':
+ case 'k':
+ size *= 1024;
+ p++;
+ }
+
+ /* Handle (possibly non-existent) address part */
+ switch (*p) {
+ case '@':
+ addr = strtoll(p + 1, NULL, 0);
+ break;
+
+ /* Adjust address if we don't need it */
+ default:
+ if (cmd.argv[i][0] == '=')
+ addr = -1;
+ else
+ addr = 0;
+ }
+
+ if (addr == 0 || size == 0) {
+ printf("bad language\n");
+ return 0;
+ } else {
+ switch (cmd.argv[i][0]) {
+ case '-':
+ mem_delete(addr, addr + size);
+ break;
+ case '+':
+ mem_add(addr, addr + size);
+ break;
+ case '=':
+ mem_limit(size);
+ break;
+ default :
+ printf("bad OP\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+ dump_biosmem(NULL);
+
+ return 0;
+}
+
+int
+Xcomaddr(void)
+{
+ extern int com_addr;
+
+ if (cmd.argc >= 2)
+ com_addr = (int)strtol(cmd.argv[1], NULL, 0);
+
+ return 0;
+}
diff --git a/sys/arch/amd64/stand/efi32/conf.c b/sys/arch/amd64/stand/efi32/conf.c
new file mode 100644
index 00000000000..6791259ea38
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/conf.c
@@ -0,0 +1,92 @@
+/* $OpenBSD: conf.c,v 1.1 2019/05/11 02:33:34 mlarkin 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/disklabel.h>
+#include <libsa.h>
+#include <lib/libsa/ufs.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/cd9660.h>
+#include <dev/cons.h>
+
+#include "disk.h"
+#include "efiboot.h"
+#include "efidev.h"
+#include "efipxe.h"
+
+const char version[] = "3.44";
+
+#ifdef EFI_DEBUG
+int debug = 0;
+#endif
+
+void (*sa_cleanup)(void) = NULL;
+
+
+void (*i386_probe1[])(void) = {
+ cninit, efi_memprobe
+};
+void (*i386_probe2[])(void) = {
+ efi_pxeprobe, efi_diskprobe, diskprobe
+};
+
+struct i386_boot_probes probe_list[] = {
+ { "probing", i386_probe1, nitems(i386_probe1) },
+ { "disk", i386_probe2, nitems(i386_probe2) }
+};
+int nibprobes = nitems(probe_list);
+
+
+struct fs_ops file_system[] = {
+ { tftp_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 },
+ { cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
+ cd9660_stat, cd9660_readdir },
+#ifdef notdef
+ { fat_open, fat_close, fat_read, fat_write, fat_seek,
+ fat_stat, fat_readdir },
+ { nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek,
+ nfs_stat, nfs_readdir },
+#endif
+};
+int nfsys = nitems(file_system);
+
+struct devsw devsw[] = {
+ { "TFTP", tftpstrategy, tftpopen, tftpclose, tftpioctl },
+ { "EFI", efistrategy, efiopen, eficlose, efiioctl },
+};
+int ndevs = nitems(devsw);
+
+struct consdev constab[] = {
+ { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc },
+ { efi_com_probe, efi_com_init, efi_com_getc, efi_com_putc },
+ { NULL }
+};
+struct consdev *cn_tab = constab;
diff --git a/sys/arch/amd64/stand/efi32/dev_i386.c b/sys/arch/amd64/stand/efi32/dev_i386.c
new file mode 100644
index 00000000000..33ce6bf67d8
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/dev_i386.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: dev_i386.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 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 AUTHOR OR HIS RELATIVES 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 MIND, 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 <dev/cons.h>
+
+#include "libsa.h"
+#include "biosdev.h"
+#include "disk.h"
+
+#ifdef SOFTRAID
+#include <dev/biovar.h>
+#include <dev/softraidvar.h>
+#include <lib/libsa/softraid.h>
+#include "softraid_amd64.h"
+#endif
+
+extern int debug;
+
+/* XXX use slot for 'rd' for 'hd' pseudo-device */
+const char bdevs[][4] = {
+ "wd", "", "fd", "", "sd", "st", "cd", "",
+ "", "", "", "", "", "", "", "", "", "hd", ""
+};
+const int nbdevs = nitems(bdevs);
+
+const char cdevs[][4] = {
+ "cn", "", "", "", "", "", "", "",
+ "com", "", "", "", "pc"
+};
+const int ncdevs = nitems(cdevs);
+
+/* pass dev_t to the open routines */
+int
+devopen(struct open_file *f, const char *fname, char **file)
+{
+ struct devsw *dp = devsw;
+ register int i, rc = 1;
+
+ *file = (char *)fname;
+
+#ifdef DEBUG
+ if (debug)
+ printf("devopen:");
+#endif
+
+ for (i = 0; i < ndevs && rc != 0; dp++, i++) {
+#ifdef DEBUG
+ if (debug)
+ printf(" %s: ", dp->dv_name);
+#endif
+ if ((rc = (*dp->dv_open)(f, file)) == 0) {
+ 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.
+ */
+ extern char *bootmac;
+ bootmac = NULL;
+ }
+ return 0;
+ }
+#ifdef DEBUG
+ else if (debug)
+ printf("%d", rc);
+#endif
+
+ }
+#ifdef DEBUG
+ if (debug)
+ putchar('\n');
+#endif
+
+ if ((f->f_flags & F_NODEV) == 0)
+ f->f_dev = dp;
+
+ return rc;
+}
+
+void
+devboot(dev_t bootdev, char *p)
+{
+#ifdef SOFTRAID
+ struct sr_boot_volume *bv;
+ struct sr_boot_chunk *bc;
+ struct diskinfo *dip = NULL;
+#endif
+ int sr_boot_vol = -1;
+ int part_type = FS_UNUSED;
+
+ if (!bootdev) {
+ *p++ = 't';
+ *p++ = 'f';
+ *p++ = 't';
+ *p++ = 'p';
+ *p = '\0';
+ return;
+ }
+
+#ifdef SOFTRAID
+ /*
+ * Determine the partition type for the 'a' partition of the
+ * boot device.
+ */
+ TAILQ_FOREACH(dip, &disklist, list)
+ if (dip->bios_info.bios_number == bootdev &&
+ (dip->bios_info.flags & BDI_BADLABEL) == 0)
+ part_type = 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) {
+ if (bv->sbv_flags & BIOC_SCBOOTABLE)
+ SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
+ if (bc->sbc_disk == bootdev)
+ sr_boot_vol = bv->sbv_unit;
+ if (sr_boot_vol != -1)
+ break;
+ }
+#endif
+
+ if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
+ *p++ = 's';
+ *p++ = 'r';
+ *p++ = '0' + sr_boot_vol;
+ } else if (bootdev & 0x100) {
+ *p++ = 'c';
+ *p++ = 'd';
+ *p++ = '0';
+ } else {
+ if (bootdev & 0x80)
+ *p++ = 'h';
+ else
+ *p++ = 'f';
+ *p++ = 'd';
+ *p++ = '0' + (bootdev & 0x7f);
+ }
+ *p++ = 'a';
+ *p = '\0';
+}
+
+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;
+}
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ if (major(dev) == 8) /* comN */
+ return comspeed(dev, sp);
+
+ /* pc0 and anything else */
+ return 9600;
+}
diff --git a/sys/arch/amd64/stand/efi32/diskprobe.c b/sys/arch/amd64/stand/efi32/diskprobe.c
new file mode 100644
index 00000000000..7f5c42cd9a1
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/diskprobe.c
@@ -0,0 +1,301 @@
+/* $OpenBSD: diskprobe.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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.
+ *
+ */
+
+/* We want the disk type names from disklabel.h */
+#undef DKTYPENAMES
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/reboot.h>
+#include <sys/disklabel.h>
+#include <sys/hibernate.h>
+
+#include <lib/libz/zlib.h>
+#include <machine/biosvar.h>
+#include <stand/boot/bootarg.h>
+
+#include "disk.h"
+#include "biosdev.h"
+#include "libsa.h"
+
+#ifdef SOFTRAID
+#include "softraid_amd64.h"
+#endif
+#include "efidev.h"
+
+#define MAX_CKSUMLEN MAXBSIZE / DEV_BSIZE /* Max # of blks to cksum */
+
+/* Local Prototypes */
+static int disksum(int);
+
+int bootdev_has_hibernate(void); /* export for loadfile() */
+
+/* List of disk devices we found/probed */
+struct disklist_lh disklist;
+
+/* Pointer to boot device */
+struct diskinfo *bootdev_dip;
+
+extern int debug;
+extern int bios_bootdev;
+extern int bios_cddev;
+
+static void
+efi_hardprobe(void)
+{
+ int n;
+ struct diskinfo *dip, *dipt;
+ u_int bsdunit, type = 0;
+ u_int scsi= 0, ide = 0, atapi = 0;
+ extern struct disklist_lh
+ efi_disklist;
+
+ n = 0;
+ TAILQ_FOREACH_SAFE(dip, &efi_disklist, list, dipt) {
+ TAILQ_REMOVE(&efi_disklist, dip, list);
+ n = scsi + ide;
+
+ /* Try to find the label, to figure out device type */
+ if ((efi_getdisklabel(dip->efi_info, &dip->disklabel))) {
+ type = 0;
+ printf(" hd%d*", n);
+ bsdunit = ide++;
+ } else {
+ /* Best guess */
+ switch (dip->disklabel.d_type) {
+ case DTYPE_SCSI:
+ type = 4;
+ bsdunit = scsi++;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ break;
+
+ case DTYPE_ESDI:
+ case DTYPE_ST506:
+ type = 0;
+ bsdunit = ide++;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ break;
+
+ case DTYPE_ATAPI:
+ type = 6;
+ n = atapi;
+ bsdunit = atapi++;
+ dip->bios_info.flags |= BDI_GOODLABEL
+ | BDI_EL_TORITO;
+ break;
+
+ default:
+ dip->bios_info.flags |= BDI_BADLABEL;
+ type = 0; /* XXX Suggest IDE */
+ bsdunit = ide++;
+ }
+ printf(" %cd%d", (type == 6)? 'c' : 'h', n);
+ }
+ if (type != 6)
+ dip->bios_info.bios_number = 0x80 | n;
+ else
+ dip->bios_info.bios_number = 0xe0 | n;
+
+ dip->bios_info.checksum = 0; /* just in case */
+ /* Fill out best we can */
+ dip->bsddev = dip->bios_info.bsd_dev =
+ MAKEBOOTDEV(type, 0, 0, bsdunit, RAW_PART);
+ check_hibernate(dip);
+
+ /* Add to queue of disks */
+ TAILQ_INSERT_TAIL(&disklist, dip, list);
+ n++;
+ }
+}
+
+/* Probe for all BIOS supported disks */
+u_int32_t bios_cksumlen;
+void
+diskprobe(void)
+{
+ struct diskinfo *dip;
+ int i;
+
+ /* These get passed to kernel */
+ bios_diskinfo_t *bios_diskinfo;
+
+ /* Init stuff */
+ TAILQ_INIT(&disklist);
+
+ efi_hardprobe();
+
+#ifdef SOFTRAID
+ srprobe();
+#endif
+
+ /* Checksumming of hard disks */
+ for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; )
+ ;
+ bios_cksumlen = i;
+
+ /* Get space for passing bios_diskinfo stuff to kernel */
+ for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
+ dip = TAILQ_NEXT(dip, list))
+ i++;
+ bios_diskinfo = alloc(++i * sizeof(bios_diskinfo_t));
+
+ /* Copy out the bios_diskinfo stuff */
+ for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
+ dip = TAILQ_NEXT(dip, list))
+ bios_diskinfo[i++] = dip->bios_info;
+
+ bios_diskinfo[i++].bios_number = -1;
+ /* Register for kernel use */
+ addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
+ addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t),
+ bios_diskinfo);
+}
+
+/* Find info on given BIOS disk */
+struct diskinfo *
+dklookup(int dev)
+{
+ struct diskinfo *dip;
+
+ for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
+ if (dip->bios_info.bios_number == dev)
+ return dip;
+
+ return NULL;
+}
+
+void
+dump_diskinfo(void)
+{
+ struct diskinfo *dip;
+
+ printf("Disk\tBIOS#\tType\tCyls\tHeads\tSecs\tFlags\tChecksum\n");
+ for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
+ bios_diskinfo_t *bdi = &dip->bios_info;
+ int d = bdi->bios_number;
+ int u = d & 0x7f;
+ char c;
+
+ if (bdi->flags & BDI_EL_TORITO) {
+ c = 'c';
+ u = 0;
+ } else {
+ c = (d & 0x80) ? 'h' : 'f';
+ }
+
+ printf("%cd%d\t0x%x\t%s\t%d\t%d\t%d\t0x%x\t0x%x\n",
+ c, u, d,
+ (bdi->flags & BDI_BADLABEL)?"*none*":"label",
+ bdi->bios_cylinders, bdi->bios_heads, bdi->bios_sectors,
+ bdi->flags, bdi->checksum);
+ }
+}
+
+/* Find BIOS portion on given BIOS disk
+ * XXX - Use dklookup() instead.
+ */
+bios_diskinfo_t *
+bios_dklookup(int dev)
+{
+ struct diskinfo *dip;
+
+ dip = dklookup(dev);
+ if (dip)
+ return &dip->bios_info;
+
+ return NULL;
+}
+
+/*
+ * Checksum one more block on all harddrives
+ *
+ * Use the adler32() function from libz,
+ * as it is quick, small, and available.
+ */
+int
+disksum(int blk)
+{
+ struct diskinfo *dip, *dip2;
+ int st, reprobe = 0;
+ char buf[DEV_BSIZE];
+
+ for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
+ bios_diskinfo_t *bdi = &dip->bios_info;
+
+ /* Skip this disk if it is not a HD or has had an I/O error */
+ if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
+ continue;
+
+ /* Adler32 checksum */
+ st = dip->diskio(F_READ, dip, blk, 1, buf);
+ if (st) {
+ bdi->flags |= BDI_INVALID;
+ continue;
+ }
+ bdi->checksum = adler32(bdi->checksum, buf, DEV_BSIZE);
+
+ for (dip2 = TAILQ_FIRST(&disklist); dip2 != dip;
+ dip2 = TAILQ_NEXT(dip2, list)) {
+ bios_diskinfo_t *bd = &dip2->bios_info;
+ if ((bd->bios_number & 0x80) &&
+ !(bd->flags & BDI_INVALID) &&
+ bdi->checksum == bd->checksum)
+ reprobe = 1;
+ }
+ }
+
+ return reprobe;
+}
+
+int
+bootdev_has_hibernate(void)
+{
+ return ((bootdev_dip->bios_info.flags & BDI_HIBVALID)? 1 : 0);
+}
+
+void
+check_hibernate(struct diskinfo *dip)
+{
+ daddr_t sec;
+ int error;
+ union hibernate_info hib;
+
+ /* read hibernate */
+ if (dip->disklabel.d_partitions[1].p_fstype != FS_SWAP ||
+ DL_GETPSIZE(&dip->disklabel.d_partitions[1]) == 0)
+ return;
+
+ sec = DL_GETPOFFSET(&dip->disklabel.d_partitions[1]) +
+ DL_GETPSIZE(&dip->disklabel.d_partitions[1]) -
+ (sizeof(union hibernate_info) / DEV_BSIZE);
+
+ error = dip->strategy(dip, F_READ, (daddr32_t)sec, sizeof hib, &hib, NULL);
+ if (error == 0 && hib.magic == HIBERNATE_MAGIC)
+ dip->bios_info.flags |= BDI_HIBVALID; /* Hibernate present */
+}
diff --git a/sys/arch/amd64/stand/efi32/efiboot.c b/sys/arch/amd64/stand/efi32/efiboot.c
new file mode 100644
index 00000000000..72b0e45ac20
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efiboot.c
@@ -0,0 +1,1045 @@
+/* $OpenBSD: efiboot.c,v 1.1 2019/05/11 02:33:34 mlarkin 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 <sys/param.h>
+#include <sys/queue.h>
+#include <dev/cons.h>
+#include <dev/isa/isareg.h>
+#include <dev/ic/comreg.h>
+#include <sys/disklabel.h>
+#include <cmd.h>
+#include <stand/boot/bootarg.h>
+#include <machine/pio.h>
+
+#include "libsa.h"
+#include "disk.h"
+
+#include <efi.h>
+#include <efiapi.h>
+#include <efiprot.h>
+#include <eficonsctl.h>
+
+#include "efidev.h"
+#include "efiboot.h"
+#include "eficall.h"
+#include "run_i386.h"
+
+#define KERN_LOADSPACE_SIZE (32 * 1024 * 1024)
+
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RS;
+EFI_HANDLE IH;
+EFI_DEVICE_PATH *efi_bootdp = NULL;
+EFI_PHYSICAL_ADDRESS heap;
+EFI_LOADED_IMAGE *loadedImage;
+UINTN heapsiz = 1 * 1024 * 1024;
+UINTN mmap_key;
+static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+u_long efi_loadaddr;
+
+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_video_init(void);
+static void efi_video_reset(void);
+static EFI_STATUS
+ efi_gop_setmode(int mode);
+EFI_STATUS efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE *);
+
+void (*run_i386)(u_long, u_long, int, int, int, int, int, int, int, int)
+ __attribute__((noreturn));
+
+extern int bios_bootdev;
+
+EFI_STATUS
+efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
+{
+ extern char *progname;
+ EFI_LOADED_IMAGE *imgp;
+ EFI_DEVICE_PATH *dp0 = NULL, *dp;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS stack;
+
+ 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);
+
+ efi_video_init();
+ efi_heap_init();
+
+ status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid,
+ (void **)&imgp);
+ if (status == EFI_SUCCESS)
+ status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle,
+ &devp_guid, (void **)&dp0);
+ if (status == EFI_SUCCESS) {
+ for (dp = dp0; !IsDevicePathEnd(dp);
+ dp = NextDevicePathNode(dp)) {
+ if (DevicePathType(dp) == MEDIA_DEVICE_PATH &&
+ (DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP ||
+ DevicePathSubType(dp) == MEDIA_CDROM_DP)) {
+ bios_bootdev =
+ (DevicePathSubType(dp) == MEDIA_CDROM_DP)
+ ? 0x1e0 : 0x80;
+ efi_bootdp = dp0;
+ break;
+ } else if (DevicePathType(dp) == MESSAGING_DEVICE_PATH&&
+ DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
+ bios_bootdev = 0x0;
+ efi_bootdp = dp0;
+ break;
+ }
+ }
+ }
+
+#ifdef __amd64__
+ /* allocate run_i386_start() on heap */
+ if ((run_i386 = alloc(run_i386_size)) == NULL)
+ panic("alloc() failed");
+ memcpy(run_i386, run_i386_start, run_i386_size);
+#endif
+
+ /* can't use sa_cleanup since printf is used after sa_cleanup() */
+ /* sa_cleanup = efi_cleanup; */
+
+#ifdef __amd64__
+ progname = "BOOTX64";
+#else
+ progname = "BOOTIA32";
+#endif
+
+ /*
+ * Move the stack before calling boot(). UEFI on some machines
+ * locate the stack on our kernel load address.
+ */
+ stack = heap + heapsiz;
+#if defined(__amd64__)
+ asm("movq %0, %%rsp;"
+ "mov %1, %%edi;"
+ "call boot;"
+ :: "r"(stack - 32), "r"(bios_bootdev));
+#else
+ asm("movl %0, %%esp;"
+ "movl %1, (%%esp);"
+ "call boot;"
+ :: "r"(stack - 32), "r"(bios_bootdev));
+#endif
+ /* must not reach here */
+ return (EFI_SUCCESS);
+}
+
+void
+efi_cleanup(void)
+{
+ int retry;
+ EFI_STATUS status;
+
+ /* retry once in case of failure */
+ for (retry = 1; retry >= 0; retry--) {
+ efi_memprobe_internal(); /* sync the current map */
+ status = EFI_CALL(BS->ExitBootServices, IH, mmap_key);
+ if (status == EFI_SUCCESS)
+ break;
+ if (retry == 0)
+ panic("ExitBootServices failed (%d)", status);
+ }
+}
+
+/***********************************************************************
+ * Disk
+ ***********************************************************************/
+struct disklist_lh efi_disklist;
+
+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(&efi_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))
+ panic("BS->LocateHandle() returns %d", status);
+
+ 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(&efi_disklist, di, list);
+ bootdev = 1;
+ continue;
+ }
+next:
+ TAILQ_INSERT_TAIL(&efi_disklist, di, list);
+ }
+
+ free(handles, sz);
+}
+
+/*
+ * 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 (-1);
+}
+
+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);
+}
+
+/***********************************************************************
+ * Memory
+ ***********************************************************************/
+bios_memmap_t bios_memmap[64];
+
+static void
+efi_heap_init(void)
+{
+ EFI_STATUS status;
+
+ heap = HEAP_LIMIT;
+ status = EFI_CALL(BS->AllocatePages, AllocateMaxAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(heapsiz), &heap);
+ if (status != EFI_SUCCESS)
+ panic("BS->AllocatePages()");
+}
+
+void
+efi_memprobe(void)
+{
+ u_int n = 0;
+ bios_memmap_t *bm;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS
+ addr = 0x10000000ULL; /* Below 256MB */
+
+ status = EFI_CALL(BS->AllocatePages, AllocateMaxAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(KERN_LOADSPACE_SIZE), &addr);
+ if (status != EFI_SUCCESS)
+ panic("BS->AllocatePages()");
+ efi_loadaddr = addr;
+
+ printf(" mem[");
+ efi_memprobe_internal();
+ for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) {
+ if (bm->type == BIOS_MAP_FREE && bm->size > 12 * 1024) {
+ if (n++ != 0)
+ printf(" ");
+ if (bm->size > 1024 * 1024)
+ printf("%uM", bm->size / 1024 / 1024);
+ else
+ printf("%uK", bm->size / 1024);
+ }
+ }
+ printf("]");
+}
+
+static void
+efi_memprobe_internal(void)
+{
+ EFI_STATUS status;
+ UINTN mapkey, mmsiz, siz;
+ UINT32 mmver;
+ EFI_MEMORY_DESCRIPTOR *mm0, *mm;
+ int i, n;
+ bios_memmap_t *bm, bm0;
+
+ cnvmem = extmem = 0;
+ bios_memmap[0].type = BIOS_MAP_END;
+
+ 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");
+ mm0 = alloc(siz);
+ status = EFI_CALL(BS->GetMemoryMap, &siz, mm0, &mapkey, &mmsiz, &mmver);
+ if (status != EFI_SUCCESS)
+ panic("cannot get the memory map");
+ n = siz / mmsiz;
+ mmap_key = mapkey;
+
+ for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)){
+ bm0.type = BIOS_MAP_END;
+ bm0.addr = mm->PhysicalStart;
+ bm0.size = mm->NumberOfPages * EFI_PAGE_SIZE;
+ if (mm->Type == EfiReservedMemoryType ||
+ mm->Type == EfiUnusableMemory ||
+ mm->Type == EfiRuntimeServicesCode ||
+ mm->Type == EfiRuntimeServicesData)
+ bm0.type = BIOS_MAP_RES;
+ else if (mm->Type == EfiLoaderCode ||
+ mm->Type == EfiLoaderData ||
+ mm->Type == EfiBootServicesCode ||
+ mm->Type == EfiBootServicesData ||
+ mm->Type == EfiConventionalMemory)
+ bm0.type = BIOS_MAP_FREE;
+ else if (mm->Type == EfiACPIReclaimMemory)
+ bm0.type = BIOS_MAP_ACPI;
+ else if (mm->Type == EfiACPIMemoryNVS)
+ bm0.type = BIOS_MAP_NVS;
+ else
+ /*
+ * XXX Is there anything to do for EfiMemoryMappedIO
+ * XXX EfiMemoryMappedIOPortSpace EfiPalCode?
+ */
+ bm0.type = BIOS_MAP_RES;
+
+ for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) {
+ if (bm->type != bm0.type)
+ continue;
+ if (bm->addr <= bm0.addr &&
+ bm0.addr <= bm->addr + bm->size) {
+ bm->size = bm0.addr + bm0.size - bm->addr;
+ break;
+ } else if (bm0.addr <= bm->addr &&
+ bm->addr <= bm0.addr + bm0.size) {
+ bm->size = bm->addr + bm->size - bm0.addr;
+ bm->addr = bm0.addr;
+ break;
+ }
+ }
+ if (bm->type == BIOS_MAP_END) {
+ *bm = bm0;
+ (++bm)->type = BIOS_MAP_END;
+ }
+ }
+ for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) {
+ if (bm->addr < IOM_BEGIN) /* Below memory hole */
+ cnvmem =
+ max(cnvmem, (bm->addr + bm->size) / 1024);
+ if (bm->addr >= IOM_END /* Above the memory hole */ &&
+ bm->addr / 1024 == extmem + 1024)
+ extmem += bm->size / 1024;
+ }
+ free(mm0, siz);
+}
+
+/***********************************************************************
+ * Console
+ ***********************************************************************/
+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
+static SIMPLE_INPUT_INTERFACE *conin;
+static EFI_GUID con_guid
+ = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+static EFI_GUID gop_guid
+ = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+static EFI_GUID serio_guid
+ = SERIAL_IO_PROTOCOL;
+struct efi_video {
+ int cols;
+ int rows;
+} efi_video[32];
+
+static void
+efi_video_init(void)
+{
+ EFI_CONSOLE_CONTROL_PROTOCOL *conctrl = NULL;
+ int i, mode80x25, mode100x31;
+ UINTN cols, rows;
+ EFI_STATUS status;
+
+ conout = ST->ConOut;
+ status = EFI_CALL(BS->LocateProtocol, &con_guid, NULL,
+ (void **)&conctrl);
+ if (status == EFI_SUCCESS)
+ (void)EFI_CALL(conctrl->SetMode, conctrl,
+ EfiConsoleControlScreenText);
+ mode80x25 = -1;
+ mode100x31 = -1;
+ for (i = 0; i < conout->Mode->MaxMode; i++) {
+ status = EFI_CALL(conout->QueryMode, conout, i, &cols, &rows);
+ if (EFI_ERROR(status))
+ continue;
+ if (mode80x25 < 0 && cols == 80 && rows == 25)
+ mode80x25 = i;
+ if (mode100x31 < 0 && cols == 100 && rows == 31)
+ mode100x31 = i;
+ if (i < nitems(efi_video)) {
+ efi_video[i].cols = cols;
+ efi_video[i].rows = rows;
+ }
+ }
+ if (mode100x31 >= 0)
+ EFI_CALL(conout->SetMode, conout, mode100x31);
+ else if (mode80x25 >= 0)
+ EFI_CALL(conout->SetMode, conout, mode80x25);
+ conin = ST->ConIn;
+ efi_video_reset();
+}
+
+static void
+efi_video_reset(void)
+{
+ EFI_CALL(conout->EnableCursor, conout, TRUE);
+ EFI_CALL(conout->SetAttribute, conout,
+ EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK));
+ EFI_CALL(conout->ClearScreen, conout);
+}
+
+void
+efi_cons_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_MIDPRI;
+ cn->cn_dev = makedev(12, 0);
+ printf(" pc%d", minor(cn->cn_dev));
+}
+
+void
+efi_cons_init(struct consdev *cp)
+{
+}
+
+int
+efi_cons_getc(dev_t dev)
+{
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+ UINTN dummy;
+ static int lastchar = 0;
+
+ if (lastchar) {
+ int r = lastchar;
+ if ((dev & 0x80) == 0)
+ lastchar = 0;
+ return (r);
+ }
+
+ status = EFI_CALL(conin->ReadKeyStroke, conin, &key);
+ while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
+ if (dev & 0x80)
+ return (0);
+ EFI_CALL(BS->WaitForEvent, 1, &conin->WaitForKey, &dummy);
+ status = EFI_CALL(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;
+
+ EFI_CALL(conout->OutputString, conout, buf);
+}
+
+int
+efi_cons_getshifts(dev_t dev)
+{
+ /* XXX */
+ return (0);
+}
+
+int com_addr = -1;
+int com_speed = -1;
+
+static SERIAL_IO_INTERFACE *serios[4];
+const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+/* call with sp == 0 to query the current speed */
+int
+pio_comspeed(dev_t dev, int sp)
+{
+ int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
+ int i, newsp;
+ int err;
+
+ if (sp <= 0)
+ return com_speed;
+ /* valid baud rate? */
+ if (115200 < sp || sp < 75)
+ return -1;
+
+ /*
+ * Accepted speeds:
+ * 75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and
+ * 14400 28800 57600 115200
+ */
+ for (i = sp; i != 75 && i != 14400; i >>= 1)
+ if (i & 1)
+ return -1;
+
+/* ripped screaming from dev/ic/com.c */
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+ newsp = divrnd((COM_FREQ / 16), sp);
+ if (newsp <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+#undef divrnd
+
+ if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev &&
+ com_speed != sp) {
+ printf("com%d: changing speed to %d baud in 5 seconds, "
+ "change your terminal to match!\n\a",
+ minor(dev), sp);
+ sleep(5);
+ }
+
+ outb(port + com_cfcr, LCR_DLAB);
+ outb(port + com_dlbl, newsp);
+ outb(port + com_dlbh, newsp>>8);
+ outb(port + com_cfcr, LCR_8BITS);
+ if (com_speed != -1)
+ printf("\ncom%d: %d baud\n", minor(dev), sp);
+
+ newsp = com_speed;
+ com_speed = sp;
+ return newsp;
+}
+
+int
+pio_com_getc(dev_t dev)
+{
+ int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr;
+
+ if (dev & 0x80)
+ return (inb(port + com_lsr) & LSR_RXRDY);
+
+ while ((inb(port + com_lsr) & LSR_RXRDY) == 0)
+ ;
+
+ return (inb(port + com_data) & 0xff);
+}
+
+void
+pio_com_putc(dev_t dev, int c)
+{
+ int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
+
+ while ((inb(port + com_lsr) & LSR_TXRDY) == 0)
+ ;
+
+ outb(port + com_data, c);
+}
+
+void
+efi_com_probe(struct consdev *cn)
+{
+ EFI_HANDLE *handles = NULL;
+ SERIAL_IO_INTERFACE *serio;
+ EFI_STATUS status;
+ EFI_DEVICE_PATH *dp, *dp0;
+ EFI_DEV_PATH_PTR dpp;
+ UINTN sz;
+ int i, uid = -1;
+
+ cn->cn_pri = CN_LOWPRI;
+ cn->cn_dev = makedev(8, 0);
+
+ sz = 0;
+ status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid, 0, &sz, 0);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ handles = alloc(sz);
+ status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid,
+ 0, &sz, handles);
+ }
+ if (handles == NULL || EFI_ERROR(status)) {
+ free(handles, sz);
+ return;
+ }
+
+ for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+ /*
+ * Identify port number of the handle. This assumes ACPI
+ * UID 0-3 map to legacy COM[1-4] and they use the legacy
+ * port address.
+ */
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
+ (void **)&dp0);
+ if (EFI_ERROR(status))
+ continue;
+ uid = -1;
+ for (dp = dp0; !IsDevicePathEnd(dp);
+ dp = NextDevicePathNode(dp)) {
+ dpp = (EFI_DEV_PATH_PTR)dp;
+ if (DevicePathType(dp) == ACPI_DEVICE_PATH &&
+ DevicePathSubType(dp) == ACPI_DP)
+ if (dpp.Acpi->HID == EFI_PNP_ID(0x0501)) {
+ uid = dpp.Acpi->UID;
+ break;
+ }
+ }
+ if (uid < 0 || nitems(serios) <= uid)
+ continue;
+
+ /* Prepare SERIAL_IO_INTERFACE */
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &serio_guid,
+ (void **)&serio);
+ if (EFI_ERROR(status))
+ continue;
+ serios[uid] = serio;
+ }
+ free(handles, sz);
+
+ for (i = 0; i < nitems(serios); i++) {
+ if (serios[i] != NULL)
+ printf(" com%d", i);
+ }
+}
+
+int
+efi_valid_com(dev_t dev)
+{
+ return (minor(dev) < nitems(serios) && serios[minor(dev)] != NULL);
+}
+
+int
+comspeed(dev_t dev, int sp)
+{
+ EFI_STATUS status;
+ SERIAL_IO_INTERFACE *serio = serios[minor(dev)];
+ int newsp;
+
+ if (sp <= 0)
+ return com_speed;
+
+ if (!efi_valid_com(dev))
+ return pio_comspeed(dev, sp);
+
+ if (serio->Mode->BaudRate != sp) {
+ status = EFI_CALL(serio->SetAttributes, serio,
+ sp, serio->Mode->ReceiveFifoDepth,
+ serio->Mode->Timeout, serio->Mode->Parity,
+ serio->Mode->DataBits, serio->Mode->StopBits);
+ if (EFI_ERROR(status)) {
+ printf("com%d: SetAttribute() failed with status=%d\n",
+ minor(dev), status);
+ return (-1);
+ }
+ if (com_speed != -1)
+ printf("\ncom%d: %d baud\n", minor(dev), sp);
+ }
+
+ /* same as comspeed() in libsa/bioscons.c */
+ newsp = com_speed;
+ com_speed = sp;
+
+ return (newsp);
+}
+
+void
+efi_com_init(struct consdev *cn)
+{
+ if (!efi_valid_com(cn->cn_dev))
+ /* This actually happens if the machine has another serial. */
+ return;
+
+ if (com_speed == -1)
+ comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */
+}
+
+int
+efi_com_getc(dev_t dev)
+{
+ EFI_STATUS status;
+ SERIAL_IO_INTERFACE *serio;
+ UINTN sz;
+ u_char buf;
+ static u_char lastchar = 0;
+
+ if (!efi_valid_com(dev & 0x7f))
+ return pio_com_getc(dev);
+ serio = serios[minor(dev & 0x7f)];
+
+ if (lastchar != 0) {
+ int r = lastchar;
+ if ((dev & 0x80) == 0)
+ lastchar = 0;
+ return (r);
+ }
+
+ for (;;) {
+ sz = 1;
+ status = EFI_CALL(serio->Read, serio, &sz, &buf);
+ if (status == EFI_SUCCESS && sz > 0)
+ break;
+ if (status != EFI_TIMEOUT && EFI_ERROR(status))
+ panic("Error reading from serial status=%d", status);
+ if (dev & 0x80)
+ return (0);
+ }
+
+ if (dev & 0x80)
+ lastchar = buf;
+
+ return (buf);
+}
+
+void
+efi_com_putc(dev_t dev, int c)
+{
+ SERIAL_IO_INTERFACE *serio;
+ UINTN sz = 1;
+ u_char buf;
+
+ if (!efi_valid_com(dev)) {
+ pio_com_putc(dev, c);
+ return;
+ }
+ serio = serios[minor(dev)];
+ buf = c;
+ EFI_CALL(serio->Write, serio, &sz, &buf);
+}
+
+/***********************************************************************
+ * Miscellaneous
+ ***********************************************************************/
+/*
+ * ACPI GUID is confusing in UEFI spec.
+ * {EFI_,}_ACPI_20_TABLE_GUID or EFI_ACPI_TABLE_GUID means
+ * ACPI 2.0 or above.
+ */
+static EFI_GUID acpi_guid = ACPI_20_TABLE_GUID;
+static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID;
+static EFI_GRAPHICS_OUTPUT *gop;
+static int gopmode = -1;
+
+#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
+
+static EFI_STATUS
+efi_gop_setmode(int mode)
+{
+ EFI_STATUS status;
+
+ status = EFI_CALL(gop->SetMode, gop, mode);
+ if (EFI_ERROR(status) || gop->Mode->Mode != mode)
+ printf("GOP SetMode() failed (%d)\n", status);
+
+ return (status);
+}
+
+void
+efi_makebootargs(void)
+{
+ int i;
+ EFI_STATUS status;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
+ *gopi;
+ bios_efiinfo_t ei;
+ int curmode;
+ UINTN sz, gopsiz, bestsiz = 0;
+
+ memset(&ei, 0, sizeof(ei));
+ /*
+ * ACPI, BIOS configuration table
+ */
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ if (efi_guidcmp(&acpi_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ ei.config_acpi = (intptr_t)
+ ST->ConfigurationTable[i].VendorTable;
+ else if (efi_guidcmp(&smbios_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ ei.config_smbios = (intptr_t)
+ ST->ConfigurationTable[i].VendorTable;
+ }
+
+ /*
+ * Frame buffer
+ */
+ status = EFI_CALL(BS->LocateProtocol, &gop_guid, NULL,
+ (void **)&gop);
+ if (!EFI_ERROR(status)) {
+ if (gopmode < 0) {
+ for (i = 0; i < gop->Mode->MaxMode; i++) {
+ status = EFI_CALL(gop->QueryMode, gop,
+ i, &sz, &gopi);
+ if (EFI_ERROR(status))
+ continue;
+ gopsiz = gopi->HorizontalResolution *
+ gopi->VerticalResolution;
+ if (gopsiz > bestsiz) {
+ gopmode = i;
+ bestsiz = gopsiz;
+ }
+ }
+ }
+ if (gopmode >= 0 && gopmode != gop->Mode->Mode) {
+ curmode = gop->Mode->Mode;
+ if (efi_gop_setmode(gopmode) != EFI_SUCCESS)
+ (void)efi_gop_setmode(curmode);
+ }
+
+ gopi = gop->Mode->Info;
+ switch (gopi->PixelFormat) {
+ case PixelBlueGreenRedReserved8BitPerColor:
+ ei.fb_red_mask = 0x00ff0000;
+ ei.fb_green_mask = 0x0000ff00;
+ ei.fb_blue_mask = 0x000000ff;
+ ei.fb_reserved_mask = 0xff000000;
+ break;
+ case PixelRedGreenBlueReserved8BitPerColor:
+ ei.fb_red_mask = 0x000000ff;
+ ei.fb_green_mask = 0x0000ff00;
+ ei.fb_blue_mask = 0x00ff0000;
+ ei.fb_reserved_mask = 0xff000000;
+ break;
+ case PixelBitMask:
+ ei.fb_red_mask = gopi->PixelInformation.RedMask;
+ ei.fb_green_mask = gopi->PixelInformation.GreenMask;
+ ei.fb_blue_mask = gopi->PixelInformation.BlueMask;
+ ei.fb_reserved_mask =
+ gopi->PixelInformation.ReservedMask;
+ break;
+ default:
+ break;
+ }
+ ei.fb_addr = gop->Mode->FrameBufferBase;
+ ei.fb_size = gop->Mode->FrameBufferSize;
+ ei.fb_height = gopi->VerticalResolution;
+ ei.fb_width = gopi->HorizontalResolution;
+ ei.fb_pixpsl = gopi->PixelsPerScanLine;
+ }
+
+ addbootarg(BOOTARG_EFIINFO, sizeof(ei), &ei);
+}
+
+void
+_rtt(void)
+{
+#ifdef EFI_DEBUG
+ printf("Hit any key to reboot\n");
+ efi_cons_getc(0);
+#endif
+ EFI_CALL(RS->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
+ for (;;)
+ continue;
+}
+
+time_t
+getsecs(void)
+{
+ EFI_TIME t;
+ time_t r = 0;
+ int y = 0;
+ const int daytab[][14] = {
+ { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
+ { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ };
+#define isleap(_y) (((_y) % 4) == 0 && (((_y) % 100) != 0 || ((_y) % 400) == 0))
+
+ EFI_CALL(ST->RuntimeServices->GetTime, &t, NULL);
+
+ /* Calc days from UNIX epoch */
+ r = (t.Year - 1970) * 365;
+ for (y = 1970; y < t.Year; y++) {
+ if (isleap(y))
+ r++;
+ }
+ r += daytab[isleap(t.Year)? 1 : 0][t.Month] + t.Day;
+
+ /* Calc secs */
+ r *= 60 * 60 * 24;
+ r += ((t.Hour * 60) + t.Minute) * 60 + t.Second;
+ if (-24 * 60 < t.TimeZone && t.TimeZone < 24 * 60)
+ r += t.TimeZone * 60;
+
+ return (r);
+}
+
+u_int
+sleep(u_int i)
+{
+ time_t t;
+
+ /*
+ * Loop for the requested number of seconds, polling,
+ * so that it may handle interrupts.
+ */
+ for (t = getsecs() + i; getsecs() < t; cnischar())
+ ;
+
+ return 0;
+}
+
+/***********************************************************************
+ * Commands
+ ***********************************************************************/
+int
+Xexit_efi(void)
+{
+ EFI_CALL(BS->Exit, IH, 0, 0, NULL);
+ for (;;)
+ continue;
+ return (0);
+}
+
+int
+Xvideo_efi(void)
+{
+ int i, mode = -1;
+
+ if (cmd.argc >= 2) {
+ mode = strtol(cmd.argv[1], NULL, 10);
+ if (0 <= mode && mode < nitems(efi_video) &&
+ efi_video[mode].cols > 0) {
+ EFI_CALL(conout->SetMode, conout, mode);
+ efi_video_reset();
+ }
+ } else {
+ for (i = 0; i < nitems(efi_video) &&
+ i < conout->Mode->MaxMode; i++) {
+ if (efi_video[i].cols > 0)
+ printf("Mode %d: %d x %d\n", i,
+ efi_video[i].cols,
+ efi_video[i].rows);
+ }
+ printf("\n");
+ }
+ printf("Current Mode = %d\n", conout->Mode->Mode);
+
+ return (0);
+}
+
+int
+Xpoweroff_efi(void)
+{
+ EFI_CALL(RS->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ return (0);
+}
+
+int
+Xgop_efi(void)
+{
+ EFI_STATUS status;
+ int i, mode = -1;
+ UINTN sz;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
+ *gopi;
+
+ status = EFI_CALL(BS->LocateProtocol, &gop_guid, NULL,
+ (void **)&gop);
+ if (EFI_ERROR(status))
+ return (0);
+
+ if (cmd.argc >= 2) {
+ mode = strtol(cmd.argv[1], NULL, 10);
+ if (0 <= mode && mode < gop->Mode->MaxMode) {
+ status = EFI_CALL(gop->QueryMode, gop, mode,
+ &sz, &gopi);
+ if (!EFI_ERROR(status)) {
+ if (efi_gop_setmode(mode) == EFI_SUCCESS)
+ gopmode = mode;
+ }
+ }
+ } else {
+ for (i = 0; i < gop->Mode->MaxMode; i++) {
+ status = EFI_CALL(gop->QueryMode, gop, i, &sz, &gopi);
+ if (EFI_ERROR(status))
+ continue;
+ printf("Mode %d: %d x %d (stride = %d)\n", i,
+ gopi->HorizontalResolution,
+ gopi->VerticalResolution,
+ gopi->PixelsPerScanLine);
+ }
+ printf("\n");
+ }
+ printf("Current Mode = %d\n", gop->Mode->Mode);
+
+ return (0);
+}
diff --git a/sys/arch/amd64/stand/efi32/efiboot.h b/sys/arch/amd64/stand/efi32/efiboot.h
new file mode 100644
index 00000000000..beb3be554de
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efiboot.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: efiboot.h,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void efi_cleanup(void);
+void efi_cons_probe(struct consdev *);
+void efi_memprobe(void);
+void efi_hardprobe(void);
+void efi_diskprobe(void);
+void efi_pxeprobe(void);
+void efi_cons_init(struct consdev *);
+int efi_cons_getc(dev_t);
+void efi_cons_putc(dev_t, int);
+int efi_cons_getshifts(dev_t dev);
+void efi_com_probe(struct consdev *);
+void efi_com_init(struct consdev *);
+int efi_com_getc(dev_t);
+void efi_com_putc(dev_t, int);
+int Xvideo_efi(void);
+int Xgop_efi(void);
+int Xexit_efi(void);
+void efi_makebootargs(void);
+
+int Xpoweroff_efi(void);
+
+extern void (*run_i386)(u_long, u_long, int, int, int, int, int, int, int, int)
+ __attribute__ ((noreturn));
diff --git a/sys/arch/amd64/stand/efi32/eficall.S b/sys/arch/amd64/stand/efi32/eficall.S
new file mode 100644
index 00000000000..fd73a2c6fdd
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/eficall.S
@@ -0,0 +1,64 @@
+/* $OpenBSD: eficall.S,v 1.1 2019/05/11 02:33:34 mlarkin 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 <machine/asm.h>
+
+/*
+ * Rearrange the arguments to call the given function by EFI ABI.
+ *
+ * efi_call(nargs, func, arg[0], arg[1], arg[2], arg[3], arg[4], ...)
+ * ----------------------------------------------------------------------
+ * BSD: RDI RSI RDX RCX R8 R9 stack
+ * EFI: - - RCX RDX R8 R9 stack (w/shadow)
+ */
+ENTRY(efi_call)
+ push %rbp
+ mov %rsp, %rbp
+
+ xchg %rcx, %rdx
+ mov %rcx, %rax
+ mov %rdi, %rcx
+
+ /*
+ * set "nargs - 2 + 4 + 1" (= %rdi + 3) for next call stack size.
+ * (nargs - 2) is for arguments in stack, +4 for shadow registers
+ * and +1 for alignment
+ */
+ add $3, %rdi
+
+ shl $3, %rdi /* 64-bit word */
+ sub %rdi, %rsp /* get the stack */
+ and $(-0x10), %rsp /* align 16 bytes */
+
+ /* copy args */
+ sub $3, %rcx
+ cmp $1, %rcx
+ jle 2f
+
+1: /* loop arg[n-1] .. arg[4] */
+ mov 0x8(%rbp, %rcx, 8), %rdi
+ mov %rdi, 0x18(%rsp, %rcx, 8)
+ loopnz 1b
+2:
+ mov %rax, %rcx
+
+ call *%rsi
+
+ mov %rbp, %rsp
+ pop %rbp
+ retq
diff --git a/sys/arch/amd64/stand/efi32/eficall.h b/sys/arch/amd64/stand/efi32/eficall.h
new file mode 100644
index 00000000000..2d8cf2923d2
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/eficall.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: eficall.h,v 1.1 2019/05/11 02:33:34 mlarkin 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
diff --git a/sys/arch/amd64/stand/efi32/efidev.c b/sys/arch/amd64/stand/efi32/efidev.c
new file mode 100644
index 00000000000..19915a8993f
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efidev.c
@@ -0,0 +1,794 @@
+/* $OpenBSD: efidev.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * Copyright (c) 2003 Tobias Weingartner
+ * 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.
+ *
+ */
+#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 "disk.h"
+
+#ifdef SOFTRAID
+#include <dev/softraidvar.h>
+#include <lib/libsa/softraid.h>
+#include "softraid_amd64.h"
+#endif
+
+#include <efi.h>
+#include "eficall.h"
+
+extern int debug;
+
+#include "efidev.h"
+#include "biosdev.h" /* for dklookup() */
+
+#define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
+#define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed))
+
+struct efi_diskinfo {
+ EFI_BLOCK_IO *blkio;
+ UINT32 mediaid;
+};
+
+int bios_bootdev;
+static EFI_STATUS
+ efid_io(int, efi_diskinfo_t, u_int, int, void *);
+static int efid_diskio(int, struct diskinfo *, u_int, int, void *);
+static 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->efi_info = alloc(sizeof(struct efi_diskinfo));
+ dip->efi_info->blkio = blkio;
+ dip->efi_info->mediaid = blkio->Media->MediaId;
+ dip->diskio = efid_diskio;
+ dip->strategy = efistrategy;
+}
+
+static EFI_STATUS
+efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
+{
+ u_int blks, lba, i_lblks, i_tblks, i_nblks;
+ EFI_STATUS status = EFI_SUCCESS;
+ static u_char *iblk = NULL;
+ static u_int iblksz = 0;
+
+ /* block count of the intrisic block size in DEV_BSIZE */
+ blks = EFI_BLKSPERSEC(ed);
+ if (blks == 0)
+ /* block size < 512. HP Stream 13 actually has such a disk. */
+ return (EFI_UNSUPPORTED);
+
+ /* leading and trailing unaligned blocks in intrisic block */
+ i_lblks = ((off % blks) == 0)? 0 : blks - (off % blks);
+ i_tblks = (nsect > i_lblks)? (off + nsect) % blks : 0;
+
+ /* aligned blocks in intrisic block */
+ i_nblks = (nsect > i_lblks + i_tblks)? nsect - (i_lblks + i_tblks) : 0;
+
+ lba = (off + i_lblks) / blks;
+
+ switch (rw) {
+ case F_READ:
+ /* allocate the space for reading unaligned blocks */
+ if (ed->blkio->Media->BlockSize != DEV_BSIZE) {
+ if (iblk && iblksz < ed->blkio->Media->BlockSize) {
+ free(iblk, iblksz);
+ iblk = NULL;
+ }
+ if (iblk == NULL) {
+ iblk = alloc(ed->blkio->Media->BlockSize);
+ iblksz = ed->blkio->Media->BlockSize;
+ }
+ }
+ if (i_lblks > 0) {
+ status = EFI_CALL(ed->blkio->ReadBlocks,
+ ed->blkio, ed->mediaid, lba - 1,
+ ed->blkio->Media->BlockSize, iblk);
+ if (EFI_ERROR(status))
+ goto on_eio;
+ memcpy(buf, iblk + (blks - i_lblks) * DEV_BSIZE,
+ min(nsect, i_lblks) * DEV_BSIZE);
+ }
+ if (i_nblks > 0) {
+ status = EFI_CALL(ed->blkio->ReadBlocks,
+ ed->blkio, ed->mediaid, lba,
+ ed->blkio->Media->BlockSize * (i_nblks / blks),
+ buf + (i_lblks * DEV_BSIZE));
+ if (EFI_ERROR(status))
+ goto on_eio;
+ }
+ if (i_tblks > 0) {
+ status = EFI_CALL(ed->blkio->ReadBlocks,
+ ed->blkio, ed->mediaid, lba + (i_nblks / blks),
+ ed->blkio->Media->BlockSize, iblk);
+ if (EFI_ERROR(status))
+ goto on_eio;
+ memcpy(buf + (i_lblks + i_nblks) * DEV_BSIZE, iblk,
+ i_tblks * DEV_BSIZE);
+ }
+ break;
+ case F_WRITE:
+ if (ed->blkio->Media->ReadOnly)
+ goto on_eio;
+ /* XXX not yet */
+ goto on_eio;
+ break;
+ }
+ return (EFI_SUCCESS);
+
+on_eio:
+ 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->efi_info, 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, ...)
+{
+#ifdef SOFTRAID
+ struct sr_boot_volume *bv;
+#endif
+ register char *cp, **file;
+ dev_t maj, unit, part;
+ struct diskinfo *dip;
+ int biosdev, devlen;
+#if 0
+ const char *st;
+#endif
+ va_list ap;
+ char *dev;
+
+ va_start(ap, f);
+ cp = *(file = va_arg(ap, char **));
+ va_end(ap);
+
+#ifdef EFI_DEBUG
+ if (debug)
+ printf("%s\n", cp);
+#endif
+
+ f->f_devdata = NULL;
+
+ /* Search for device specification. */
+ dev = cp;
+ if (cp[4] == ':')
+ devlen = 2;
+ else if (cp[5] == ':')
+ devlen = 3;
+ else
+ return ENOENT;
+ cp += devlen;
+
+ /* Get unit. */
+ if ('0' <= *cp && *cp <= '9')
+ unit = *cp++ - '0';
+ else {
+ printf("Bad unit number\n");
+ return EUNIT;
+ }
+
+ /* Get partition. */
+ if ('a' <= *cp && *cp <= 'p')
+ part = *cp++ - 'a';
+ else {
+ printf("Bad partition\n");
+ return EPART;
+ }
+
+ /* Get filename. */
+ cp++; /* skip ':' */
+ if (*cp != 0)
+ *file = cp;
+ else
+ f->f_flags |= F_RAW;
+
+#ifdef SOFTRAID
+ /* Intercept softraid disks. */
+ if (strncmp("sr", dev, 2) == 0) {
+
+ /* 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 = efid_diskio;
+ dip->strategy = efistrategy;
+ bv->sbv_diskinfo = dip;
+ dip->sr_vol = bv;
+ dip->bios_info.flags |= BDI_BADLABEL;
+ }
+
+ dip = bv->sbv_diskinfo;
+
+ if (dip->bios_info.flags & BDI_BADLABEL) {
+ /* Attempt to read disklabel. */
+ bv->sbv_part = 'c';
+ if (sr_getdisklabel(bv, &dip->disklabel))
+ return ERDLAB;
+ dip->bios_info.flags &= ~BDI_BADLABEL;
+ check_hibernate(dip);
+ }
+
+ bv->sbv_part = part + 'a';
+
+ bootdev_dip = dip;
+ f->f_devdata = dip;
+
+ return 0;
+ }
+#endif
+ for (maj = 0; maj < nbdevs &&
+ strncmp(dev, bdevs[maj], devlen); maj++);
+ if (maj >= nbdevs) {
+ printf("Unknown device: ");
+ for (cp = *file; *cp != ':'; cp++)
+ putchar(*cp);
+ putchar('\n');
+ return EADAPT;
+ }
+
+ biosdev = unit;
+ switch (maj) {
+ case 0: /* wd */
+ case 4: /* sd */
+ case 17: /* hd */
+ biosdev |= 0x80;
+ break;
+ case 2: /* fd */
+ break;
+ case 6: /* cd */
+ biosdev |= 0xe0;
+ break;
+ default:
+ return ENXIO;
+ }
+
+ /* Find device */
+ dip = dklookup(biosdev);
+ if (dip == NULL)
+ return ENXIO;
+ bootdev_dip = dip;
+
+ /* Fix up bootdev */
+ { dev_t bsd_dev;
+ bsd_dev = dip->bios_info.bsd_dev;
+ dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
+ B_CONTROLLER(bsd_dev), unit, part);
+ dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
+ B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
+ }
+
+#if 0
+ dip->bios_info.bsd_dev = dip->bootdev;
+ bootdev = dip->bootdev;
+#endif
+
+#ifdef EFI_DEBUG
+ if (debug) {
+ printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
+ dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
+ dip->bios_info.bios_edd);
+ }
+#endif
+
+#if 0
+/*
+ * XXX In UEFI, media change can be detected by MediaID
+ */
+ /* Try for disklabel again (might be removable media) */
+ if (dip->bios_info.flags & BDI_BADLABEL) {
+ st = efi_getdisklabel(dip->efi_info, &dip->disklabel);
+#ifdef EFI_DEBUG
+ if (debug && st)
+ printf("%s\n", st);
+#endif
+ if (!st) {
+ dip->bios_info.flags &= ~BDI_BADLABEL;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ } else
+ return ERDLAB;
+ }
+#endif
+ f->f_devdata = dip;
+
+ return 0;
+}
+
+int
+efistrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ struct diskinfo *dip = (struct diskinfo *)devdata;
+ u_int8_t error = 0;
+ size_t nsect;
+
+#ifdef SOFTRAID
+ /* Intercept strategy for softraid volumes. */
+ if (dip->sr_vol)
+ return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
+#endif
+ nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
+ blk += DL_SECTOBLK(&dip->disklabel,
+ dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset);
+
+ if (blk < 0)
+ error = EINVAL;
+ else
+ error = dip->diskio(rw, dip, blk, nsect, buf);
+
+#ifdef EFI_DEBUG
+ if (debug) {
+ if (error != 0)
+ printf("=0x%x(%s)", error, error);
+ putchar('\n');
+ }
+#endif
+ 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;
+}
+
+void
+efi_dump_diskinfo(void)
+{
+ efi_diskinfo_t ed;
+ struct diskinfo *dip;
+ bios_diskinfo_t *bdi;
+ uint64_t siz;
+ const char *sizu;
+
+ printf("Disk\tBlkSiz\tIoAlign\tSize\tFlags\tChecksum\n");
+ TAILQ_FOREACH(dip, &disklist, list) {
+ bdi = &dip->bios_info;
+ ed = dip->efi_info;
+
+ siz = (ed->blkio->Media->LastBlock + 1) *
+ ed->blkio->Media->BlockSize;
+ siz /= 1024 * 1024;
+ if (siz < 10000)
+ sizu = "MB";
+ else {
+ siz /= 1024;
+ sizu = "GB";
+ }
+
+ printf("%cd%d\t%u\t%u\t%u%s\t0x%x\t0x%x\t%s\n",
+ (B_TYPE(bdi->bsd_dev) == 6)? 'c' : 'h',
+ (bdi->bios_number & 0x1f),
+ ed->blkio->Media->BlockSize,
+ ed->blkio->Media->IoAlign, (unsigned)siz, sizu,
+ bdi->flags, bdi->checksum,
+ (ed->blkio->Media->RemovableMedia)? "Removable" : "");
+ }
+}
diff --git a/sys/arch/amd64/stand/efi32/efidev.h b/sys/arch/amd64/stand/efi32/efidev.h
new file mode 100644
index 00000000000..1c4fe65fb85
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efidev.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: efidev.h,v 1.1 2019/05/11 02:33:34 mlarkin 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);
+const char *efi_getdisklabel(efi_diskinfo_t, struct disklabel *);
+int efiopen(struct open_file *, ...);
+int efistrategy(void *, int, daddr32_t, size_t, void *, size_t *);
+int eficlose(struct open_file *);
+int efiioctl(struct open_file *, u_long, void *);
+void efi_dump_diskinfo(void);
diff --git a/sys/arch/amd64/stand/efi32/efipxe.c b/sys/arch/amd64/stand/efi32/efipxe.c
new file mode 100644
index 00000000000..382a05382a1
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efipxe.c
@@ -0,0 +1,306 @@
+/* $OpenBSD: efipxe.c,v 1.1 2019/05/11 02:33:34 mlarkin 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 <machine/biosvar.h>
+
+#include <libsa.h>
+#include <lib/libsa/tftp.h>
+
+#include "disk.h"
+
+#include <efi.h>
+#include <efiapi.h>
+#include "eficall.h"
+#include "efiboot.h"
+
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_DEVICE_PATH *efi_bootdp;
+
+extern char *bootmac;
+static UINT8 boothw[16];
+static EFI_IP_ADDRESS bootip, servip;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+static EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL;
+static EFI_PXE_BASE_CODE *PXE = NULL;
+
+extern int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+extern int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+
+/*
+ * TFTP initial probe. This function discovers PXE handles and tries
+ * to figure out if there has already been a successfull PXE handshake.
+ * If so, set the PXE variable.
+ */
+void
+efi_pxeprobe(void)
+{
+ 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 = NULL;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i],
+ &devp_guid, (void **)&dp0);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+ if (efi_device_path_ncmp(efi_bootdp, dp0, depth))
+ continue;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &pxe_guid,
+ (void **)&pxe);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ if (pxe->Mode == NULL)
+ continue;
+
+ if (pxe->Mode->DhcpAckReceived) {
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)
+ &pxe->Mode->DhcpAck;
+ }
+ if (pxe->Mode->PxeReplyReceived) {
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)
+ &pxe->Mode->PxeReply;
+ }
+
+ if (dhcp) {
+ memcpy(&bootip, dhcp->BootpYiAddr, sizeof(bootip));
+ memcpy(&servip, dhcp->BootpSiAddr, sizeof(servip));
+ memcpy(boothw, dhcp->BootpHwAddr, sizeof(boothw));
+ bootmac = boothw;
+ PXE = pxe;
+ break;
+ }
+ }
+}
+
+/*
+ * TFTP filesystem layer implementation.
+ */
+struct tftp_handle {
+ unsigned char *inbuf; /* input buffer */
+ size_t inbufsize;
+ off_t inbufoff;
+};
+
+struct fs_ops tftp_fs = {
+ tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek,
+ tftp_stat, tftp_readdir
+};
+
+int
+tftp_open(char *path, struct open_file *f)
+{
+ struct tftp_handle *tftpfile;
+ EFI_PHYSICAL_ADDRESS addr;
+ EFI_STATUS status;
+ UINT64 size;
+
+ if (strcmp("TFTP", f->f_dev->dv_name) != 0)
+ return ENXIO;
+
+ if (PXE == NULL)
+ return ENXIO;
+
+ tftpfile = alloc(sizeof(*tftpfile));
+ if (tftpfile == NULL)
+ return ENOMEM;
+ memset(tftpfile, 0, sizeof(*tftpfile));
+
+ status = EFI_CALL(PXE->Mtftp, PXE, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ NULL, FALSE, &size, NULL, &servip, 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, &servip, path, NULL, FALSE);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENXIO;
+ }
+out:
+ f->f_fsdata = tftpfile;
+ return 0;
+}
+
+int
+tftp_close(struct open_file *f)
+{
+ struct tftp_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
+tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid)
+{
+ struct tftp_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
+tftp_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+ return EROFS;
+}
+
+off_t
+tftp_seek(struct open_file *f, off_t offset, int where)
+{
+ struct tftp_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
+tftp_stat(struct open_file *f, struct stat *sb)
+{
+ struct tftp_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
+tftp_readdir(struct open_file *f, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * Dummy TFTP network device.
+ */
+int
+tftpopen(struct open_file *f, ...)
+{
+ char **fname, *p;
+ va_list ap;
+
+ va_start(ap, f);
+ fname = va_arg(ap, char **);
+ va_end(ap);
+
+ /* No PXE set -> no PXE available */
+ if (PXE == NULL)
+ return 1;
+
+ /* Parse tftp:bsd into "tftp" and "bsd" */
+ for (p = *fname; *p != ':' && *p != '\0'; p++)
+ ;
+ if (*p != ':')
+ return 1;
+ if (strncmp(*fname, "tftp", p - *fname) != 0)
+ return 1;
+
+ *fname = p + 1;
+ return 0;
+}
+
+int
+tftpclose(struct open_file *f)
+{
+ return 0;
+}
+
+int
+tftpioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return EOPNOTSUPP;
+}
+
+int
+tftpstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ return EOPNOTSUPP;
+}
diff --git a/sys/arch/amd64/stand/efi32/efipxe.h b/sys/arch/amd64/stand/efi32/efipxe.h
new file mode 100644
index 00000000000..b448db8b6f7
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efipxe.h
@@ -0,0 +1,21 @@
+/* $OpenBSD: efipxe.h,v 1.1 2019/05/11 02:33:34 mlarkin 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.
+ */
+
+int tftpopen(struct open_file *, ...);
+int tftpclose(struct open_file *);
+int tftpioctl(struct open_file *, u_long, void *);
+int tftpstrategy(void *, int, daddr32_t, size_t, void *, size_t *);
diff --git a/sys/arch/amd64/stand/efi32/efirng.c b/sys/arch/amd64/stand/efi32/efirng.c
new file mode 100644
index 00000000000..0178c14551a
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/efirng.c
@@ -0,0 +1,87 @@
+/* $OpenBSD: efirng.c,v 1.1 2019/05/11 02:33:34 mlarkin 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;
+
+void
+fwrandom(char *buf, size_t buflen)
+{
+ EFI_STATUS status;
+ EFI_RNG_PROTOCOL *rng = NULL;
+ UINT8 *random;
+ size_t i;
+
+ status = EFI_CALL(BS->LocateProtocol, &rng_guid, NULL, (void **)&rng);
+ if (rng == NULL || EFI_ERROR(status))
+ return;
+
+ random = alloc(buflen);
+
+ status = EFI_CALL(rng->GetRNG, rng, NULL, buflen, random);
+ if (EFI_ERROR(status)) {
+ printf("RNG GetRNG() failed (%d)\n", status);
+ goto out;
+ }
+
+ for (i = 0; i < buflen; i++)
+ buf[i] ^= random[i];
+
+out:
+ free(random, buflen);
+}
diff --git a/sys/arch/amd64/stand/efi32/exec_i386.c b/sys/arch/amd64/stand/efi32/exec_i386.c
new file mode 100644
index 00000000000..87c5c98b5e9
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/exec_i386.c
@@ -0,0 +1,220 @@
+/* $OpenBSD: exec_i386.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1997-1998 Michael Shalayeff
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 AUTHORS ``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/disklabel.h>
+#include <dev/cons.h>
+#include <lib/libsa/loadfile.h>
+#include <machine/biosvar.h>
+#include <machine/specialreg.h>
+#include <stand/boot/bootarg.h>
+
+#include "cmd.h"
+#include "disk.h"
+#include "libsa.h"
+
+#ifdef SOFTRAID
+#include <dev/softraidvar.h>
+#include <lib/libsa/softraid.h>
+#include "softraid_amd64.h"
+#endif
+
+#include "efiboot.h"
+
+typedef void (*startfuncp)(int, int, int, int, int, int, int, int)
+ __attribute__ ((noreturn));
+
+void ucode_load(void);
+extern struct cmd_state cmd;
+
+char *bootmac = NULL;
+
+void
+run_loadfile(uint64_t *marks, int howto)
+{
+ u_long entry;
+#ifdef EXEC_DEBUG
+ extern int debug;
+#endif
+ dev_t bootdev = bootdev_dip->bootdev;
+ size_t ac = BOOTARG_LEN;
+ caddr_t av = (caddr_t)BOOTARG_OFF;
+ bios_consdev_t cd;
+ extern int com_speed; /* from bioscons.c */
+ extern int com_addr;
+ bios_ddb_t ddb;
+ extern int db_console;
+ bios_bootduid_t bootduid;
+#ifdef SOFTRAID
+ bios_bootsr_t bootsr;
+ struct sr_boot_volume *bv;
+#endif
+ int i;
+ u_long delta;
+ extern u_long efi_loadaddr;
+
+ if ((av = alloc(ac)) == NULL)
+ panic("alloc for bootarg");
+ efi_makebootargs();
+ delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr;
+ if (sa_cleanup != NULL)
+ (*sa_cleanup)();
+
+ cd.consdev = cn_tab->cn_dev;
+ cd.conspeed = com_speed;
+ cd.consaddr = com_addr;
+ cd.consfreq = 0;
+ addbootarg(BOOTARG_CONSDEV, sizeof(cd), &cd);
+
+ if (bootmac != NULL)
+ addbootarg(BOOTARG_BOOTMAC, sizeof(bios_bootmac_t), bootmac);
+
+ if (db_console != -1) {
+ ddb.db_console = db_console;
+ addbootarg(BOOTARG_DDB, sizeof(ddb), &ddb);
+ }
+
+ bcopy(bootdev_dip->disklabel.d_uid, &bootduid.duid, sizeof(bootduid));
+ addbootarg(BOOTARG_BOOTDUID, sizeof(bootduid), &bootduid);
+
+ ucode_load();
+
+#ifdef SOFTRAID
+ if (bootdev_dip->sr_vol != NULL) {
+ bv = bootdev_dip->sr_vol;
+ bzero(&bootsr, sizeof(bootsr));
+ bcopy(&bv->sbv_uuid, &bootsr.uuid, sizeof(bootsr.uuid));
+ if (bv->sbv_maskkey != NULL)
+ bcopy(bv->sbv_maskkey, &bootsr.maskkey,
+ sizeof(bootsr.maskkey));
+ addbootarg(BOOTARG_BOOTSR, sizeof(bios_bootsr_t), &bootsr);
+ explicit_bzero(&bootsr, sizeof(bootsr));
+ }
+
+ sr_clear_keys();
+#endif
+
+ entry = marks[MARK_ENTRY] & 0x0fffffff;
+ entry += delta;
+
+ printf("entry point at 0x%lx\n", entry);
+
+ /* Sync the memory map and call ExitBootServices() */
+ efi_cleanup();
+
+ /* Pass memory map to the kernel */
+ mem_pass();
+
+ /*
+ * This code may be used both for 64bit and 32bit. Make sure the
+ * bootarg is always 32bit, even on amd64.
+ */
+#ifdef __amd64__
+ makebootargs32(av, &ac);
+#else
+ makebootargs(av, &ac);
+#endif
+
+ /*
+ * Move the loaded kernel image to the usual place after calling
+ * ExitBootServices().
+ */
+ memmove((void *)marks[MARK_START] + delta, (void *)marks[MARK_START],
+ marks[MARK_END] - marks[MARK_START]);
+ for (i = 0; i < MARK_MAX; i++)
+ marks[i] += delta;
+
+#ifdef __amd64__
+ (*run_i386)((u_long)run_i386, entry, howto, bootdev, BOOTARG_APIVER,
+ marks[MARK_END], extmem, cnvmem, ac, (intptr_t)av);
+#else
+ /* stack and the gung is ok at this point, so, no need for asm setup */
+ (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER, marks[MARK_END],
+ extmem, cnvmem, ac, (int)av);
+#endif
+ /* not reached */
+}
+
+void
+ucode_load(void)
+{
+ uint32_t model, family, stepping;
+ uint32_t dummy, signature;
+ uint32_t vendor[4];
+ bios_ucode_t uc;
+ struct stat sb;
+ char path[128];
+ size_t buflen;
+ char *buf;
+ int fd;
+
+ CPUID(0, dummy, vendor[0], vendor[2], vendor[1]);
+ vendor[3] = 0; /* NULL-terminate */
+ if (strcmp((char *)vendor, "GenuineIntel") != 0)
+ return;
+
+ CPUID(1, signature, dummy, dummy, dummy);
+ family = (signature >> 8) & 0x0f;
+ model = (signature >> 4) & 0x0f;
+ if (family == 0x6 || family == 0xf) {
+ family += (signature >> 20) & 0xff;
+ model += ((signature >> 16) & 0x0f) << 4;
+ }
+ stepping = (signature >> 0) & 0x0f;
+
+ snprintf(path, sizeof(path), "%s:/etc/firmware/intel/%02x-%02x-%02x",
+ cmd.bootdev, family, model, stepping);
+
+ fd = open(path, 0);
+ if (fd == -1)
+ return;
+
+ if (fstat(fd, &sb) == -1)
+ return;
+
+ buflen = sb.st_size;
+ if (buflen > 128*1024) {
+ printf("ucode too large\n");
+ return;
+ }
+
+ buf = (char *)(1*1024*1024);
+
+ if (read(fd, buf, buflen) != buflen) {
+ close(fd);
+ return;
+ }
+
+ uc.uc_addr = (uint64_t)buf;
+ uc.uc_size = (uint64_t)buflen;
+ addbootarg(BOOTARG_UCODE, sizeof(uc), &uc);
+
+ close(fd);
+}
diff --git a/sys/arch/amd64/stand/efi32/heap.h b/sys/arch/amd64/stand/efi32/heap.h
new file mode 100644
index 00000000000..618db452cf8
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/heap.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: heap.h,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <efi.h>
+
+static char *top = NULL;
+#define NEEDS_HEAP_INIT 1
+
+static void
+heap_init(void)
+{
+ extern EFI_PHYSICAL_ADDRESS heap;
+ if (top == NULL)
+ top = (char *)(uintptr_t)heap;
+}
diff --git a/sys/arch/amd64/stand/efi32/ldscript.amd64 b/sys/arch/amd64/stand/efi32/ldscript.amd64
new file mode 100644
index 00000000000..ab3ab48c3a9
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/ldscript.amd64
@@ -0,0 +1,65 @@
+/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0;
+ ImageBase = .;
+ .hash : { *(.hash) } /* this MUST come first! */
+ . = ALIGN(4096);
+ .eh_frame :
+ {
+ *(.eh_frame)
+ }
+ . = ALIGN(4096);
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ }
+ . = ALIGN(4096);
+ .reloc :
+ {
+ *(.reloc)
+ }
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.got.plt)
+ *(.got)
+ *(.data*)
+ *(.sdata)
+ /* the EFI loader doesn't seem to like a .bss section, so we stick
+ it all into .data: */
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ *(.rel.local)
+ }
+ . = ALIGN(4096);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .rela :
+ {
+ *(.rela.data*)
+ *(.rela.got)
+ *(.rela.stab)
+ }
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ .ignored.reloc :
+ {
+ *(.rela.reloc)
+ *(.eh_frame)
+ *(.note.GNU-stack)
+ }
+ .comment 0 : { *(.comment) }
+}
diff --git a/sys/arch/amd64/stand/efi32/ldscript.i386 b/sys/arch/amd64/stand/efi32/ldscript.i386
new file mode 100644
index 00000000000..975e36c14f5
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/ldscript.i386
@@ -0,0 +1,75 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0;
+ ImageBase = .;
+ .hash : { *(.hash) } /* this MUST come first! */
+ . = ALIGN(4096);
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ }
+ . = ALIGN(4096);
+ .sdata :
+ {
+ *(.got.plt)
+ *(.got)
+ *(.srodata)
+ *(.sdata)
+ *(.sbss)
+ *(.scommon)
+ }
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data)
+ *(.data1)
+ *(.data.*)
+ *(.sdata)
+ *(.got.plt)
+ *(.got)
+ /* the EFI loader doesn't seem to like a .bss section, so we stick
+ it all into .data: */
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ . = ALIGN(4096);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .rel :
+ {
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.got)
+ *(.rel.stab)
+ *(.data.rel.ro.local)
+ *(.data.rel.local)
+ *(.data.rel.ro)
+ *(.data.rel*)
+ }
+ . = ALIGN(4096);
+ .reloc : /* This is the PECOFF .reloc section! */
+ {
+ *(.reloc)
+ }
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ /DISCARD/ :
+ {
+ *(.rel.reloc)
+ *(.eh_frame)
+ *(.note.GNU-stack)
+ }
+ .comment 0 : { *(.comment) }
+}
diff --git a/sys/arch/amd64/stand/efi32/machdep.c b/sys/arch/amd64/stand/efi32/machdep.c
new file mode 100644
index 00000000000..5e50922f3c8
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/machdep.c
@@ -0,0 +1,95 @@
+/* $OpenBSD: machdep.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 2004 Tom Cosgrove
+ * Copyright (c) 1997-1999 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 AUTHOR OR HIS RELATIVES 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 MIND, 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 "libsa.h"
+#include "biosdev.h"
+#include <machine/apmvar.h>
+#include <machine/biosvar.h>
+#include <machine/specialreg.h>
+#include <machine/vmmvar.h>
+
+#include "efiboot.h"
+
+volatile struct BIOS_regs BIOS_regs;
+
+#if defined(DEBUG)
+#define CKPT(c) (*(u_int16_t*)0xb8148 = 0x4700 + (c))
+#else
+#define CKPT(c) /* c */
+#endif
+
+const char *vmm_hv_signature = VMM_HV_SIGNATURE;
+
+void
+machdep(void)
+{
+ int i, j, vmm = 0;
+ struct i386_boot_probes *pr;
+ uint32_t dummy, ebx, ecx, edx;
+ dev_t dev;
+
+ /*
+ * The list of probe routines is now in conf.c.
+ */
+ for (i = 0; i < nibprobes; i++) {
+ pr = &probe_list[i];
+ if (pr != NULL) {
+ printf("%s:", pr->name);
+
+ for (j = 0; j < pr->count; j++) {
+ (*(pr->probes)[j])();
+ }
+
+ printf("\n");
+ }
+ }
+
+ CPUID(0x1, dummy, dummy, ecx, dummy);
+ if (ecx & CPUIDECX_HV) {
+ CPUID(0x40000000, dummy, ebx, ecx, edx);
+ if (memcmp(&ebx, &vmm_hv_signature[0], sizeof(uint32_t)) == 0 &&
+ memcmp(&ecx, &vmm_hv_signature[4], sizeof(uint32_t)) == 0 &&
+ memcmp(&edx, &vmm_hv_signature[8], sizeof(uint32_t)) == 0)
+ vmm = 1;
+ }
+
+ /* Set console to com0/115200 by default in vmm */
+ if (vmm) {
+ dev = ttydev("com0");
+ cnspeed(dev, 115200);
+ cnset(dev);
+ }
+}
+
+int
+check_skip_conf(void)
+{
+ /* Return non-zero (skip boot.conf) if Control "shift" key down */
+ return (efi_cons_getshifts(0) & 0x04);
+}
diff --git a/sys/arch/amd64/stand/efi32/memprobe.c b/sys/arch/amd64/stand/efi32/memprobe.c
new file mode 100644
index 00000000000..e119a990737
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/memprobe.c
@@ -0,0 +1,173 @@
+/* $OpenBSD: memprobe.c,v 1.1 2019/05/11 02:33:34 mlarkin Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * Copyright (c) 1997-1999 Tobias Weingartner
+ * 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 <machine/biosvar.h>
+#include <dev/isa/isareg.h>
+#include <stand/boot/bootarg.h>
+#include "libsa.h"
+
+u_int cnvmem, extmem; /* XXX - compatibility */
+
+bios_memmap_t bios_memmap[64]; /* This is easier */
+
+void
+dump_biosmem(bios_memmap_t *tm)
+{
+ register bios_memmap_t *p;
+ register u_int total = 0;
+
+ if (tm == NULL)
+ tm = bios_memmap;
+
+ for (p = tm; p->type != BIOS_MAP_END; p++) {
+ printf("Region %ld: type %u at 0x%llx for %uKB\n",
+ (long)(p - tm), p->type, p->addr,
+ (u_int)(p->size / 1024));
+
+ if (p->type == BIOS_MAP_FREE)
+ total += p->size / 1024;
+ }
+
+ printf("Low ram: %dKB High ram: %dKB\n", cnvmem, extmem);
+ printf("Total free memory: %uKB\n", total);
+}
+
+int
+mem_limit(long long ml)
+{
+ register bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
+ register int64_t sp = p->addr, ep = p->addr + p->size;
+
+ if (p->type != BIOS_MAP_FREE)
+ continue;
+
+ /* Wholly above limit, nuke it */
+ if ((sp >= ml) && (ep >= ml)) {
+ bcopy (p + 1, p, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)p);
+ } else if ((sp < ml) && (ep >= ml)) {
+ p->size -= (ep - ml);
+ }
+ }
+ return 0;
+}
+
+int
+mem_delete(long long sa, long long ea)
+{
+ register bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
+ if (p->type == BIOS_MAP_FREE) {
+ register int64_t sp = p->addr, ep = p->addr + p->size;
+
+ /* can we eat it as a whole? */
+ if ((sa - sp) <= PAGE_SIZE && (ep - ea) <= PAGE_SIZE) {
+ bcopy(p + 1, p, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)p);
+ break;
+ /* eat head or legs */
+ } else if (sa <= sp && sp < ea) {
+ p->addr = ea;
+ p->size = ep - ea;
+ break;
+ } else if (sa < ep && ep <= ea) {
+ p->size = sa - sp;
+ break;
+ } else if (sp < sa && ea < ep) {
+ /* bite in half */
+ bcopy(p, p + 1, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)p -
+ sizeof(bios_memmap[0]));
+ p[1].addr = ea;
+ p[1].size = ep - ea;
+ p->size = sa - sp;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int
+mem_add(long long sa, long long ea)
+{
+ register bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
+ if (p->type == BIOS_MAP_FREE) {
+ register int64_t sp = p->addr, ep = p->addr + p->size;
+
+ /* is it already there? */
+ if (sp <= sa && ea <= ep) {
+ break;
+ /* join head or legs */
+ } else if (sa < sp && sp <= ea) {
+ p->addr = sa;
+ p->size = ep - sa;
+ break;
+ } else if (sa <= ep && ep < ea) {
+ p->size = ea - sp;
+ break;
+ } else if (ea < sp) {
+ /* insert before */
+ bcopy(p, p + 1, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)(p - 1));
+ p->addr = sa;
+ p->size = ea - sa;
+ break;
+ }
+ }
+ }
+
+ /* meaning add new item at the end of the list */
+ if (p->type == BIOS_MAP_END) {
+ p[1] = p[0];
+ p->type = BIOS_MAP_FREE;
+ p->addr = sa;
+ p->size = ea - sa;
+ }
+
+ return 0;
+}
+
+void
+mem_pass(void)
+{
+ bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++)
+ ;
+ addbootarg(BOOTARG_MEMMAP, (p - bios_memmap + 1) * sizeof *bios_memmap,
+ bios_memmap);
+}
diff --git a/sys/arch/amd64/stand/efi32/run_i386.S b/sys/arch/amd64/stand/efi32/run_i386.S
new file mode 100644
index 00000000000..ccb423d0079
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/run_i386.S
@@ -0,0 +1,115 @@
+/* $OpenBSD: run_i386.S,v 1.1 2019/05/11 02:33:34 mlarkin 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 <machine/asm.h>
+#include <machine/specialreg.h>
+
+#define CODE_SEGMENT 0x10
+#define DATA_SEGMENT 0x18
+
+ .globl _C_LABEL(run_i386_size)
+_C_LABEL(run_i386_size):
+ .long run_i386_end - _C_LABEL(run_i386_start)
+
+ .align 4
+ .text
+ .globl _C_LABEL(run_i386_start)
+_C_LABEL(run_i386_start):
+start:
+ /*
+ * run_i386(_start) is to call the loaded kernel's start() with
+ * 32bit segment mode from x64 mode.
+ * %rdi == loaded start address, %rsi == kernel start address
+ */
+
+ /* re-arrange the parameters for the x86 calling convension */
+ mov %edx, (run_i386_end - start - 0x20)(%rdi)
+ mov %ecx, (run_i386_end - start - 0x1c)(%rdi)
+ mov %r8d, (run_i386_end - start - 0x18)(%rdi)
+ mov %r9d, (run_i386_end - start - 0x14)(%rdi)
+ mov 0x8(%rsp), %edx
+ mov %edx, (run_i386_end - start - 0x10)(%rdi)
+ mov 0x10(%rsp), %edx
+ mov %edx, (run_i386_end - start - 0xc)(%rdi)
+ mov 0x18(%rsp), %edx
+ mov %edx, (run_i386_end - start - 0x8)(%rdi)
+ mov 0x20(%rsp), %edx
+ mov %edx, (run_i386_end - start - 0x4)(%rdi)
+
+ /* Prepare jump address */
+ lea (start32a - start)(%rdi), %rax
+ movl %eax, (start32r - start)(%rdi)
+
+ cli
+
+ /* Setup GDT */
+ lea (gdt - start)(%rdi), %rax
+ mov %rax, (gdtrr - start)(%rdi)
+ lgdt (gdtr - start)(%rdi)
+
+ /* Jump to set %cs */
+ ljmp *(start32r - start)(%rdi)
+
+ .align 4
+start32a:
+ .code32
+ movl $DATA_SEGMENT, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ lea (run_i386_end - start - 0x20)(%edi), %eax
+ mov %eax, %esp
+
+ /* Disable Paging in CR0 */
+ movl %cr0, %eax
+ andl $(~CR0_PG), %eax
+ movl %eax, %cr0
+
+ /* Disable PAE in CR4 */
+ movl %cr4, %eax
+ andl $(~CR4_PAE), %eax
+ movl %eax, %cr4
+
+ jmp start32b
+start32b:
+ .code32
+
+ call *%esi
+
+ .align 4
+start32r:
+ .long 0
+ .long CODE_SEGMENT
+ .align 4
+gdt:
+ .long 0, 0
+ .long 0, 0
+ .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xcf, 0x00
+ .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00
+gdtr:
+ .word gdtr - gdt
+gdtrr:
+ .quad
+start32end:
+ /* Space for the stack */
+ .align 4
+ .space 8192
+run_i386_end:
diff --git a/sys/arch/amd64/stand/efi32/run_i386.h b/sys/arch/amd64/stand/efi32/run_i386.h
new file mode 100644
index 00000000000..f20d2d4f19a
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/run_i386.h
@@ -0,0 +1,21 @@
+/* $OpenBSD: run_i386.h,v 1.1 2019/05/11 02:33:34 mlarkin 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.
+ */
+
+extern void run_i386_start(u_long, u_long, int, int, int, int, int, int,
+ int, int) __attribute__ ((noreturn));
+extern u_int run_i386_size;
diff --git a/sys/arch/amd64/stand/efi32/self_reloc.c b/sys/arch/amd64/stand/efi32/self_reloc.c
new file mode 100644
index 00000000000..75ccf65bad6
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/self_reloc.c
@@ -0,0 +1,124 @@
+/* $OpenBSD: self_reloc.c,v 1.1 2019/05/11 02:33:34 mlarkin 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__)
+#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
+#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);
+ }
+}
diff --git a/sys/arch/amd64/stand/efi32/start_amd64.S b/sys/arch/amd64/stand/efi32/start_amd64.S
new file mode 100644
index 00000000000..171dbff3d0a
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/start_amd64.S
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * Copyright (C) 2005 Intel Co.
+ * Contributed by Fenghua Yu <fenghua.yu@intel.com>.
+ * 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.
+ * 3. Neither the name of Hewlett-Packard Co. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+/*
+ * crt0-efi-x86_64.S - x86_64 EFI startup code.
+ * $FreeBSD: head/sys/boot/efi/loader/arch/amd64/start.S 282727 2015-05-10 13:24:26Z ian $
+ */
+
+ .text
+ .align 4
+
+ .globl _start
+_start:
+ subq $8, %rsp
+ pushq %rcx
+ pushq %rdx
+
+0:
+ lea ImageBase(%rip), %rdi
+ lea _DYNAMIC(%rip), %rsi
+
+ popq %rcx
+ popq %rdx
+ pushq %rcx
+ pushq %rdx
+ call self_reloc
+
+ popq %rdi
+ popq %rsi
+
+ call efi_main
+ addq $8, %rsp
+
+.exit:
+ ret
+
+ /*
+ * hand-craft a dummy .reloc section so EFI knows it's a relocatable
+ * executable:
+ */
+
+ .data
+ .section .reloc, "a"
+ .long 0
+ .long 10
+ .word 0
diff --git a/sys/arch/amd64/stand/efi32/start_i386.S b/sys/arch/amd64/stand/efi32/start_i386.S
new file mode 100644
index 00000000000..016ab93d15a
--- /dev/null
+++ b/sys/arch/amd64/stand/efi32/start_i386.S
@@ -0,0 +1,68 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD: head/sys/boot/efi/loader/arch/i386/start.S 282728 2015-05-10 13:30:21Z ian $
+ */
+
+ .text
+
+#include <machine/asm.h>
+
+#define EFI_SUCCESS 0
+
+/*
+ * EFI entry point.
+ * _start(EFI_IMAGE image_handle, EFI_SYSTEM_TABLE *system_table);
+ *
+ * We calculate the base address along with _DYNAMIC, relocate us and finally
+ * pass control to efi_main.
+ */
+
+ENTRY(_start)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl 12(%ebp) /* image_handle */
+ pushl 8(%ebp) /* system_table */
+ call 0f
+0: popl %eax
+ movl %eax, %ebx
+ addl $ImageBase-0b, %eax
+ addl $_DYNAMIC-0b, %ebx
+ pushl %ebx /* dynamic */
+ pushl %eax /* ImageBase */
+ call self_reloc
+ popl %ebx /* remove ImageBase from the stack */
+ popl %ebx /* remove dynamic from the stack */
+ call efi_main
+1: leave
+ ret
+END(_start)
+
+ .data
+ .section .reloc, "a"
+ .long 0
+ .long 10
+ .word 0